]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
7zip: Fix SEGV in check_7zip_header_in_sfx via ELF offset validation 2864/head
authorVijay D'Silva <vijaydsilva@google.com>
Thu, 12 Feb 2026 03:51:51 +0000 (03:51 +0000)
committerVijay D'Silva <vijaydsilva@google.com>
Thu, 12 Feb 2026 04:46:19 +0000 (04:46 +0000)
The crash reported in this issue is caused by a segmentation fault
that happens when a pointer `p` passed to `check_7zip_header_in_sfx`
is dereferenced. That argument `p` is defined as `p = buff + offset` in
`archive_read_format_7zip_bid` with `offset` determined by a call
to `find_elf_data_sec`.

Within `find_elf_data_sec`, a 64-bit ELF section offset is cast
to `ssize_t`. For a sufficiently large offset, such as an unsigned
64-bit value exceeding `SSIZE_MAX`, the `ssize_t` will be negative,
which leads to `p` to point before the start of the buffer.

This patch eliminates the problem by:
1. Reading the ELF section offset into a `uint64_t`.
2. Validating that the offset does not exceed `SSIZE_MAX`.
3. If the offset is invalid, breaking the loop to retain the safe
   default `SFX_MIN_ADDR`.

These checks ensure that `min_addr` is always within the bounds of the buffer.
This PR includes a regression test `test_malformed3` in
`test_read_format_7zip_malformed.c` using a crafted reproducer file.

CodeMender verified with AddressSanitizer that the crash is resolved and the
test suite passes.

Co-authored-by: CodeMender <codemender-patching@google.com>
Fixes: https://issues.oss-fuzz.com/issues/470963352
libarchive/archive_read_support_format_7zip.c
libarchive/test/test_read_format_7zip_malformed.c
libarchive/test/test_read_format_7zip_malformed3.7z.uu [new file with mode: 0644]

index 330d5515dd50de2d1c87481b16eb597db86b7544..46bc1744517fc195b7f3e8282c72ac5894c27a10 100644 (file)
@@ -34,6 +34,9 @@
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_BZLIB_H
 #include <bzlib.h>
 #endif
@@ -855,13 +858,18 @@ find_elf_data_sec(struct archive_read *a)
                while (e_shnum > 0) {
                        name_offset = (*dec32)(h + sec_tbl_offset);
                        if (name_offset == data_sym_offset) {
+                               uint64_t sel_offset;
+
                                if (format_64) {
-                                       min_addr = (*dec64)(
+                                       sel_offset = (*dec64)(
                                            h + sec_tbl_offset + 0x18);
                                } else {
-                                       min_addr = (*dec32)(
+                                       sel_offset = (*dec32)(
                                            h + sec_tbl_offset + 0x10);
                                }
+                               if (sel_offset > SSIZE_MAX)
+                                       break;
+                               min_addr = (ssize_t)sel_offset;
                                break;
                        }
                        sec_tbl_offset += e_shentsize;
index f2120879fa8ce4fd4b4b935f6fda4866c5b662ae..bd3452c00aad5ea4ae400ae9659a0db6d5d16392 100644 (file)
@@ -59,8 +59,25 @@ test_malformed2(void)
        assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
 }
 
+
+static void
+test_malformed3(void)
+{
+       const char *refname = "test_read_format_7zip_malformed3.7z";
+       struct archive *a;
+
+       extract_reference_file(refname);
+
+       assert((a = archive_read_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_FATAL, archive_read_open_filename(a, refname, 10240));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+}
+
 DEFINE_TEST(test_read_format_7zip_malformed)
 {
        test_malformed1();
        test_malformed2();
+       test_malformed3();
 }
diff --git a/libarchive/test/test_read_format_7zip_malformed3.7z.uu b/libarchive/test/test_read_format_7zip_malformed3.7z.uu
new file mode 100644 (file)
index 0000000..4e81498
--- /dev/null
@@ -0,0 +1,24 @@
+begin 644 test_read_format_7zip_malformed3.7z
+M?T5,1@("`64N9&5B=0``+ZZNRO_______P```/\Q```````````"````````
+M```L0"!S+F)S,``1<P!```H``FMK__](:VMK:VNAH:$!`*&AH:&A)S$```!C
+M;VUP>FEP503_8G-S90``````#0H-_P```'X```````````(`````````````
+M`*D``````"\`````____^@````$````````#`/__________<RYD96)U```O
+MKJ[*________````_S$```````````(``````````"Q`(',N8G,P`!%S`$``
+M(``":VNAH2<Q```````#Z'K__P5%145%____________`/__________;VUP
+M>FEP503_8G-S90``````#0H-_P```'X```````````(``````````````*D`
+M`````"\`````____^@````$````````#_P```/______<RYD96)U```OKJ[*
+M________````_S$```````````(``````````"Q`(',N8G,P`!%S`$"0`P`"
+M:VLR:TAK:VMK:Z&AH0$`H:&AH:$G,@```&-O;7!Z:7!5!/]28W-E```````-
+M"@W_````?@```````````@``````````````J0``````+P`````0___Z````
+M`0````````,`__________\PXT$N9&%T80#^E)3+E)24_P3_____________
+M____(________^+______P5%145%____________`/__________________
+M_____________________^?_________145%0``#`/Z4E,N4P<'!P<'!E```
+M`/_R`````'5U=75U=75U=75U=75U=75U=75U=75U=75U=75U=75U=75U=75U
+M=75U=75U=75U=75U=75U=75U=75U=75U=75U=75U=75U=75U=0`````"````
+M```````L0"!S+F4```````T*#?\```!^```````````"``````````````"I
+M```````O`````/___^0````!`````````P#__W5U=75U=75U=75U=75U=75U
+M=0`````"```````````L0"!S+F)S,?P1<P!```,`"&MK,FM(:VMK145%145%
+,P45%145%1?____\$
+`
+end
+