summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryanjun.zhu <yanjun.zhu@windriver.com>2012-12-11 10:00:32 (GMT)
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-02-14 15:19:52 (GMT)
commit54dd30e514412198734e8ddf56fca98f078e4fc1 (patch)
tree694276392c93e48679ee1c945dcef4c2f12a56eb
parent19f39c5d069a556c9b1c9af82cd9edd92772c0c5 (diff)
downloadpoky-54dd30e514412198734e8ddf56fca98f078e4fc1.tar.gz
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: 4493173c1ab7a0528e0c74935a105e474521ed1c) 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>
-rw-r--r--meta/recipes-devtools/squashfs-tools/patches/squashfs-4.2-fix-CVE-2012-4025.patch190
-rw-r--r--meta/recipes-devtools/squashfs-tools/patches/squashfs-add-a-commment-and-fix-some-other-comments.patch38
-rw-r--r--meta/recipes-devtools/squashfs-tools/patches/squashfs-fix-open-file-limit.patch215
-rw-r--r--meta/recipes-devtools/squashfs-tools/squashfs-tools_4.2.bb5
4 files changed, 447 insertions, 1 deletions
diff --git a/meta/recipes-devtools/squashfs-tools/patches/squashfs-4.2-fix-CVE-2012-4025.patch b/meta/recipes-devtools/squashfs-tools/patches/squashfs-4.2-fix-CVE-2012-4025.patch
new file mode 100644
index 0000000..0dabfba
--- /dev/null
+++ b/meta/recipes-devtools/squashfs-tools/patches/squashfs-4.2-fix-CVE-2012-4025.patch
@@ -0,0 +1,190 @@
1Upstream-Status: Backport
2
3Reference: http://squashfs.git.sourceforge.net/git/gitweb.cgi?
4p=squashfs/squashfs;a=patch;h=8515b3d420f502c5c0236b86e2d6d7e3b23c190e
5
6Integer overflow in the queue_init function in unsquashfs.c in
7unsquashfs in Squashfs 4.2 and earlier allows remote attackers
8to execute arbitrary code via a crafted block_log field in the
9superblock of a .sqsh file, leading to a heap-based buffer overflow.
10
11http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-4025
12
13Signed-off-by: yanjun.zhu <yanjun.zhu@windriver.com>
14
15--- a/unsquashfs.c 2012-11-30 17:57:57.000000000 +0800
16+++ b/unsquashfs.c 2012-11-30 17:58:09.000000000 +0800
17@@ -33,6 +33,7 @@
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/resource.h>
21+#include <limits.h>
22
23 struct cache *fragment_cache, *data_cache;
24 struct queue *to_reader, *to_deflate, *to_writer, *from_writer;
25@@ -138,6 +139,24 @@ void sigalrm_handler()
26 }
27
28
29+int add_overflow(int a, int b)
30+{
31+ return (INT_MAX - a) < b;
32+}
33+
34+
35+int shift_overflow(int a, int shift)
36+{
37+ return (INT_MAX >> shift) < a;
38+}
39+
40+
41+int multiply_overflow(int a, int multiplier)
42+{
43+ return (INT_MAX / multiplier) < a;
44+}
45+
46+
47 struct queue *queue_init(int size)
48 {
49 struct queue *queue = malloc(sizeof(struct queue));
50@@ -145,6 +164,10 @@ struct queue *queue_init(int size)
51 if(queue == NULL)
52 EXIT_UNSQUASH("Out of memory in queue_init\n");
53
54+ if(add_overflow(size, 1) ||
55+ multiply_overflow(size + 1, sizeof(void *)))
56+ EXIT_UNSQUASH("Size too large in queue_init\n");
57+
58 queue->data = malloc(sizeof(void *) * (size + 1));
59 if(queue->data == NULL)
60 EXIT_UNSQUASH("Out of memory in queue_init\n");
61@@ -1948,13 +1971,30 @@ void initialise_threads(int fragment_buf
62 * allocate to_reader, to_deflate and to_writer queues. Set based on
63 * open file limit and cache size, unless open file limit is unlimited,
64 * in which case set purely based on cache limits
65+ *
66+ * In doing so, check that the user supplied values do not overflow
67+ * a signed int
68 */
69 if (max_files != -1) {
70+ if(add_overflow(data_buffer_size, max_files) ||
71+ add_overflow(data_buffer_size, max_files * 2))
72+ EXIT_UNSQUASH("Data queue size is too large\n");
73+
74 to_reader = queue_init(max_files + data_buffer_size);
75 to_deflate = queue_init(max_files + data_buffer_size);
76 to_writer = queue_init(max_files * 2 + data_buffer_size);
77 } else {
78- int all_buffers_size = fragment_buffer_size + data_buffer_size;
79+ int all_buffers_size;
80+
81+ if(add_overflow(fragment_buffer_size, data_buffer_size))
82+ EXIT_UNSQUASH("Data and fragment queues combined are"
83+ " too large\n");
84+
85+ all_buffers_size = fragment_buffer_size + data_buffer_size;
86+
87+ if(add_overflow(all_buffers_size, all_buffers_size))
88+ EXIT_UNSQUASH("Data and fragment queues combined are"
89+ " too large\n");
90
91 to_reader = queue_init(all_buffers_size);
92 to_deflate = queue_init(all_buffers_size);
93@@ -2059,6 +2099,32 @@ void progress_bar(long long current, lon
94 }
95
96
97+int parse_number(char *arg, int *res)
98+{
99+ char *b;
100+ long number = strtol(arg, &b, 10);
101+
102+ /* check for trailing junk after number */
103+ if(*b != '\0')
104+ return 0;
105+
106+ /* check for strtol underflow or overflow in conversion */
107+ if(number == LONG_MIN || number == LONG_MAX)
108+ return 0;
109+
110+ /* reject negative numbers as invalid */
111+ if(number < 0)
112+ return 0;
113+
114+ /* check if long result will overflow signed int */
115+ if(number > INT_MAX)
116+ return 0;
117+
118+ *res = number;
119+ return 1;
120+}
121+
122+
123 #define VERSION() \
124 printf("unsquashfs version 4.2 (2011/02/28)\n");\
125 printf("copyright (C) 2011 Phillip Lougher "\
126@@ -2140,8 +2206,8 @@ int main(int argc, char *argv[])
127 } else if(strcmp(argv[i], "-data-queue") == 0 ||
128 strcmp(argv[i], "-da") == 0) {
129 if((++i == argc) ||
130- (data_buffer_size = strtol(argv[i], &b,
131- 10), *b != '\0')) {
132+ !parse_number(argv[i],
133+ &data_buffer_size)) {
134 ERROR("%s: -data-queue missing or invalid "
135 "queue size\n", argv[0]);
136 exit(1);
137@@ -2154,8 +2220,8 @@ int main(int argc, char *argv[])
138 } else if(strcmp(argv[i], "-frag-queue") == 0 ||
139 strcmp(argv[i], "-fr") == 0) {
140 if((++i == argc) ||
141- (fragment_buffer_size = strtol(argv[i],
142- &b, 10), *b != '\0')) {
143+ !parse_number(argv[i],
144+ &fragment_buffer_size)) {
145 ERROR("%s: -frag-queue missing or invalid "
146 "queue size\n", argv[0]);
147 exit(1);
148@@ -2280,11 +2346,39 @@ options:
149 block_log = sBlk.s.block_log;
150
151 /*
152+ * Sanity check block size and block log.
153+ *
154+ * Check they're within correct limits
155+ */
156+ if(block_size > SQUASHFS_FILE_MAX_SIZE ||
157+ block_log > SQUASHFS_FILE_MAX_LOG)
158+ EXIT_UNSQUASH("Block size or block_log too large."
159+ " File system is corrupt.\n");
160+
161+ /*
162+ * Check block_size and block_log match
163+ */
164+ if(block_size != (1 << block_log))
165+ EXIT_UNSQUASH("Block size and block_log do not match."
166+ " File system is corrupt.\n");
167+
168+ /*
169 * convert from queue size in Mbytes to queue size in
170- * blocks
171+ * blocks.
172+ *
173+ * In doing so, check that the user supplied values do not
174+ * overflow a signed int
175 */
176- fragment_buffer_size <<= 20 - block_log;
177- data_buffer_size <<= 20 - block_log;
178+ if(shift_overflow(fragment_buffer_size, 20 - block_log))
179+ EXIT_UNSQUASH("Fragment queue size is too large\n");
180+ else
181+ fragment_buffer_size <<= 20 - block_log;
182+
183+ if(shift_overflow(data_buffer_size, 20 - block_log))
184+ EXIT_UNSQUASH("Data queue size is too large\n");
185+ else
186+ data_buffer_size <<= 20 - block_log;
187+
188 initialise_threads(fragment_buffer_size, data_buffer_size);
189
190 fragment_data = malloc(block_size);
diff --git a/meta/recipes-devtools/squashfs-tools/patches/squashfs-add-a-commment-and-fix-some-other-comments.patch b/meta/recipes-devtools/squashfs-tools/patches/squashfs-add-a-commment-and-fix-some-other-comments.patch
new file mode 100644
index 0000000..fa075f9
--- /dev/null
+++ b/meta/recipes-devtools/squashfs-tools/patches/squashfs-add-a-commment-and-fix-some-other-comments.patch
@@ -0,0 +1,38 @@
1Upstream-Status: Backport
2
3unsquashfs: add a commment and fix some other comments
4
5Signed-off-by: yanjun.zhu <yanjun.zhu@windriver.com>
6
7diff -urpN a/unsquashfs.c b/unsquashfs.c
8--- a/unsquashfs.c 2012-11-30 15:27:14.000000000 +0800
9+++ b/unsquashfs.c 2012-11-30 15:27:56.000000000 +0800
10@@ -814,7 +814,7 @@ int write_file(struct inode *inode, char
11
12 /*
13 * the writer thread is queued a squashfs_file structure describing the
14- * file. If the file has one or more blocks or a fragments they are
15+ * file. If the file has one or more blocks or a fragment they are
16 * queued separately (references to blocks in the cache).
17 */
18 file->fd = file_fd;
19@@ -838,7 +838,7 @@ int write_file(struct inode *inode, char
20 block->offset = 0;
21 block->size = i == file_end ? inode->data & (block_size - 1) :
22 block_size;
23- if(block_list[i] == 0) /* sparse file */
24+ if(block_list[i] == 0) /* sparse block */
25 block->buffer = NULL;
26 else {
27 block->buffer = cache_get(data_cache, start,
28@@ -2161,6 +2161,10 @@ options:
29 block_size = sBlk.s.block_size;
30 block_log = sBlk.s.block_log;
31
32+ /*
33+ * convert from queue size in Mbytes to queue size in
34+ * blocks
35+ */
36 fragment_buffer_size <<= 20 - block_log;
37 data_buffer_size <<= 20 - block_log;
38 initialise_threads(fragment_buffer_size, data_buffer_size);
diff --git a/meta/recipes-devtools/squashfs-tools/patches/squashfs-fix-open-file-limit.patch b/meta/recipes-devtools/squashfs-tools/patches/squashfs-fix-open-file-limit.patch
new file mode 100644
index 0000000..c60f7b4
--- /dev/null
+++ b/meta/recipes-devtools/squashfs-tools/patches/squashfs-fix-open-file-limit.patch
@@ -0,0 +1,215 @@
1Upstream-Status: Backport
2
3unsquashfs: fix open file limit
4
5Previously Unsquashfs relied on the to_writer queue being
6set to 1000 to limit the amount of open file read-ahead to a
7maximum of 500. For the default process limit of 1024 open files
8this was perhaps acceptable, but it obviously breaks if ulimit has
9been used to set the open file limit to below 504 (this includes
10stdin, stdout, stderr and the Squashfs filesystem being unsquashed).
11
12More importantly setting the to_writer queue to 1000 to limit
13the amount of files open has always been an inherent performance
14hit because the to_writer queue queues blocks. It limits the
15block readhead to 1000 blocks, irrespective of how many files
16that represents. A single file containing more than 1000 blocks
17will still be limited to a 1000 block readahead even though the
18data block cache typically can buffer more than this (at the
19default data cache size of 256 Mbytes and the default block size
20of 128 Kbytes, it can buffer 2048 blocks). Obviously the
21caches serve more than just a read-ahead role (they also
22cache decompressed blocks in case they're referenced later e.g.
23by duplicate files), but the artificial limit imposed on
24the read-ahead due to setting the to_writer queue to 1000 is
25unnecessary.
26
27This commit does away with the need to limit the to_writer queue,
28by introducing open_wait() and close_wake() calls which correctly
29track the amount of open files.
30
31Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
32
33Signed-off-by: yanjun.zhu <yanjun.zhu@windriver.com>
34
35diff -urpN a/unsquashfs.c b/unsquashfs.c
36--- a/unsquashfs.c 2012-11-30 15:31:29.000000000 +0800
37+++ b/unsquashfs.c 2012-11-30 15:32:03.000000000 +0800
38@@ -31,6 +31,8 @@
39
40 #include <sys/sysinfo.h>
41 #include <sys/types.h>
42+#include <sys/time.h>
43+#include <sys/resource.h>
44
45 struct cache *fragment_cache, *data_cache;
46 struct queue *to_reader, *to_deflate, *to_writer, *from_writer;
47@@ -784,6 +786,46 @@ failure:
48 }
49
50
51+pthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER;
52+pthread_cond_t open_empty = PTHREAD_COND_INITIALIZER;
53+int open_unlimited, open_count;
54+#define OPEN_FILE_MARGIN 10
55+
56+
57+void open_init(int count)
58+{
59+ open_count = count;
60+ open_unlimited = count == -1;
61+}
62+
63+
64+int open_wait(char *pathname, int flags, mode_t mode)
65+{
66+ if (!open_unlimited) {
67+ pthread_mutex_lock(&open_mutex);
68+ while (open_count == 0)
69+ pthread_cond_wait(&open_empty, &open_mutex);
70+ open_count --;
71+ pthread_mutex_unlock(&open_mutex);
72+ }
73+
74+ return open(pathname, flags, mode);
75+}
76+
77+
78+void close_wake(int fd)
79+{
80+ close(fd);
81+
82+ if (!open_unlimited) {
83+ pthread_mutex_lock(&open_mutex);
84+ open_count ++;
85+ pthread_cond_signal(&open_empty);
86+ pthread_mutex_unlock(&open_mutex);
87+ }
88+}
89+
90+
91 int write_file(struct inode *inode, char *pathname)
92 {
93 unsigned int file_fd, i;
94@@ -794,8 +836,8 @@ int write_file(struct inode *inode, char
95
96 TRACE("write_file: regular file, blocks %d\n", inode->blocks);
97
98- file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0),
99- (mode_t) inode->mode & 0777);
100+ file_fd = open_wait(pathname, O_CREAT | O_WRONLY |
101+ (force ? O_TRUNC : 0), (mode_t) inode->mode & 0777);
102 if(file_fd == -1) {
103 ERROR("write_file: failed to create file %s, because %s\n",
104 pathname, strerror(errno));
105@@ -1712,7 +1754,7 @@ void *writer(void *arg)
106 }
107 }
108
109- close(file_fd);
110+ close_wake(file_fd);
111 if(failed == FALSE)
112 set_attributes(file->pathname, file->mode, file->uid,
113 file->gid, file->time, file->xattr, force);
114@@ -1803,9 +1845,9 @@ void *progress_thread(void *arg)
115
116 void initialise_threads(int fragment_buffer_size, int data_buffer_size)
117 {
118- int i;
119+ struct rlimit rlim;
120+ int i, max_files, res;
121 sigset_t sigmask, old_mask;
122- int all_buffers_size = fragment_buffer_size + data_buffer_size;
123
124 sigemptyset(&sigmask);
125 sigaddset(&sigmask, SIGINT);
126@@ -1841,10 +1883,86 @@ void initialise_threads(int fragment_buf
127 EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
128 deflator_thread = &thread[3];
129
130- to_reader = queue_init(all_buffers_size);
131- to_deflate = queue_init(all_buffers_size);
132- to_writer = queue_init(1000);
133+ /*
134+ * dimensioning the to_reader and to_deflate queues. The size of
135+ * these queues is directly related to the amount of block
136+ * read-ahead possible. To_reader queues block read requests to
137+ * the reader thread and to_deflate queues block decompression
138+ * requests to the deflate thread(s) (once the block has been read by
139+ * the reader thread). The amount of read-ahead is determined by
140+ * the combined size of the data_block and fragment caches which
141+ * determine the total number of blocks which can be "in flight"
142+ * at any one time (either being read or being decompressed)
143+ *
144+ * The maximum file open limit, however, affects the read-ahead
145+ * possible, in that for normal sizes of the fragment and data block
146+ * caches, where the incoming files have few data blocks or one fragment
147+ * only, the file open limit is likely to be reached before the
148+ * caches are full. This means the worst case sizing of the combined
149+ * sizes of the caches is unlikely to ever be necessary. However, is is
150+ * obvious read-ahead up to the data block cache size is always possible
151+ * irrespective of the file open limit, because a single file could
152+ * contain that number of blocks.
153+ *
154+ * Choosing the size as "file open limit + data block cache size" seems
155+ * to be a reasonable estimate. We can reasonably assume the maximum
156+ * likely read-ahead possible is data block cache size + one fragment
157+ * per open file.
158+ *
159+ * dimensioning the to_writer queue. The size of this queue is
160+ * directly related to the amount of block read-ahead possible.
161+ * However, unlike the to_reader and to_deflate queues, this is
162+ * complicated by the fact the to_writer queue not only contains
163+ * entries for fragments and data_blocks but it also contains
164+ * file entries, one per open file in the read-ahead.
165+ *
166+ * Choosing the size as "2 * (file open limit) +
167+ * data block cache size" seems to be a reasonable estimate.
168+ * We can reasonably assume the maximum likely read-ahead possible
169+ * is data block cache size + one fragment per open file, and then
170+ * we will have a file_entry for each open file.
171+ */
172+ res = getrlimit(RLIMIT_NOFILE, &rlim);
173+ if (res == -1) {
174+ ERROR("failed to get open file limit! Defaulting to 1\n");
175+ rlim.rlim_cur = 1;
176+ }
177+
178+ if (rlim.rlim_cur != RLIM_INFINITY) {
179+ /*
180+ * leave OPEN_FILE_MARGIN free (rlim_cur includes fds used by
181+ * stdin, stdout, stderr and filesystem fd
182+ */
183+ if (rlim.rlim_cur <= OPEN_FILE_MARGIN)
184+ /* no margin, use minimum possible */
185+ max_files = 1;
186+ else
187+ max_files = rlim.rlim_cur - OPEN_FILE_MARGIN;
188+ } else
189+ max_files = -1;
190+
191+ /* set amount of available files for use by open_wait and close_wake */
192+ open_init(max_files);
193+
194+ /*
195+ * allocate to_reader, to_deflate and to_writer queues. Set based on
196+ * open file limit and cache size, unless open file limit is unlimited,
197+ * in which case set purely based on cache limits
198+ */
199+ if (max_files != -1) {
200+ to_reader = queue_init(max_files + data_buffer_size);
201+ to_deflate = queue_init(max_files + data_buffer_size);
202+ to_writer = queue_init(max_files * 2 + data_buffer_size);
203+ } else {
204+ int all_buffers_size = fragment_buffer_size + data_buffer_size;
205+
206+ to_reader = queue_init(all_buffers_size);
207+ to_deflate = queue_init(all_buffers_size);
208+ to_writer = queue_init(all_buffers_size * 2);
209+ }
210+
211 from_writer = queue_init(1);
212+
213 fragment_cache = cache_init(block_size, fragment_buffer_size);
214 data_cache = cache_init(block_size, data_buffer_size);
215 pthread_create(&thread[0], NULL, reader, NULL);
diff --git a/meta/recipes-devtools/squashfs-tools/squashfs-tools_4.2.bb b/meta/recipes-devtools/squashfs-tools/squashfs-tools_4.2.bb
index 9922f1e..528efed 100644
--- a/meta/recipes-devtools/squashfs-tools/squashfs-tools_4.2.bb
+++ b/meta/recipes-devtools/squashfs-tools/squashfs-tools_4.2.bb
@@ -8,12 +8,15 @@ LIC_FILES_CHKSUM = "file://../COPYING;md5=0636e73ff0215e8d672dc4c32c317bb3 \
8 file://../../7zC.txt;beginline=12;endline=16;md5=2056cd6d919ebc3807602143c7449a7c \ 8 file://../../7zC.txt;beginline=12;endline=16;md5=2056cd6d919ebc3807602143c7449a7c \
9 " 9 "
10DEPENDS = "attr zlib xz" 10DEPENDS = "attr zlib xz"
11PR = "1" 11PR = "r2"
12 12
13SRC_URI = "${SOURCEFORGE_MIRROR}/squashfs/squashfs${PV}.tar.gz;name=squashfs \ 13SRC_URI = "${SOURCEFORGE_MIRROR}/squashfs/squashfs${PV}.tar.gz;name=squashfs \
14 http://downloads.sourceforge.net/sevenzip/lzma465.tar.bz2;name=lzma \ 14 http://downloads.sourceforge.net/sevenzip/lzma465.tar.bz2;name=lzma \
15 " 15 "
16SRC_URI += "file://squashfs-4.2-fix-CVE-2012-4024.patch \ 16SRC_URI += "file://squashfs-4.2-fix-CVE-2012-4024.patch \
17 file://squashfs-add-a-commment-and-fix-some-other-comments.patch \
18 file://squashfs-fix-open-file-limit.patch \
19 file://squashfs-4.2-fix-CVE-2012-4025.patch \
17 " 20 "
18SRC_URI[squashfs.md5sum] = "1b7a781fb4cf8938842279bd3e8ee852" 21SRC_URI[squashfs.md5sum] = "1b7a781fb4cf8938842279bd3e8ee852"
19SRC_URI[squashfs.sha256sum] = "d9e0195aa922dbb665ed322b9aaa96e04a476ee650f39bbeadb0d00b24022e96" 22SRC_URI[squashfs.sha256sum] = "d9e0195aa922dbb665ed322b9aaa96e04a476ee650f39bbeadb0d00b24022e96"