]> wimlib.net Git - wimlib/commitdiff
Prevent huge memory allocations from fuzzed header fields
authorEric Biggers <ebiggers3@gmail.com>
Mon, 27 Mar 2023 00:25:46 +0000 (17:25 -0700)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 27 Mar 2023 00:25:46 +0000 (17:25 -0700)
include/wimlib/header.h
include/wimlib/wim.h
src/header.c
src/metadata_resource.c
src/wim.c

index 894bd22591897491f2089ce75c4bd0dacb64939f..7ef677369f9a039f8d44a96160dd94dca29e95e9 100644 (file)
@@ -112,7 +112,12 @@ struct wim_header_disk {
        /* +0xd0 (208)  */
 } _packed_attribute;
 
-#define MAX_IMAGES (((INT_MAX < INT32_MAX) ? INT_MAX : INT32_MAX) - 1)
+/*
+ * Arbitrarily limit the maximum number of images to 65535, to prevent huge
+ * memory allocations when processing fuzzed files.  This can be increased if
+ * ever needed (up to INT_MAX - 1).
+ */
+#define MAX_IMAGES     65535
 
 /* In-memory representation of a WIM header.  See `struct wim_header_disk' for
  * field descriptions.  */
index 67f55e3bb0ed24df599161cf7fd314ef01b80028..571d59cfb762e533acbf8323f0e4af0dba96aaca 100644 (file)
@@ -96,6 +96,9 @@ struct WIMStruct {
         * Otherwise, this field is invalid (!filedes_valid(&out_fd)).  */
        struct filedes out_fd;
 
+       /* The size of the backing file, or 0 if unknown */
+       u64 file_size;
+
        /*
         * This is the cached decompressor for this WIM file, or NULL if no
         * decompressor is cached yet.  Normally, all the compressed data in a
index cf19396317ca3af6da227c6b4b60d1bd180b4b06..3424edadf4d37394f760c0228b2d170bb7d246c9 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013, 2015 Eric Biggers
+ * Copyright 2012-2023 Eric Biggers
  *
  * This file is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the Free
@@ -144,6 +144,18 @@ read_wim_header(WIMStruct *wim, struct wim_header *hdr)
        get_wim_reshdr(&disk_hdr.boot_metadata_reshdr, &hdr->boot_metadata_reshdr);
        hdr->boot_idx = le32_to_cpu(disk_hdr.boot_idx);
        get_wim_reshdr(&disk_hdr.integrity_table_reshdr, &hdr->integrity_table_reshdr);
+
+       /*
+        * Prevent huge memory allocations when processing fuzzed files.  The
+        * blob table, XML data, and integrity table are all uncompressed, so
+        * they should never be larger than the WIM file itself.
+        */
+       if (wim->file_size > 0 &&
+           (hdr->blob_table_reshdr.uncompressed_size > wim->file_size ||
+            hdr->xml_data_reshdr.uncompressed_size > wim->file_size ||
+            hdr->integrity_table_reshdr.uncompressed_size > wim->file_size))
+               return WIMLIB_ERR_INVALID_HEADER;
+
        return 0;
 
 read_error:
index 19975e2e368921466aa9cd9eb9b648ad3f504850..e114ed28ce8f4c43ba002fc25c759e0b8c3dfefa 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013 Eric Biggers
+ * Copyright 2012-2023 Eric Biggers
  *
  * This file is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the Free
@@ -79,6 +79,18 @@ read_metadata_resource(struct wim_image_metadata *imd)
 
        metadata_blob = imd->metadata_blob;
 
+       /*
+        * Prevent huge memory allocations when processing fuzzed files.  The
+        * case of metadata resources is tough, since a metadata resource can
+        * legitimately decompress to many times the size of the WIM file
+        * itself, e.g. in the case of an image containing many empty files with
+        * similar long filenames.  Arbitrarily choose 512x as a generous limit.
+        */
+       if (metadata_blob->blob_location == BLOB_IN_WIM &&
+           metadata_blob->rdesc->wim->file_size > 0 &&
+           metadata_blob->size / 512 > metadata_blob->rdesc->wim->file_size)
+               return WIMLIB_ERR_INVALID_METADATA_RESOURCE;
+
        /* Read the metadata resource into memory.  (It may be compressed.)  */
        ret = read_blob_into_alloc_buf(metadata_blob, &buf);
        if (ret)
index 97125c4b10549769d65c2792040f4b6fb4f4e6ee..b143b0eab523964fb85cfaf2c319eedd7f187451 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (C) 2012-2016 Eric Biggers
+ * Copyright 2012-2023 Eric Biggers
  *
  * This file is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the Free
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "wimlib.h"
@@ -644,11 +645,17 @@ begin_read(WIMStruct *wim, const void *wim_filename_or_fd, int open_flags)
                filedes_init(&wim->in_fd, *(const int*)wim_filename_or_fd);
                wim->in_fd.is_pipe = 1;
        } else {
+               struct stat stbuf;
+
                wimfile = wim_filename_or_fd;
                ret = open_wim_file(wimfile, &wim->in_fd);
                if (ret)
                        return ret;
 
+               /* The file size is needed for enforcing some limits later. */
+               if (fstat(wim->in_fd.fd, &stbuf) == 0)
+                       wim->file_size = stbuf.st_size;
+
                /* The absolute path to the WIM is requested so that
                 * wimlib_overwrite() still works even if the process changes
                 * its working directory.  This actually happens if a WIM is