Compare central directory size with number of entries.
Credit to OSS-Fuzz.
diff --git a/lib/zip_open.c b/lib/zip_open.c
index 8680700..dec6a98 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -721,16 +721,19 @@
eocd_disk = _zip_buffer_get_16(buffer);
eocd_offset = _zip_buffer_get_64(buffer);
- if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
+ /* valid seek value for start of EOCD */
+ if (eocd_offset > ZIP_INT64_MAX) {
zip_error_set(error, ZIP_ER_SEEK, EFBIG);
return NULL;
}
+ /* does EOCD fit before EOCD locator? */
if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
zip_error_set(error, ZIP_ER_INCONS, 0);
return NULL;
}
+ /* make sure current position of buffer is beginning of EOCD */
if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
_zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
free_buffer = false;
@@ -754,8 +757,10 @@
return NULL;
}
+ /* size of EOCD */
size = _zip_buffer_get_64(buffer);
+ /* is there a hole between EOCD and EOCD locator, or do they overlap? */
if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
zip_error_set(error, ZIP_ER_INCONS, 0);
if (free_buffer) {
@@ -807,6 +812,7 @@
size = _zip_buffer_get_64(buffer);
offset = _zip_buffer_get_64(buffer);
+ /* did we read past the end of the buffer? */
if (!_zip_buffer_ok(buffer)) {
zip_error_set(error, ZIP_ER_INTERNAL, 0);
if (free_buffer) {
@@ -833,6 +839,11 @@
return NULL;
}
+ if (nentry > size / CDENTRYSIZE) {
+ zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
if ((cd = _zip_cdir_new(nentry, error)) == NULL)
return NULL;
diff --git a/regress/open_file_count.test b/regress/open_file_count.test
index 56f0447..5078978 100644
--- a/regress/open_file_count.test
+++ b/regress/open_file_count.test
@@ -8,5 +8,5 @@
return 1
stdout opening 'incons-file-count-high.zzip' returned error 21
stdout opening 'incons-file-count-low.zzip' returned error 21
-stdout opening 'incons-file-count-overflow.zzip' returned error 14
+stdout opening 'incons-file-count-overflow.zzip' returned error 21
stderr 3 errors
diff --git a/regress/open_incons.test b/regress/open_incons.test
index 0843816..cda6afb 100644
--- a/regress/open_incons.test
+++ b/regress/open_incons.test
@@ -60,7 +60,7 @@
stdout opening 'incons-eocd-magic-bad.zzip' returned error 19
stdout opening 'incons-file-count-high.zzip' returned error 21
stdout opening 'incons-file-count-low.zzip' returned error 21
-stdout opening 'incons-file-count-overflow.zzip' returned error 14
+stdout opening 'incons-file-count-overflow.zzip' returned error 21
stdout opening 'incons-local-compression-method.zzip' returned error 21
stdout opening 'incons-local-compsize-larger.zzip' returned error 21
stdout opening 'incons-local-compsize-smaller.zzip' returned error 21