]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Fix 7z PPMD reading beyond boundary
authorcielavenir <cielartisan@gmail.com>
Fri, 18 Feb 2022 09:19:12 +0000 (18:19 +0900)
committercielavenir <cielartisan@gmail.com>
Fri, 18 Feb 2022 09:19:12 +0000 (18:19 +0900)
libarchive/archive_read_support_format_7zip.c

index 63cbb7df32c8177a8054bbe864e8ecdeb56b4318..f15374f7a58b8b677abefc696bd9f550fae97bd9 100644 (file)
@@ -287,6 +287,7 @@ struct _7zip {
                const unsigned char     *next_in;
                int64_t                  avail_in;
                int64_t                  total_in;
+               int64_t                  stream_in;
                unsigned char           *next_out;
                int64_t                  avail_out;
                int64_t                  total_out;
@@ -986,15 +987,27 @@ ppmd_read(void *p)
        struct _7zip *zip = (struct _7zip *)(a->format->data);
        Byte b;
 
-       if (zip->ppstream.avail_in == 0) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Truncated RAR file data");
-               zip->ppstream.overconsumed = 1;
-               return (0);
+       if (zip->ppstream.avail_in <= 0) {
+               // Ppmd7_DecodeSymbol might require reading multiple bytes and we are on boundary; last resort to read using __archive_read_ahead.
+               ssize_t bytes_avail = 0;
+               const uint8_t* data = __archive_read_ahead(a, zip->ppstream.stream_in+1, &bytes_avail);
+               if(bytes_avail < zip->ppstream.stream_in+1) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                               "Truncated 7z file data");
+                       zip->ppstream.overconsumed = 1;
+                       return (0);
+               }
+               zip->ppstream.next_in++;
+               b = data[zip->ppstream.stream_in];
+               zip->ppstream.avail_in--;
+               zip->ppstream.total_in++;
+               zip->ppstream.stream_in++;
+       } else {
+               b = *zip->ppstream.next_in++;
+               zip->ppstream.avail_in--;
+               zip->ppstream.total_in++;
+               zip->ppstream.stream_in++;
        }
-       b = *zip->ppstream.next_in++;
-       zip->ppstream.avail_in--;
-       zip->ppstream.total_in++;
        return (b);
 }
 
@@ -1485,6 +1498,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
                }
                zip->ppstream.next_in = t_next_in;
                zip->ppstream.avail_in = t_avail_in;
+               zip->ppstream.stream_in = 0;
                zip->ppstream.next_out = t_next_out;
                zip->ppstream.avail_out = t_avail_out;
                if (zip->ppmd7_stat == 0) {