mirror of
https://git.yoctoproject.org/poky
synced 2026-09-15 06:49:33 +02:00
squashfs: fix CVE-2012-4025
CQID:WIND00366813 Reference: http://squashfs.git.sourceforge.net/git/gitweb.cgi? p=squashfs/squashfs;a=patch;h=8515b3d420f502c5c0236b86e2d6d7e3b23c190e Integer overflow in the queue_init function in unsquashfs.c in unsquashfs in Squashfs 4.2 and earlier allows remote attackers to execute arbitrary code via a crafted block_log field in the superblock of a .sqsh file, leading to a heap-based buffer overflow. http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-4025 (From OE-Core rev: bb1611d4830bb7aff2371afdb2a77a4ca7298c7d) Signed-off-by: yanjun.zhu <yanjun.zhu@windriver.com> [YOCTO #3564] Signed-off-by: Saul Wold <sgw@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
f023d05898
commit
5b3ffcea5e
@@ -0,0 +1,190 @@
|
||||
Upstream-Status: Backport
|
||||
|
||||
Reference: http://squashfs.git.sourceforge.net/git/gitweb.cgi?
|
||||
p=squashfs/squashfs;a=patch;h=8515b3d420f502c5c0236b86e2d6d7e3b23c190e
|
||||
|
||||
Integer overflow in the queue_init function in unsquashfs.c in
|
||||
unsquashfs in Squashfs 4.2 and earlier allows remote attackers
|
||||
to execute arbitrary code via a crafted block_log field in the
|
||||
superblock of a .sqsh file, leading to a heap-based buffer overflow.
|
||||
|
||||
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-4025
|
||||
|
||||
Signed-off-by: yanjun.zhu <yanjun.zhu@windriver.com>
|
||||
|
||||
--- a/unsquashfs.c 2012-11-30 17:57:57.000000000 +0800
|
||||
+++ b/unsquashfs.c 2012-11-30 17:58:09.000000000 +0800
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
+#include <limits.h>
|
||||
|
||||
struct cache *fragment_cache, *data_cache;
|
||||
struct queue *to_reader, *to_deflate, *to_writer, *from_writer;
|
||||
@@ -138,6 +139,24 @@ void sigalrm_handler()
|
||||
}
|
||||
|
||||
|
||||
+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));
|
||||
@@ -145,6 +164,10 @@ struct queue *queue_init(int size)
|
||||
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");
|
||||
@@ -1948,13 +1971,30 @@ void initialise_threads(int fragment_buf
|
||||
* allocate to_reader, to_deflate and to_writer queues. Set based on
|
||||
* open file limit and cache size, unless open file limit is unlimited,
|
||||
* in which case set purely based on cache limits
|
||||
+ *
|
||||
+ * In doing so, check that the user supplied values do not overflow
|
||||
+ * a signed int
|
||||
*/
|
||||
if (max_files != -1) {
|
||||
+ if(add_overflow(data_buffer_size, max_files) ||
|
||||
+ add_overflow(data_buffer_size, max_files * 2))
|
||||
+ EXIT_UNSQUASH("Data queue size is too large\n");
|
||||
+
|
||||
to_reader = queue_init(max_files + data_buffer_size);
|
||||
to_deflate = queue_init(max_files + data_buffer_size);
|
||||
to_writer = queue_init(max_files * 2 + data_buffer_size);
|
||||
} else {
|
||||
- int all_buffers_size = fragment_buffer_size + data_buffer_size;
|
||||
+ int all_buffers_size;
|
||||
+
|
||||
+ 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);
|
||||
@@ -2059,6 +2099,32 @@ void progress_bar(long long current, lon
|
||||
}
|
||||
|
||||
|
||||
+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");\
|
||||
printf("copyright (C) 2011 Phillip Lougher "\
|
||||
@@ -2140,8 +2206,8 @@ int main(int argc, char *argv[])
|
||||
} 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);
|
||||
@@ -2154,8 +2220,8 @@ int main(int argc, char *argv[])
|
||||
} 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);
|
||||
@@ -2280,11 +2346,39 @@ options:
|
||||
block_log = sBlk.s.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
|
||||
+ * blocks.
|
||||
+ *
|
||||
+ * In doing so, check that the user supplied values do not
|
||||
+ * overflow a signed int
|
||||
*/
|
||||
- fragment_buffer_size <<= 20 - block_log;
|
||||
- data_buffer_size <<= 20 - block_log;
|
||||
+ 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);
|
||||
Reference in New Issue
Block a user