[git commit] unzip: fix for .zip archives with >4GB file

Denys Vlasenko vda.linux at googlemail.com
Wed Apr 14 19:15:25 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=afc766fc12d54670aaed9bbb228efc7a5be561db
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
unzip_main                                          2644    2665     +21
input_tab                                            926     927      +1
bb_banner                                             46      47      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 23/0)               Total: 23 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 archival/unzip.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/archival/unzip.c b/archival/unzip.c
index d94bbabcf..12db4e579 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -82,11 +82,13 @@ enum {
 	ZIP_FILEHEADER_MAGIC = 0x504b0304,
 	ZIP_CDF_MAGIC        = 0x504b0102, /* CDF item */
 	ZIP_CDE_MAGIC        = 0x504b0506, /* End of CDF */
+	ZIP64_CDE_MAGIC      = 0x504b0606, /* End of Zip64 CDF */
 	ZIP_DD_MAGIC         = 0x504b0708,
 #else
 	ZIP_FILEHEADER_MAGIC = 0x04034b50,
 	ZIP_CDF_MAGIC        = 0x02014b50,
 	ZIP_CDE_MAGIC        = 0x06054b50,
+	ZIP64_CDE_MAGIC      = 0x06064b50,
 	ZIP_DD_MAGIC         = 0x08074b50,
 #endif
 };
@@ -260,6 +262,12 @@ static uint32_t find_cdf_offset(void)
 			continue;
 		/* we found CDE! */
 		memcpy(cde.raw, p + 1, CDE_LEN);
+		dbg("cde.this_disk_no:%d",             cde.fmt.this_disk_no            );
+		dbg("cde.disk_with_cdf_no:%d",         cde.fmt.disk_with_cdf_no        );
+		dbg("cde.cdf_entries_on_this_disk:%d", cde.fmt.cdf_entries_on_this_disk);
+		dbg("cde.cdf_entries_total:%d",        cde.fmt.cdf_entries_total       );
+		dbg("cde.cdf_size:%d",                 cde.fmt.cdf_size                );
+		dbg("cde.cdf_offset:%x",               cde.fmt.cdf_offset              );
 		FIX_ENDIANNESS_CDE(cde);
 		/*
 		 * I've seen .ZIP files with seemingly valid CDEs
@@ -302,19 +310,27 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf)
 		dbg("got ZIP_CDE_MAGIC");
 		return 0; /* EOF */
 	}
+	if (magic == ZIP64_CDE_MAGIC) { /* seen in .zip with >4GB files */
+		dbg("got ZIP64_CDE_MAGIC");
+		return 0; /* EOF */
+	}
 	xread(zip_fd, cdf->raw, CDF_HEADER_LEN);
 
 	FIX_ENDIANNESS_CDF(*cdf);
-	dbg("  filename_len:%u extra_len:%u file_comment_length:%u",
+	dbg("  magic:%08x filename_len:%u extra_len:%u file_comment_length:%u",
+		magic,
 		(unsigned)cdf->fmt.filename_len,
 		(unsigned)cdf->fmt.extra_len,
 		(unsigned)cdf->fmt.file_comment_length
 	);
+//TODO: require that magic == ZIP_CDF_MAGIC?
+
 	cdf_offset += 4 + CDF_HEADER_LEN
 		+ cdf->fmt.filename_len
 		+ cdf->fmt.extra_len
 		+ cdf->fmt.file_comment_length;
 
+	dbg("Next cdf_offset 0x%x", cdf_offset);
 	return cdf_offset;
 };
 #endif
@@ -436,7 +452,9 @@ static void unzip_extract(zip_header_t *zip, int dst_fd)
 	}
 
 	/* Validate decompression - size */
-	if (zip->fmt.ucmpsize != xstate.bytes_out) {
+	if (zip->fmt.ucmpsize != 0xffffffff /* seen on files with >4GB uncompressed data */
+	 && zip->fmt.ucmpsize != xstate.bytes_out
+	) {
 		/* Don't die. Who knows, maybe len calculation
 		 * was botched somewhere. After all, crc matched! */
 		bb_simple_error_msg("bad length");


More information about the busybox-cvs mailing list