diff options
author | cielavenir <cielartisan@gmail.com> | 2022-02-18 18:19:12 +0900 |
---|---|---|
committer | cielavenir <cielartisan@gmail.com> | 2022-02-18 18:19:12 +0900 |
commit | a57125009c99fdd4675b71498987e91fc53a7d2f (patch) | |
tree | 38780dfa6a1d4da6c13cd822161a81751ac2c32b /libarchive/archive_read_support_format_7zip.c | |
parent | 93f03b0f5d7316714df9b289a49150ab7a63bfaf (diff) | |
download | libarchive-a57125009c99fdd4675b71498987e91fc53a7d2f.tar.gz |
Fix 7z PPMD reading beyond boundary
Diffstat (limited to 'libarchive/archive_read_support_format_7zip.c')
-rw-r--r-- | libarchive/archive_read_support_format_7zip.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index 63cbb7df..f15374f7 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -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) { |