Control: tags 1086155 + patch
Control: tags 1086155 + pending

Dear maintainer,

I've prepared an NMU for libarchive (versioned as 3.7.4-1.1) and
uploaded it to DELAYED/2. Please feel free to tell me if I
should delay it longer.

MR corresponding is at 
https://salsa.debian.org/debian/libarchive/-/merge_requests/7 

Regards,
Salvatore
diff -Nru libarchive-3.7.4/debian/changelog libarchive-3.7.4/debian/changelog
--- libarchive-3.7.4/debian/changelog	2024-08-07 13:36:27.000000000 +0200
+++ libarchive-3.7.4/debian/changelog	2024-11-01 21:30:39.000000000 +0100
@@ -1,3 +1,10 @@
+libarchive (3.7.4-1.1) unstable; urgency=medium
+
+  * rar4 reader: protect copy_from_lzss_window_to_unp() (CVE-2024-20696)
+    (Closes: #1086155)
+
+ -- Salvatore Bonaccorso <car...@debian.org>  Fri, 01 Nov 2024 21:30:39 +0100
+
 libarchive (3.7.4-1) unstable; urgency=medium
 
   * Drop a t64-related Lintian override.
diff -Nru libarchive-3.7.4/debian/patches/rar4-reader-protect-copy_from_lzss_window_to_unp-217.patch libarchive-3.7.4/debian/patches/rar4-reader-protect-copy_from_lzss_window_to_unp-217.patch
--- libarchive-3.7.4/debian/patches/rar4-reader-protect-copy_from_lzss_window_to_unp-217.patch	1970-01-01 01:00:00.000000000 +0100
+++ libarchive-3.7.4/debian/patches/rar4-reader-protect-copy_from_lzss_window_to_unp-217.patch	2024-11-01 21:28:54.000000000 +0100
@@ -0,0 +1,122 @@
+From: "Dustin L. Howett" <dus...@howett.net>
+Date: Thu, 9 May 2024 18:59:17 -0500
+Subject: rar4 reader: protect copy_from_lzss_window_to_unp() (#2172)
+Origin: https://github.com/libarchive/libarchive/commit/eac15e252010c1189a5c0f461364dbe2cd2a68b1
+Bug: https://github.com/libarchive/libarchive/pull/2172
+Bug-Debian: https://bugs.debian.org/1086155
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2024-20696
+
+copy_from_lzss_window_to_unp unnecessarily took an `int` parameter where
+both of its callers were holding a `size_t`.
+
+A lzss opcode chain could be constructed that resulted in a negative
+copy length, which when passed into memcpy would result in a very, very
+large positive number.
+
+Switching copy_from_lzss_window_to_unp to take a `size_t` allows it to
+properly bounds-check length.
+
+In addition, this patch also ensures that `length` is not itself larger
+than the destination buffer.
+
+Security: CVE-2024-20696
+---
+ libarchive/archive_read_support_format_rar.c | 28 +++++++++++++-------
+ 1 file changed, 18 insertions(+), 10 deletions(-)
+
+diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
+index 4fc6626cacfd..5776df4bd944 100644
+--- a/libarchive/archive_read_support_format_rar.c
++++ b/libarchive/archive_read_support_format_rar.c
+@@ -432,7 +432,7 @@ static int make_table_recurse(struct archive_read *, struct huffman_code *, int,
+                               struct huffman_table_entry *, int, int);
+ static int expand(struct archive_read *, int64_t *);
+ static int copy_from_lzss_window_to_unp(struct archive_read *, const void **,
+-                                        int64_t, int);
++                                        int64_t, size_t);
+ static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);
+ static int parse_filter(struct archive_read *, const uint8_t *, uint16_t,
+                         uint8_t);
+@@ -2060,7 +2060,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
+         bs = rar->unp_buffer_size - rar->unp_offset;
+       else
+         bs = (size_t)rar->bytes_uncopied;
+-      ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs);
++      ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, bs);
+       if (ret != ARCHIVE_OK)
+         return (ret);
+       rar->offset += bs;
+@@ -2213,7 +2213,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
+       bs = rar->unp_buffer_size - rar->unp_offset;
+     else
+       bs = (size_t)rar->bytes_uncopied;
+-    ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs);
++    ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, bs);
+     if (ret != ARCHIVE_OK)
+       return (ret);
+     rar->offset += bs;
+@@ -3094,11 +3094,16 @@ copy_from_lzss_window(struct archive_read *a, void *buffer,
+ 
+ static int
+ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
+-                             int64_t startpos, int length)
++                             int64_t startpos, size_t length)
+ {
+   int windowoffs, firstpart;
+   struct rar *rar = (struct rar *)(a->format->data);
+ 
++  if (length > rar->unp_buffer_size)
++  {
++    goto fatal;
++  }
++
+   if (!rar->unp_buffer)
+   {
+     if ((rar->unp_buffer = malloc(rar->unp_buffer_size)) == NULL)
+@@ -3110,17 +3115,17 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
+   }
+ 
+   windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
+-  if(windowoffs + length <= lzss_size(&rar->lzss)) {
++  if(windowoffs + length <= (size_t)lzss_size(&rar->lzss)) {
+     memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],
+            length);
+-  } else if (length <= lzss_size(&rar->lzss)) {
++  } else if (length <= (size_t)lzss_size(&rar->lzss)) {
+     firstpart = lzss_size(&rar->lzss) - windowoffs;
+     if (firstpart < 0) {
+       archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                         "Bad RAR file data");
+       return (ARCHIVE_FATAL);
+     }
+-    if (firstpart < length) {
++    if ((size_t)firstpart < length) {
+       memcpy(&rar->unp_buffer[rar->unp_offset],
+              &rar->lzss.window[windowoffs], firstpart);
+       memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],
+@@ -3130,9 +3135,7 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
+              &rar->lzss.window[windowoffs], length);
+     }
+   } else {
+-      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+-                        "Bad RAR file data");
+-      return (ARCHIVE_FATAL);
++      goto fatal;
+   }
+   rar->unp_offset += length;
+   if (rar->unp_offset >= rar->unp_buffer_size)
+@@ -3140,6 +3143,11 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
+   else
+     *buffer = NULL;
+   return (ARCHIVE_OK);
++
++fatal:
++  archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++                    "Bad RAR file data");
++  return (ARCHIVE_FATAL);
+ }
+ 
+ static const void *
+-- 
+2.45.2
+
diff -Nru libarchive-3.7.4/debian/patches/series libarchive-3.7.4/debian/patches/series
--- libarchive-3.7.4/debian/patches/series	2024-08-07 13:36:27.000000000 +0200
+++ libarchive-3.7.4/debian/patches/series	2024-11-01 21:29:23.000000000 +0100
@@ -1,3 +1,4 @@
 typos.patch
 fix-OOB-in-rar-delta-filter-2148.patch
 fix-OOB-in-rar-audio-filter-2149.patch
+rar4-reader-protect-copy_from_lzss_window_to_unp-217.patch

Reply via email to