From: elhananhaenel Date: Sat, 7 Mar 2026 20:32:09 +0000 (+0200) Subject: rar: fix LZSS window size mismatch after PPMd block X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d379dc0b2976b7207d1ad78f5ed3eb99a5b6d375;p=thirdparty%2Flibarchive.git rar: fix LZSS window size mismatch after PPMd block When a PPMd-compressed block updates dictionary_size, the LZSS window from a prior block is not reallocated. The allocation guard only checks if dictionary_size is zero or the window pointer is NULL, not whether the existing window is large enough. This allows copy_from_lzss_window() to read past the allocated buffer. Fix the guard to also check whether the current window is undersized. Add bounds checks in copy_from_lzss_window() and parse_filter() as defense in depth. --- diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c index 9b401c00b..08e407f9d 100644 --- a/libarchive/archive_read_support_format_rar.c +++ b/libarchive/archive_read_support_format_rar.c @@ -2548,7 +2548,8 @@ parse_codes(struct archive_read *a) return (r); } - if (!rar->dictionary_size || !rar->lzss.window) + if (!rar->dictionary_size || !rar->lzss.window || + (rar->lzss.mask + 1) < rar->dictionary_size) { /* Seems as though dictionary sizes are not used. Even so, minimize * memory usage as much as possible. @@ -3149,6 +3150,11 @@ copy_from_lzss_window(struct archive_read *a, uint8_t *buffer, windowoffs = lzss_offset_for_position(&rar->lzss, startpos); firstpart = lzss_size(&rar->lzss) - windowoffs; + if (length > lzss_size(&rar->lzss)) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Bad RAR file data"); + return (ARCHIVE_FATAL); + } if (firstpart < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Bad RAR file data"); @@ -3315,7 +3321,8 @@ parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint else blocklength = prog ? prog->oldfilterlength : 0; - if (blocklength > rar->dictionary_size) + if (blocklength > rar->dictionary_size || + blocklength > (uint32_t)(rar->lzss.mask + 1)) return 0; registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS;