diff options
author | Martin Matuska <mm@FreeBSD.org> | 2021-08-23 00:24:04 +0000 |
---|---|---|
committer | Martin Matuska <mm@FreeBSD.org> | 2021-08-23 00:24:04 +0000 |
commit | 9aa5476184726da9d9159568c9b15e29451b5778 (patch) | |
tree | 3896a8e970fd3caae9cd4c1380fb98a368a461d6 /libarchive/archive_read_support_format_zip.c | |
parent | 8be2bb3d35e232080b4e39244020e650bbe31562 (diff) | |
download | src-9aa5476184726da9d9159568c9b15e29451b5778.tar.gz src-9aa5476184726da9d9159568c9b15e29451b5778.zip |
Update vendor/libarchive/dist to libarchive/libarchive@1b2c437b9
Libarchive 3.5.2
New features:
PR #1502: Support for PWB and v7 binary cpio formats
PR #1509: Support of deflate algorithm in symbolic link decompression
for ZIP archives
Important bugfixes:
IS #1044: fix extraction of hardlinks to symlinks
PR #1480: Fix truncation of size values during 7zip archive
extraction on 32bit architectures
PR #1504: fix rar header skiming
PR #1514: ZIP excessive disk read - fix location of central directory
PR #1520: fix double-free in CAB reader
PR #1521: Fixed leak of rar before ending with error
PR #1530: Handle short writes from archive_write_callback
PR #1532: 7zip: Use compression settings from file also for file header
IS #1566: do not follow symlinks when processing the fixup list
Obtained from: libarchive
Libarchive commit: 1b2c437b99b361c7692538fa373e99955e9b93ae
Libarchive tag: v3.5.2
Diffstat (limited to 'libarchive/archive_read_support_format_zip.c')
-rw-r--r-- | libarchive/archive_read_support_format_zip.c | 154 |
1 files changed, 52 insertions, 102 deletions
diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index a64332c2818c..21d41cc0f741 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -142,6 +142,7 @@ struct zip { /* Structural information about the archive. */ struct archive_string format_name; int64_t central_directory_offset; + int64_t central_directory_offset_adjusted; size_t central_directory_entries_total; size_t central_directory_entries_on_this_disk; int has_encrypted_entries; @@ -246,6 +247,17 @@ struct zip { /* Many systems define min or MIN, but not all. */ #define zipmin(a,b) ((a) < (b) ? (a) : (b)) +#ifdef HAVE_ZLIB_H +static int +zip_read_data_deflate(struct archive_read *a, const void **buff, + size_t *size, int64_t *offset); +#endif +#if HAVE_LZMA_H && HAVE_LIBLZMA +static int +zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff, + size_t *size, int64_t *offset); +#endif + /* This function is used by Ppmd8_DecodeSymbol during decompression of Ppmd8 * streams inside ZIP files. It has 2 purposes: one is to fetch the next * compressed byte from the stream, second one is to increase the counter how @@ -899,81 +911,6 @@ process_extra(struct archive_read *a, struct archive_entry *entry, return ARCHIVE_OK; } -#if HAVE_LZMA_H && HAVE_LIBLZMA -/* - * Auxiliary function to uncompress data chunk from zipx archive - * (zip with lzma compression). - */ -static int -zipx_lzma_uncompress_buffer(const char *compressed_buffer, - size_t compressed_buffer_size, - char *uncompressed_buffer, - size_t uncompressed_buffer_size) -{ - int status = ARCHIVE_FATAL; - // length of 'lzma properties data' in lzma compressed - // data segment (stream) inside zip archive - const size_t lzma_params_length = 5; - // offset of 'lzma properties data' from the beginning of lzma stream - const size_t lzma_params_offset = 4; - // end position of 'lzma properties data' in lzma stream - const size_t lzma_params_end = lzma_params_offset + lzma_params_length; - if (compressed_buffer == NULL || - compressed_buffer_size < lzma_params_end || - uncompressed_buffer == NULL) - return status; - - // prepare header for lzma_alone_decoder to replace zipx header - // (see comments in 'zipx_lzma_alone_init' for justification) -#pragma pack(push) -#pragma pack(1) - struct _alone_header - { - uint8_t bytes[5]; // lzma_params_length - uint64_t uncompressed_size; - } alone_header; -#pragma pack(pop) - // copy 'lzma properties data' blob - memcpy(&alone_header.bytes[0], compressed_buffer + lzma_params_offset, - lzma_params_length); - alone_header.uncompressed_size = UINT64_MAX; - - // prepare new compressed buffer, see 'zipx_lzma_alone_init' for details - const size_t lzma_alone_buffer_size = - compressed_buffer_size - lzma_params_end + sizeof(alone_header); - unsigned char *lzma_alone_compressed_buffer = - (unsigned char*) malloc(lzma_alone_buffer_size); - if (lzma_alone_compressed_buffer == NULL) - return status; - // copy lzma_alone header into new buffer - memcpy(lzma_alone_compressed_buffer, (void*) &alone_header, - sizeof(alone_header)); - // copy compressed data into new buffer - memcpy(lzma_alone_compressed_buffer + sizeof(alone_header), - compressed_buffer + lzma_params_end, - compressed_buffer_size - lzma_params_end); - - // create and fill in lzma_alone_decoder stream - lzma_stream stream = LZMA_STREAM_INIT; - lzma_ret ret = lzma_alone_decoder(&stream, UINT64_MAX); - if (ret == LZMA_OK) - { - stream.next_in = lzma_alone_compressed_buffer; - stream.avail_in = lzma_alone_buffer_size; - stream.total_in = 0; - stream.next_out = (unsigned char*)uncompressed_buffer; - stream.avail_out = uncompressed_buffer_size; - stream.total_out = 0; - ret = lzma_code(&stream, LZMA_RUN); - if (ret == LZMA_OK || ret == LZMA_STREAM_END) - status = ARCHIVE_OK; - } - lzma_end(&stream); - free(lzma_alone_compressed_buffer); - return status; -} -#endif - /* * Assumes file pointer is at beginning of local file header. */ @@ -1242,36 +1179,30 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, linkname_length = (size_t)zip_entry->compressed_size; archive_entry_set_size(entry, 0); - p = __archive_read_ahead(a, linkname_length, NULL); - if (p == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Truncated Zip file"); - return ARCHIVE_FATAL; - } + // take into account link compression if any size_t linkname_full_length = linkname_length; if (zip->entry->compression != 0) { // symlink target string appeared to be compressed int status = ARCHIVE_FATAL; - char *uncompressed_buffer = - (char*) malloc(zip_entry->uncompressed_size); - if (uncompressed_buffer == NULL) - { - archive_set_error(&a->archive, ENOMEM, - "No memory for lzma decompression"); - return status; - } + const void *uncompressed_buffer; switch (zip->entry->compression) { +#if HAVE_ZLIB_H + case 8: /* Deflate compression. */ + zip->entry_bytes_remaining = zip_entry->compressed_size; + status = zip_read_data_deflate(a, &uncompressed_buffer, + &linkname_full_length, NULL); + break; +#endif #if HAVE_LZMA_H && HAVE_LIBLZMA case 14: /* ZIPx LZMA compression. */ /*(see zip file format specification, section 4.4.5)*/ - status = zipx_lzma_uncompress_buffer(p, - linkname_length, - uncompressed_buffer, - (size_t)zip_entry->uncompressed_size); + zip->entry_bytes_remaining = zip_entry->compressed_size; + status = zip_read_data_zipx_lzma_alone(a, &uncompressed_buffer, + &linkname_full_length, NULL); break; #endif default: /* Unsupported compression. */ @@ -1280,8 +1211,6 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, if (status == ARCHIVE_OK) { p = uncompressed_buffer; - linkname_full_length = - (size_t)zip_entry->uncompressed_size; } else { @@ -1294,6 +1223,16 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, return ARCHIVE_FAILED; } } + else + { + p = __archive_read_ahead(a, linkname_length, NULL); + } + + if (p == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Truncated Zip file"); + return ARCHIVE_FATAL; + } sconv = zip->sconv; if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME)) @@ -1663,7 +1602,8 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip) /* To unpack ZIPX's "LZMA" (id 14) stream we can use standard liblzma * that is a part of XZ Utils. The stream format stored inside ZIPX * file is a modified "lzma alone" file format, that was used by the - * `lzma` utility which was later deprecated in favour of `xz` utility. * Since those formats are nearly the same, we can use a standard + * `lzma` utility which was later deprecated in favour of `xz` utility. + * Since those formats are nearly the same, we can use a standard * "lzma alone" decoder from XZ Utils. */ memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream)); @@ -3415,24 +3355,31 @@ archive_read_support_format_zip_capabilities_seekable(struct archive_read * a) static int read_eocd(struct zip *zip, const char *p, int64_t current_offset) { + uint16_t disk_num; + uint32_t cd_size, cd_offset; + + disk_num = archive_le16dec(p + 4); + cd_size = archive_le32dec(p + 12); + cd_offset = archive_le32dec(p + 16); + /* Sanity-check the EOCD we've found. */ /* This must be the first volume. */ - if (archive_le16dec(p + 4) != 0) + if (disk_num != 0) return 0; /* Central directory must be on this volume. */ - if (archive_le16dec(p + 4) != archive_le16dec(p + 6)) + if (disk_num != archive_le16dec(p + 6)) return 0; /* All central directory entries must be on this volume. */ if (archive_le16dec(p + 10) != archive_le16dec(p + 8)) return 0; /* Central directory can't extend beyond start of EOCD record. */ - if (archive_le32dec(p + 16) + archive_le32dec(p + 12) - > current_offset) + if (cd_offset + cd_size > current_offset) return 0; /* Save the central directory location for later use. */ - zip->central_directory_offset = archive_le32dec(p + 16); + zip->central_directory_offset = cd_offset; + zip->central_directory_offset_adjusted = current_offset - cd_size; /* This is just a tiny bit higher than the maximum returned by the streaming Zip bidder. This ensures @@ -3484,6 +3431,8 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p) /* Save the central directory offset for later use. */ zip->central_directory_offset = archive_le64dec(p + 48); + /* TODO: Needs scanning backwards to find the eocd64 instead of assuming */ + zip->central_directory_offset_adjusted = zip->central_directory_offset; return 32; } @@ -3655,7 +3604,8 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry, * know the correction we need to apply to account for leading * padding. */ - if (__archive_read_seek(a, zip->central_directory_offset, SEEK_SET) < 0) + if (__archive_read_seek(a, zip->central_directory_offset_adjusted, SEEK_SET) + < 0) return ARCHIVE_FATAL; found = 0; |