summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/squashfs-tools/squashfs-tools/squashfs-4.2-fix-CVE-2012-4025.patch
blob: a5cdecf95b47da099c034d6257f6a49fec965337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
From fef997df2a1d6609af55e30eb67b65c786588fcb Mon Sep 17 00:00:00 2001
From: "yanjun.zhu" <yanjun.zhu@windriver.com>
Date: Wed, 20 May 2015 18:18:47 +0200
Subject: [PATCH 4/4] Fix CVE-2012-4025

Upstream-Status: Backport

Reference: https://github.com/plougher/squashfs-tools/commit/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>
Signed-off-by: Martin Jansa <martin.jansa@lge.com>
---
 squashfs-tools/squashfs_fs.h |   1 +
 squashfs-tools/unsquashfs.c  | 110 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 103 insertions(+), 8 deletions(-)

diff --git a/squashfs_fs.h b/squashfs_fs.h
index d4fba1b..6227be2 100644
--- a/squashfs_fs.h
+++ b/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
diff --git a/unsquashfs.c b/unsquashfs.c
index 4fc04e8..078d6ca 100644
--- a/unsquashfs.c
+++ b/unsquashfs.c
@@ -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_buffer_size, int data_buffer_size)
 	 * 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, long long max, int columns)
 }
 
 
+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);
-- 
2.1.4