From d85976e7ff4a062e1de6e04dab7bb78e3344768f Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Wed, 15 Jun 2016 18:38:30 -0700 Subject: [PATCH] Issue 553: Fix broken decryption for ZIP files. Sometimes, decompressing was failing due to miscalculation of buffer offsets, and hence causing a silent buffer overflow. When a previous chunk decompression left some bytes in the decryption buffer, it was not taken into account in determining space left in the decompression buffer. So, it could happen, that the decryption buffer is completely full, but some bytes are not used yet. In such case, even though the buffer is full, the code tried to decrypt more bytes behind it's boundary. This CL resolves this issue by properly calculating the amount of space left in the decompression buffer. (This is an edited version of Tomasz Mikolajewski's pull request.) --- libarchive/archive_read_support_format_zip.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 0a0be96b5..34ab04ecc 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -181,6 +181,14 @@ struct zip { char init_decryption; /* Decryption buffer. */ + /* + * The decrypted data starts at decrypted_ptr and + * extends for decrypted_bytes_remaining. Decryption + * adds new data to the end of this block, data is returned + * to clients from the beginning. When the block hits the + * end of decrypted_buffer, it has to be shuffled back to + * the beginning of the buffer. + */ unsigned char *decrypted_buffer; unsigned char *decrypted_ptr; size_t decrypted_buffer_size; @@ -1293,8 +1301,9 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, if (zip->tctx_valid || zip->cctx_valid) { if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) { - size_t buff_remaining = zip->decrypted_buffer_size - - (zip->decrypted_ptr - zip->decrypted_buffer); + size_t buff_remaining = + (zip->decrypted_buffer + zip->decrypted_buffer_size) + - (zip->decrypted_ptr + zip->decrypted_bytes_remaining); if (buff_remaining > (size_t)bytes_avail) buff_remaining = (size_t)bytes_avail;