diff --git a/.gitignore b/.gitignore index 5270323..6806873 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ squashfs-4.1.tar.bz2 /squashfs-4.2-20101223.bz2 /squashfs-4.2-20101231.bz2 /squashfs4.2.tar.gz +/squashfs4.3.tar.gz diff --git a/buffer-issue.patch b/buffer-issue.patch deleted file mode 100644 index 4464e88..0000000 --- a/buffer-issue.patch +++ /dev/null @@ -1,261 +0,0 @@ -From: Phillip Lougher -Date: Sat, 24 Nov 2012 02:34:48 +0000 (+0000) -Subject: unsquashfs: fix CVE-2012-4025 -X-Git-Url: http://squashfs.git.sourceforge.net/git/gitweb.cgi?p=squashfs%2Fsquashfs;a=commitdiff_plain;h=8515b3d420f502c5c0236b86e2d6d7e3b23c190e;hp=19c38fba0be1ce949ab44310d7f49887576cc123 - -unsquashfs: fix CVE-2012-4025 - -Fix integer overflow exploit in queue_init() leading to heap overflow. - -This was a complex exploit to fix because analysis of the code showed -there were multiple ways this exploit could be triggered, in addition -to the exploit vector documented in the CVE. - -Exploit: - -Data_buffer_size and fragment_buffer_size are added together and -passed to the queue_init function defined as: - -struct queue *queue_init(int size) - -Unfortunately, data_buffer_size and fragment_buffer_size are ints, and -contain values supplied by the user. The addition of these values can -overflow, leading to a negative size passed to queue_init() - -In queue_init, space is allocated by - -queue->data = malloc(sizeof(void *) * (size + 1)); - -Given a sufficiently large negative size, (size + 1) * sizeof(void *) -can overflow leading to a small positive number, leading to a small -amount of buffer space being created. - -In queue_get, the read pointer is moved through the buffer space by - -queue->readp = (queue->readp + 1) % queue->size; - -The negative sign of size is ignored, leading to readp going beyond the -allocated buffer space. - -Analysis of exploit: - -The exploit above is subtle, and centres around passing a negative -number to queue_init() due to integer overflow. This exploit can be -fixed by adding a check for negative size passed into queue_init(). - -However, further analysis of the exploit shows it can be triggered much -more easily. Data_buffer_size and fragment_buffer_size added together -can produce a value less than MAX_INT, which when passed into -queue_init() is not negative. However, this less than MAX_INT value can -overflow in the malloc calculation when multipled by sizeof(void *), -leading to a small positive integer. This leads to the situation where -the buffer allocated is smaller than size, and subsequent heap overflow. - -Checking for a negative number in queue_init() is insufficient to -determine if overflow has or will occur. In fact any one time -"spot checks" on size is fraught with the problem it can fail to detect -previous overflow (i.e. previous overflow which has resulted in a small -positive number is impossible to distinguish from a valid small positive -number), and it cannot detect if overflow will occur later. - -Due to this the approach to the fix is to check every operation -performed on data_buffer_size, fragment_buffer_size and any values -derived from them. All calculations are checked for potential overflow -before they are performed. - -This has the following advantages: - -1. It allows the code to trap exactly where the overflow takes place, - leading to more descriptive error messages. - -2. It ensures overflow situations do not feed through to later - calculations making it more difficult to determine if overflow has - occurred. - -3. It ensures too large values for data and fragment buffer sizes are - correctly rejected even if they don't trigger the exploits. - -Signed-off-by: Phillip Lougher ---- - -diff --git a/squashfs-tools/squashfs_fs.h b/squashfs-tools/squashfs_fs.h -index d1dc987..58d31f4 100644 ---- squashfs-tools/squashfs_fs.h -+++ squashfs-tools/squashfs_fs.h -@@ -39,6 +39,7 @@ - #define SQUASHFS_FILE_LOG 17 - - #define SQUASHFS_FILE_MAX_SIZE 1048576 -+#define SQUASHFS_FILE_MAX_LOG 20 - - /* Max number of uids and gids */ - #define SQUASHFS_IDS 65536 ---- squashfs-tools/unsquashfs.c.buffer 2012-11-25 17:07:52.237809893 -0600 -+++ squashfs-tools/unsquashfs.c 2012-11-25 17:15:24.155246275 -0600 -@@ -31,6 +31,7 @@ - - #include - #include -+#include - - struct cache *fragment_cache, *data_cache; - struct queue *to_reader, *to_deflate, *to_writer, *from_writer; -@@ -136,6 +137,24 @@ - } - - -+int add_overflow(int a, int b) -+{ -+ return (INT_MAX - a) < b; -+} -+ -+ -+int shift_overflow(int a, int shift) -+{ -+ return (INT_MAX >> shift) < a; -+} -+ -+ -+int multiply_overflow(int a, int multiplier) -+{ -+ return (INT_MAX / multiplier) < a; -+} -+ -+ - struct queue *queue_init(int size) - { - struct queue *queue = malloc(sizeof(struct queue)); -@@ -143,6 +162,10 @@ - if(queue == NULL) - EXIT_UNSQUASH("Out of memory in queue_init\n"); - -+ if(add_overflow(size, 1) || -+ multiply_overflow(size + 1, sizeof(void *))) -+ EXIT_UNSQUASH("Size too large in queue_init\n"); -+ - queue->data = malloc(sizeof(void *) * (size + 1)); - if(queue->data == NULL) - EXIT_UNSQUASH("Out of memory in queue_init\n"); -@@ -1805,7 +1828,7 @@ - { - int i; - sigset_t sigmask, old_mask; -- int all_buffers_size = fragment_buffer_size + data_buffer_size; -+ int all_buffers_size; - - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGINT); -@@ -1841,6 +1864,15 @@ - EXIT_UNSQUASH("Out of memory allocating thread descriptors\n"); - deflator_thread = &thread[3]; - -+ if(add_overflow(fragment_buffer_size, data_buffer_size)) -+ EXIT_UNSQUASH("Data and fragment queues combined are" -+ " too large\n"); -+ -+ all_buffers_size = fragment_buffer_size + data_buffer_size; -+ -+ if(add_overflow(all_buffers_size, all_buffers_size)) -+ EXIT_UNSQUASH("Data and fragment queues combined are" -+ " too large\n"); - to_reader = queue_init(all_buffers_size); - to_deflate = queue_init(all_buffers_size); - to_writer = queue_init(1000); -@@ -1940,6 +1972,31 @@ - fflush(stdout); - } - -+int parse_number(char *arg, int *res) -+{ -+ char *b; -+ long number = strtol(arg, &b, 10); -+ -+ /* check for trailing junk after number */ -+ if(*b != '\0') -+ return 0; -+ -+ /* check for strtol underflow or overflow in conversion */ -+ if(number == LONG_MIN || number == LONG_MAX) -+ return 0; -+ -+ /* reject negative numbers as invalid */ -+ if(number < 0) -+ return 0; -+ -+ /* check if long result will overflow signed int */ -+ if(number > INT_MAX) -+ return 0; -+ -+ *res = number; -+ return 1; -+} -+ - - #define VERSION() \ - printf("unsquashfs version 4.2 (2011/02/28)\n");\ -@@ -2022,8 +2079,8 @@ - } else if(strcmp(argv[i], "-data-queue") == 0 || - strcmp(argv[i], "-da") == 0) { - if((++i == argc) || -- (data_buffer_size = strtol(argv[i], &b, -- 10), *b != '\0')) { -+ !parse_number(argv[i], -+ &data_buffer_size)) { - ERROR("%s: -data-queue missing or invalid " - "queue size\n", argv[0]); - exit(1); -@@ -2036,8 +2093,8 @@ - } else if(strcmp(argv[i], "-frag-queue") == 0 || - strcmp(argv[i], "-fr") == 0) { - if((++i == argc) || -- (fragment_buffer_size = strtol(argv[i], -- &b, 10), *b != '\0')) { -+ !parse_number(argv[i], -+ &fragment_buffer_size)) { - ERROR("%s: -frag-queue missing or invalid " - "queue size\n", argv[0]); - exit(1); -@@ -2161,8 +2218,41 @@ - block_size = sBlk.s.block_size; - block_log = sBlk.s.block_log; - -- fragment_buffer_size <<= 20 - block_log; -- data_buffer_size <<= 20 - block_log; -+ /* -+ * Sanity check block size and block log. -+ * -+ * Check they're within correct limits -+ */ -+ if(block_size > SQUASHFS_FILE_MAX_SIZE || -+ block_log > SQUASHFS_FILE_MAX_LOG) -+ EXIT_UNSQUASH("Block size or block_log too large." -+ " File system is corrupt.\n"); -+ -+ /* -+ * Check block_size and block_log match -+ */ -+ if(block_size != (1 << block_log)) -+ EXIT_UNSQUASH("Block size and block_log do not match." -+ " File system is corrupt.\n"); -+ -+ /* -+ * convert from queue size in Mbytes to queue size in -+ * blocks. -+ * -+ * In doing so, check that the user supplied values do not -+ * overflow a signed int -+ */ -+ if(shift_overflow(fragment_buffer_size, 20 - block_log)) -+ EXIT_UNSQUASH("Fragment queue size is too large\n"); -+ else -+ fragment_buffer_size <<= 20 - block_log; -+ -+ if(shift_overflow(data_buffer_size, 20 - block_log)) -+ EXIT_UNSQUASH("Data queue size is too large\n"); -+ else -+ data_buffer_size <<= 20 - block_log; -+ -+ - initialise_threads(fragment_buffer_size, data_buffer_size); - - fragment_data = malloc(block_size); diff --git a/path-issue.patch b/path-issue.patch deleted file mode 100644 index 7058241..0000000 --- a/path-issue.patch +++ /dev/null @@ -1,77 +0,0 @@ -From: Phillip Lougher -Date: Thu, 22 Nov 2012 04:58:39 +0000 (+0000) -Subject: unsquashfs: fix CVE-2012-4024 -X-Git-Url: http://squashfs.git.sourceforge.net/git/gitweb.cgi?p=squashfs%2Fsquashfs;a=commitdiff_plain;h=19c38fba0be1ce949ab44310d7f49887576cc123;hp=f7bbe5a202648b505879e2570672c012498f31fb - -unsquashfs: fix CVE-2012-4024 - -Fix potential stack overflow in get_component() where an individual -pathname component in an extract file (specified on the command line -or in an extract file) could exceed the 1024 byte sized targname -allocated on the stack. - -Fix by dynamically allocating targname rather than storing it as -a fixed size on the stack. - -Signed-off-by: Phillip Lougher ---- - -diff --git a/squashfs-tools/unsquashfs.c b/squashfs-tools/unsquashfs.c -index 90ed1c2..d9d1377 100644 ---- a/squashfs-tools/unsquashfs.c -+++ b/squashfs-tools/unsquashfs.c -@@ -1099,15 +1099,18 @@ void squashfs_closedir(struct dir *dir) - } - - --char *get_component(char *target, char *targname) -+char *get_component(char *target, char **targname) - { -+ char *start; -+ - while(*target == '/') - target ++; - -+ start = target; - while(*target != '/' && *target!= '\0') -- *targname ++ = *target ++; -+ target ++; - -- *targname = '\0'; -+ *targname = strndup(start, target - start); - - return target; - } -@@ -1133,12 +1136,12 @@ void free_path(struct pathname *paths) - - struct pathname *add_path(struct pathname *paths, char *target, char *alltarget) - { -- char targname[1024]; -+ char *targname; - int i, error; - - TRACE("add_path: adding \"%s\" extract file\n", target); - -- target = get_component(target, targname); -+ target = get_component(target, &targname); - - if(paths == NULL) { - paths = malloc(sizeof(struct pathname)); -@@ -1162,7 +1165,7 @@ struct pathname *add_path(struct pathname *paths, char *target, char *alltarget) - sizeof(struct path_entry)); - if(paths->name == NULL) - EXIT_UNSQUASH("Out of memory in add_path\n"); -- paths->name[i].name = strdup(targname); -+ paths->name[i].name = targname; - paths->name[i].paths = NULL; - if(use_regex) { - paths->name[i].preg = malloc(sizeof(regex_t)); -@@ -1195,6 +1198,8 @@ struct pathname *add_path(struct pathname *paths, char *target, char *alltarget) - /* - * existing matching entry - */ -+ free(targname); -+ - if(paths->name[i].paths == NULL) { - /* - * No sub-directory which means this is the leaf diff --git a/sources b/sources index df751a2..23b2973 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -1b7a781fb4cf8938842279bd3e8ee852 squashfs4.2.tar.gz +fc16dfed64a698fd66818e26e5f7b647 squashfs4.3.tar.gz diff --git a/squashfs-tools.spec b/squashfs-tools.spec index ac4fd28..687653b 100644 --- a/squashfs-tools.spec +++ b/squashfs-tools.spec @@ -1,31 +1,25 @@ Summary: Utility for the creation of squashfs filesystems Name: squashfs-tools -Version: 4.2 -Release: 5%{?dist} +Version: 4.3 +Release: 0.1.git0be606be%{?dist} License: GPLv2+ Group: System Environment/Base URL: http://squashfs.sourceforge.net/ +# For now I am using a prerelease version obtained by: +# git archive --remote git://squashfs.git.sourceforge.net/gitroot/squashfs/squashfs --format=tar --prefix=squashfs4.3/ fadb345ddcf81e2b0e8cc802dbae41260be606be | gzip > squashfs4.3.tar.gz Source0: http://downloads.sourceforge.net/squashfs/squashfs%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: zlib-devel BuildRequires: xz-devel BuildRequires: lzo-devel BuildRequires: libattr-devel -# Upstream commit 19c38fba0be1ce949ab44310d7f49887576cc123 (minus version -# date change that doesn't apply cleanly) -Patch0: path-issue.patch -# Upstream commit 8515b3d420f502c5c0236b86e2d6d7e3b23c190e -# Patch needed to be adjusted to fit with the 4.2 release -Patch1: buffer-issue.patch %description Squashfs is a highly compressed read-only filesystem for Linux. This package contains the utilities for manipulating squashfs filesystems. %prep -%setup -q -n squashfs4.2 -%patch0 -p1 -b .pathname -%patch1 -p0 -b .buffer +%setup -q -n squashfs%{version} %build pushd squashfs-tools @@ -47,6 +41,12 @@ rm -rf %{buildroot} %{_sbindir}/unsquashfs %changelog +* Sat Dec 01 2012 Bruno Wolff III - 4.3-0.1.git0be606be +- Pre-release of 4.3 to get early testing +- This update includes a bit of internal code infrastructure changes +- There are lots of fixes to better handle bad data +- The final release is expected sometime in December + * Sun Nov 25 2012 Bruno Wolff III - 4.2-5 - Backported fix for bz 842460 (CVE-2012-4025)