From 55564216b05d61a397d0fa7642d43cf5c799e934 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 26 Mar 2023 17:25:46 -0700 Subject: [PATCH] Prevent huge memory allocations from fuzzed header fields --- include/wimlib/header.h | 7 ++++++- include/wimlib/wim.h | 3 +++ src/header.c | 14 +++++++++++++- src/metadata_resource.c | 14 +++++++++++++- src/wim.c | 9 ++++++++- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/include/wimlib/header.h b/include/wimlib/header.h index 894bd225..7ef67736 100644 --- a/include/wimlib/header.h +++ b/include/wimlib/header.h @@ -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. */ diff --git a/include/wimlib/wim.h b/include/wimlib/wim.h index 67f55e3b..571d59cf 100644 --- a/include/wimlib/wim.h +++ b/include/wimlib/wim.h @@ -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 diff --git a/src/header.c b/src/header.c index cf193963..3424edad 100644 --- a/src/header.c +++ b/src/header.c @@ -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: diff --git a/src/metadata_resource.c b/src/metadata_resource.c index 19975e2e..e114ed28 100644 --- a/src/metadata_resource.c +++ b/src/metadata_resource.c @@ -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) diff --git a/src/wim.c b/src/wim.c index 97125c4b..b143b0ea 100644 --- 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 #include #include +#include #include #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 -- 2.43.0