Fix for CVE-2024-20696

Resolves: RHEL-40042
This commit is contained in:
Lukas Javorsky 2024-06-06 09:05:07 +00:00
parent 27406e543c
commit 8f2e60d141
2 changed files with 128 additions and 1 deletions

View File

@ -0,0 +1,119 @@
From eac15e252010c1189a5c0f461364dbe2cd2a68b1 Mon Sep 17 00:00:00 2001
From: "Dustin L. Howett" <dustin@howett.net>
Date: Thu, 9 May 2024 18:59:17 -0500
Subject: [PATCH] rar4 reader: protect copy_from_lzss_window_to_unp() (#2172)
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 4fc6626c..5776df4b 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.1

View File

@ -2,7 +2,7 @@
Name: libarchive Name: libarchive
Version: 3.7.2 Version: 3.7.2
Release: 5%{?dist} Release: 6%{?dist}
Summary: A library for handling streaming archive formats Summary: A library for handling streaming archive formats
# Licenses: # Licenses:
@ -52,6 +52,10 @@ Patch0002: 0002-tests-fix-zstd-long-option-test-for-32-bit-architect.patch
# Fixes Heap based buffer overflow in rar e8 filter (CVE-2024-26256) # Fixes Heap based buffer overflow in rar e8 filter (CVE-2024-26256)
Patch0003: 0003-fix-OOB-in-rar-e8-filter.patch Patch0003: 0003-fix-OOB-in-rar-e8-filter.patch
# Upstream patch: https://github.com/libarchive/libarchive/commit/eac15e252010c1189a5c0f461364dbe2cd2a68b1
# Fixes CVE-2024-20696
Patch0004: 0004-rar4-reader-protect-copy_from_lzss_window_to_unp-217.patch
%description %description
Libarchive is a programming library that can create and read several different Libarchive is a programming library that can create and read several different
streaming archive formats, including most popular tar variants, several cpio streaming archive formats, including most popular tar variants, several cpio
@ -249,6 +253,10 @@ run_testsuite
%changelog %changelog
* Thu Jun 06 2024 Lukas Javorsky <ljavorsk@redhat.com> - 3.7.2-6
- Fix CVE-2024-20696
- Resolves: RHEL-40042
* Mon May 27 2024 Lukas Javorsky <ljavorsk@redhat.com> - 3.7.2-5 * Mon May 27 2024 Lukas Javorsky <ljavorsk@redhat.com> - 3.7.2-5
- Fix for CVE-2024-26256 - Fix for CVE-2024-26256