]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
7zip: Fix NULL pointer dereference on non-zlib builds (#2193)
authorTobias Stoeckmann <stoeckmann@users.noreply.github.com>
Sat, 18 May 2024 04:43:47 +0000 (06:43 +0200)
committerGitHub <noreply@github.com>
Sat, 18 May 2024 04:43:47 +0000 (21:43 -0700)
If libarchive is built without zlib support, it is possible to trigger a
NULL pointer dereference with specially crafted 7zip files.

It takes multiple conditions to be able to reach the issue in crc32 and
all 7zip-specific ones are fixed with this PR.

libarchive/archive_crc32.h
libarchive/archive_read_support_format_7zip.c

index 98a4e2cf8f7f289cda7f3767f2c97096ab5d4860..d86a507ce78cae21d8c705572eac038acbe1ba99 100644 (file)
@@ -30,6 +30,8 @@
 #error This header is only to be used internally to libarchive.
 #endif
 
+#include <stddef.h>
+
 /*
  * When zlib is unavailable, we should still be able to validate
  * uncompressed zip archives.  That requires us to be able to compute
@@ -46,6 +48,9 @@ crc32(unsigned long crc, const void *_p, size_t len)
        static volatile int crc_tbl_inited = 0;
        static unsigned long crc_tbl[256];
 
+       if (_p == NULL)
+               return (0);
+
        if (!crc_tbl_inited) {
                for (b = 0; b < 256; ++b) {
                        crc2 = b;
index a59034f69884d373f96c3bcd83c9fd89cff919ba..13c4b071d4455ed550e988e50cb3ae2a3521f5d8 100644 (file)
@@ -2307,7 +2307,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
        usizes = ss->unpackSizes;
        for (i = 0; i < numFolders; i++) {
                unsigned pack;
-               uint64_t sum;
+               uint64_t size, sum;
 
                if (f[i].numUnpackStreams == 0)
                        continue;
@@ -2317,10 +2317,15 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
                        for (pack = 1; pack < f[i].numUnpackStreams; pack++) {
                                if (parse_7zip_uint64(a, usizes) < 0)
                                        return (-1);
+                               if (*usizes > UINT64_MAX - sum)
+                                       return (-1);
                                sum += *usizes++;
                        }
                }
-               *usizes++ = folder_uncompressed_size(&f[i]) - sum;
+               size = folder_uncompressed_size(&f[i]);
+               if (size < sum)
+                       return (-1);
+               *usizes++ = size - sum;
        }
 
        if (type == kSize) {
@@ -2414,6 +2419,8 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
                packPos = si->pi.pos;
                for (i = 0; i < si->pi.numPackStreams; i++) {
                        si->pi.positions[i] = packPos;
+                       if (packPos > UINT64_MAX - si->pi.sizes[i])
+                               return (-1);
                        packPos += si->pi.sizes[i];
                        if (packPos > zip->header_offset)
                                return (-1);
@@ -2435,6 +2442,10 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
                f = si->ci.folders;
                for (i = 0; i < si->ci.numFolders; i++) {
                        f[i].packIndex = packIndex;
+                       if (f[i].numPackedStreams > UINT32_MAX)
+                               return (-1);
+                       if (packIndex > UINT32_MAX - (uint32_t)f[i].numPackedStreams)
+                               return (-1);
                        packIndex += (uint32_t)f[i].numPackedStreams;
                        if (packIndex > si->pi.numPackStreams)
                                return (-1);
@@ -3141,7 +3152,7 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
                /* Copy mode. */
 
                *buff = __archive_read_ahead(a, minimum, &bytes_avail);
-               if (bytes_avail <= 0) {
+               if (*buff == NULL) {
                        archive_set_error(&a->archive,
                            ARCHIVE_ERRNO_FILE_FORMAT,
                            "Truncated 7-Zip file data");