From fa32110f851b121a3e1c19fda347e86396fde2bd Mon Sep 17 00:00:00 2001
From: elhananhaenel <elhanan.haenel@mail.huji.ac.il>
Date: Sat, 7 Mar 2026 22:32:09 +0200
Subject: [PATCH 1/2] 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.

CVE: CVE-2026-4424
Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/d379dc0b2976b7207d1ad78f5ed3eb99a5b6d375]
Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
---
 libarchive/archive_read_support_format_rar.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
index 88eab627..b23be937 100644
--- a/libarchive/archive_read_support_format_rar.c
+++ b/libarchive/archive_read_support_format_rar.c
@@ -2503,7 +2503,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.
@@ -3104,6 +3105,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");
@@ -3266,7 +3272,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;
-- 
2.43.0

