]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
7zip: Cap maximum allocation for SFX handling
authorTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 27 Apr 2026 17:58:05 +0000 (19:58 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 27 Apr 2026 18:10:06 +0000 (20:10 +0200)
If 7zip header cannot be found within roughly first 8 MB of data, skip
detection and assume that file is not a valid 7zip archive.

This avoids various 32 bit truncation issues as well as out of memory
conditions.

Reported by various individuals:
- Amemoyoi
- b4sh5i
- Jie Zhu
- Tikket
- wooseokdotkim

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
libarchive/archive_read_support_format_7zip.c

index 9aa9d952b6ba6d9d6cca39ced90f4e673249f221..79519e9b201093745cbc620d0588852f946ee55c 100644 (file)
@@ -67,6 +67,7 @@
 #define SFX_MIN_ADDR   0x27000
 #define SFX_MAX_ADDR   0x60000
 #define SFX_MAX_OFFSET (SFX_MAX_ADDR - SFX_MIN_ADDR)
+#define SFX_MAX_SEEK   0x800000
 
 /*
  * PE format
@@ -560,7 +561,7 @@ get_data_offset(struct archive_read *a, int64_t *data_offset)
                r = get_elf_sfx_offset(a, &sfx_offset);
        else
                r = ARCHIVE_FATAL;
-       if (r < ARCHIVE_WARN)
+       if (r < ARCHIVE_WARN || sfx_offset > SFX_MAX_SEEK)
                goto fail;
 
        offset = sfx_offset;
@@ -659,6 +660,9 @@ get_pe_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
                        break;
                }
                offset = archive_le32dec(h + PE_DOS_HDR_ELFANEW_OFFSET);
+               if (offset > SFX_MAX_SEEK) {
+                       return (ARCHIVE_FATAL);
+               }
 
                /*
                 * Read COFF header to find opt header size and sec cnt
@@ -687,6 +691,10 @@ get_pe_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
                        break;
                }
 
+               if (offset + sec_cnt * PE_SEC_HDR_LEN > SFX_MAX_SEEK) {
+                       return (ARCHIVE_FATAL);
+               }
+
                /*
                 * Traverse sec table to find max raw offset (i.e., overlay)
                 */
@@ -779,6 +787,10 @@ get_elf_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
                                break;
                }
 
+               if ((int64_t)e_shoff < 0) {
+                       return (ARCHIVE_FATAL);
+               }
+
                /*
                 * Reading the section table to find strtab section
                 */
@@ -790,6 +802,9 @@ get_elf_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
                } else {
                        request = (size_t)e_shnum * e_shentsize + 0x18;
                }
+               if (request > SFX_MAX_SEEK) {
+                       return (ARCHIVE_FATAL);
+               }
                h = __archive_read_ahead(a, request, &bytes);
                if (h == NULL) {
                        return (ARCHIVE_FATAL);
@@ -805,8 +820,9 @@ get_elf_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
                        strtab_size = (*dec32)(
                            h + e_shstrndx * e_shentsize + 0x14);
                }
-               if (strtab_size < 6 || strtab_size > SIZE_MAX)
-                       break;
+               if ((int64_t)strtab_offset < 0 || strtab_size < 6 ||
+                   strtab_size > SFX_MAX_SEEK)
+                       return (ARCHIVE_FATAL);
 
                /*
                 * Read the STRTAB section to find the .data offset