unzip: fix for .zip archives with >4GB file
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@googlemail.com>
This commit is contained in:
		| @@ -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"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user