]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Issue 553: Fix broken decryption for ZIP files.
authorTim Kientzle <kientzle@gmail.com>
Thu, 16 Jun 2016 01:38:30 +0000 (18:38 -0700)
committerTim Kientzle <kientzle@gmail.com>
Thu, 16 Jun 2016 01:38:30 +0000 (18:38 -0700)
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

index 0a0be96b5990ba0a7837fb9e53dd744900864d51..34ab04ecc9b84296a9900586a77ea27ea578f08e 100644 (file)
@@ -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;