1 |
swegener 09/10/31 15:40:15 |
2 |
|
3 |
Added: systemtap-1.0-CVE-2009-2911-dwarf.patch |
4 |
systemtap-1.0-CVE-2009-2911-varargs.patch |
5 |
systemtap-1.0-CVE-2009-2911-unwind.patch |
6 |
Log: |
7 |
Revision bump, security bug #290218. |
8 |
(Portage version: 2.2_rc47/cvs/Linux x86_64) |
9 |
|
10 |
Revision Changes Path |
11 |
1.1 dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-dwarf.patch |
12 |
|
13 |
file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-dwarf.patch?rev=1.1&view=markup |
14 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-dwarf.patch?rev=1.1&content-type=text/plain |
15 |
|
16 |
Index: systemtap-1.0-CVE-2009-2911-dwarf.patch |
17 |
=================================================================== |
18 |
https://bugzilla.redhat.com/show_bug.cgi?id=529175 |
19 |
https://bugzilla.redhat.com/attachment.cgi?id=365294 |
20 |
|
21 |
diff --git a/dwflpp.cxx b/dwflpp.cxx |
22 |
index 636cd38..c31548d 100644 |
23 |
--- a/dwflpp.cxx |
24 |
+++ b/dwflpp.cxx |
25 |
@@ -2272,7 +2272,15 @@ dwflpp::express_as_string (string prelude, |
26 |
|
27 |
fprintf(memstream, "{\n"); |
28 |
fprintf(memstream, "%s", prelude.c_str()); |
29 |
- bool deref = c_emit_location (memstream, head, 1); |
30 |
+ |
31 |
+ unsigned int stack_depth; |
32 |
+ bool deref = c_emit_location (memstream, head, 1, &stack_depth); |
33 |
+ |
34 |
+ // Ensure that DWARF keeps loc2c to a "reasonable" stack size |
35 |
+ // 32 intptr_t leads to max 256 bytes on the stack |
36 |
+ if (stack_depth > 32) |
37 |
+ throw semantic_error("oversized DWARF stack"); |
38 |
+ |
39 |
fprintf(memstream, "%s", postlude.c_str()); |
40 |
fprintf(memstream, " goto out;\n"); |
41 |
|
42 |
diff --git a/loc2c-test.c b/loc2c-test.c |
43 |
index 495a95f..ed7aa4b 100644 |
44 |
--- a/loc2c-test.c |
45 |
+++ b/loc2c-test.c |
46 |
@@ -329,11 +329,14 @@ handle_variable (Dwarf_Die *lscopes, int lnscopes, int out, |
47 |
"{\n" |
48 |
" intptr_t value;"); |
49 |
|
50 |
- bool deref = c_emit_location (stdout, head, 1); |
51 |
+ unsigned int stack_depth; |
52 |
+ bool deref = c_emit_location (stdout, head, 1, &stack_depth); |
53 |
|
54 |
obstack_free (&pool, NULL); |
55 |
|
56 |
- puts (store ? " return;" : |
57 |
+ printf (" /* max expression stack depth %u */\n", stack_depth); |
58 |
+ |
59 |
+ puts (store ? " return;" : |
60 |
" printk (\" ---> %ld\\n\", (unsigned long) value);\n" |
61 |
" return;"); |
62 |
|
63 |
diff --git a/loc2c.c b/loc2c.c |
64 |
index 5d6b549..0716c7d 100644 |
65 |
--- a/loc2c.c |
66 |
+++ b/loc2c.c |
67 |
@@ -2071,7 +2071,8 @@ emit_loc_address (FILE *out, struct location *loc, unsigned int indent, |
68 |
assign it to an address-sized value. */ |
69 |
static void |
70 |
emit_loc_value (FILE *out, struct location *loc, unsigned int indent, |
71 |
- const char *target, bool declare) |
72 |
+ const char *target, bool declare, |
73 |
+ bool *used_deref, unsigned int *max_stack) |
74 |
{ |
75 |
if (declare) |
76 |
emit ("%*s%s %s;\n", indent * 2, "", STACK_TYPE, target); |
77 |
@@ -2091,6 +2092,9 @@ emit_loc_value (FILE *out, struct location *loc, unsigned int indent, |
78 |
case loc_address: |
79 |
case loc_value: |
80 |
emit_loc_address (out, loc, indent, target); |
81 |
+ *used_deref = *used_deref || loc->address.used_deref; |
82 |
+ if (loc->address.stack_depth > *max_stack) |
83 |
+ *max_stack = loc->address.stack_depth; |
84 |
break; |
85 |
} |
86 |
|
87 |
@@ -2098,7 +2102,8 @@ emit_loc_value (FILE *out, struct location *loc, unsigned int indent, |
88 |
} |
89 |
|
90 |
bool |
91 |
-c_emit_location (FILE *out, struct location *loc, int indent) |
92 |
+c_emit_location (FILE *out, struct location *loc, int indent, |
93 |
+ unsigned int *max_stack) |
94 |
{ |
95 |
emit ("%*s{\n", indent * 2, ""); |
96 |
|
97 |
@@ -2134,9 +2139,11 @@ c_emit_location (FILE *out, struct location *loc, int indent) |
98 |
} |
99 |
|
100 |
bool deref = false; |
101 |
+ *max_stack = 0; |
102 |
|
103 |
if (loc->frame_base != NULL) |
104 |
- emit_loc_value (out, loc->frame_base, indent, "frame_base", true); |
105 |
+ emit_loc_value (out, loc->frame_base, indent, "frame_base", true, |
106 |
+ &deref, max_stack); |
107 |
|
108 |
for (; loc->next != NULL; loc = loc->next) |
109 |
switch (loc->type) |
110 |
@@ -2144,8 +2151,7 @@ c_emit_location (FILE *out, struct location *loc, int indent) |
111 |
case loc_address: |
112 |
case loc_value: |
113 |
/* Emit the program fragment to calculate the address. */ |
114 |
- emit_loc_value (out, loc, indent + 1, "addr", false); |
115 |
- deref = deref || loc->address.used_deref; |
116 |
+ emit_loc_value (out, loc, indent + 1, "addr", false, &deref, max_stack); |
117 |
break; |
118 |
|
119 |
case loc_fragment: |
120 |
@@ -2172,6 +2178,9 @@ c_emit_location (FILE *out, struct location *loc, int indent) |
121 |
|
122 |
emit ("%s%*s}\n", loc->address.program, indent * 2, ""); |
123 |
|
124 |
+ if (loc->address.stack_depth > *max_stack) |
125 |
+ *max_stack = loc->address.stack_depth; |
126 |
+ |
127 |
return deref || loc->address.used_deref; |
128 |
} |
129 |
|
130 |
diff --git a/loc2c.h b/loc2c.h |
131 |
index becf2d8..45d9382 100644 |
132 |
--- a/loc2c.h |
133 |
+++ b/loc2c.h |
134 |
@@ -112,6 +112,7 @@ struct location *c_translate_argument (struct obstack *, |
135 |
|
136 |
Writes complete lines of C99, code forming a complete C block, to STREAM. |
137 |
Return value is true iff that code uses the `deref' runtime macros. */ |
138 |
-bool c_emit_location (FILE *stream, struct location *loc, int indent); |
139 |
+bool c_emit_location (FILE *stream, struct location *loc, int indent, |
140 |
+ unsigned int *max_stack); |
141 |
|
142 |
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |
143 |
|
144 |
|
145 |
|
146 |
1.1 dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-varargs.patch |
147 |
|
148 |
file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-varargs.patch?rev=1.1&view=markup |
149 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-varargs.patch?rev=1.1&content-type=text/plain |
150 |
|
151 |
Index: systemtap-1.0-CVE-2009-2911-varargs.patch |
152 |
=================================================================== |
153 |
https://bugzilla.redhat.com/show_bug.cgi?id=529175 |
154 |
https://bugzilla.redhat.com/attachment.cgi?id=365293 |
155 |
|
156 |
diff --git a/buildrun.cxx b/buildrun.cxx |
157 |
index 100cbc4..c86a442 100644 |
158 |
--- a/buildrun.cxx |
159 |
+++ b/buildrun.cxx |
160 |
@@ -200,6 +200,9 @@ compile_pass (systemtap_session& s) |
161 |
|
162 |
// o << "CFLAGS += -fno-unit-at-a-time" << endl; |
163 |
|
164 |
+ // 512 bytes should be enough for anybody |
165 |
+ o << "EXTRA_CFLAGS += $(call cc-option,-Wframe-larger-than=512)" << endl; |
166 |
+ |
167 |
// Assumes linux 2.6 kbuild |
168 |
o << "EXTRA_CFLAGS += -Wno-unused -Werror" << endl; |
169 |
#if CHECK_POINTER_ARITH_PR5947 |
170 |
diff --git a/testsuite/transko/varargs.stp b/testsuite/transko/varargs.stp |
171 |
new file mode 100755 |
172 |
index 0000000..f38309a |
173 |
--- /dev/null |
174 |
+++ b/testsuite/transko/varargs.stp |
175 |
@@ -0,0 +1,10 @@ |
176 |
+#! stap -p3 |
177 |
+ |
178 |
+probe begin { |
179 |
+ // PR10750 enforces at most 32 print args |
180 |
+ println(1, 2, 3, 4, 5, 6, 7, 8, |
181 |
+ 9, 10, 11, 12, 13, 14, 15, 16, |
182 |
+ 17, 18, 19, 20, 21, 22, 23, 24, |
183 |
+ 25, 26, 27, 28, 29, 30, 31, 32, |
184 |
+ 33) |
185 |
+} |
186 |
diff --git a/testsuite/transok/varargs.stp b/testsuite/transok/varargs.stp |
187 |
new file mode 100755 |
188 |
index 0000000..216166f |
189 |
--- /dev/null |
190 |
+++ b/testsuite/transok/varargs.stp |
191 |
@@ -0,0 +1,9 @@ |
192 |
+#! stap -p3 |
193 |
+ |
194 |
+probe begin { |
195 |
+ // PR10750 enforces at most 32 print args |
196 |
+ println(1, 2, 3, 4, 5, 6, 7, 8, |
197 |
+ 9, 10, 11, 12, 13, 14, 15, 16, |
198 |
+ 17, 18, 19, 20, 21, 22, 23, 24, |
199 |
+ 25, 26, 27, 28, 29, 30, 31, 32) |
200 |
+} |
201 |
diff --git a/translate.cxx b/translate.cxx |
202 |
index 04a9247..c73a5bd 100644 |
203 |
--- a/translate.cxx |
204 |
+++ b/translate.cxx |
205 |
@@ -4151,6 +4151,11 @@ c_unparser::visit_print_format (print_format* e) |
206 |
{ |
207 |
stmt_expr block(*this); |
208 |
|
209 |
+ // PR10750: Enforce a reasonable limit on # of varargs |
210 |
+ // 32 varargs leads to max 256 bytes on the stack |
211 |
+ if (e->args.size() > 32) |
212 |
+ throw semantic_error("too many arguments to print", e->tok); |
213 |
+ |
214 |
// Compute actual arguments |
215 |
vector<tmpvar> tmp; |
216 |
|
217 |
|
218 |
|
219 |
|
220 |
1.1 dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-unwind.patch |
221 |
|
222 |
file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-unwind.patch?rev=1.1&view=markup |
223 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/dev-util/systemtap/files/systemtap-1.0-CVE-2009-2911-unwind.patch?rev=1.1&content-type=text/plain |
224 |
|
225 |
Index: systemtap-1.0-CVE-2009-2911-unwind.patch |
226 |
=================================================================== |
227 |
https://bugzilla.redhat.com/show_bug.cgi?id=529175 |
228 |
https://bugzilla.redhat.com/attachment.cgi?id=365413 |
229 |
|
230 |
diff --git a/runtime/unwind.c b/runtime/unwind.c |
231 |
index 00108a3..7607770 100644 |
232 |
--- a/runtime/unwind.c |
233 |
+++ b/runtime/unwind.c |
234 |
@@ -88,7 +88,7 @@ static sleb128_t get_sleb128(const u8 **pcur, const u8 *end) |
235 |
|
236 |
/* given an FDE, find its CIE */ |
237 |
static const u32 *cie_for_fde(const u32 *fde, void *unwind_data, |
238 |
- int is_ehframe) |
239 |
+ uint32_t table_len, int is_ehframe) |
240 |
{ |
241 |
const u32 *cie; |
242 |
|
243 |
@@ -118,6 +118,11 @@ static const u32 *cie_for_fde(const u32 *fde, void *unwind_data, |
244 |
else |
245 |
cie = unwind_data + fde[1]; |
246 |
|
247 |
+ /* Make sure address falls in the table */ |
248 |
+ if (((void *)cie) < ((void*)unwind_data) |
249 |
+ || ((void*)cie) > ((void*)(unwind_data + table_len))) |
250 |
+ return NULL; |
251 |
+ |
252 |
if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde) |
253 |
|| (*cie & (sizeof(*cie) - 1)) |
254 |
|| (cie[1] != 0xffffffff && cie[1] != 0)) { |
255 |
@@ -200,7 +205,8 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy |
256 |
return value; |
257 |
} |
258 |
|
259 |
-static signed fde_pointer_type(const u32 *cie) |
260 |
+static signed fde_pointer_type(const u32 *cie, void *unwind_data, |
261 |
+ uint32_t table_len) |
262 |
{ |
263 |
const u8 *ptr = (const u8 *)(cie + 2); |
264 |
unsigned version = *ptr; |
265 |
@@ -212,11 +218,16 @@ static signed fde_pointer_type(const u32 *cie) |
266 |
const u8 *end = (const u8 *)(cie + 1) + *cie; |
267 |
uleb128_t len; |
268 |
|
269 |
+ /* end of cie should fall within unwind table. */ |
270 |
+ if (((void*)end) < ((void *)unwind_data) |
271 |
+ || ((void *)end) > ((void *)(unwind_data + table_len))) |
272 |
+ return -1; |
273 |
+ |
274 |
/* check if augmentation size is first (and thus present) */ |
275 |
if (*ptr != 'z') |
276 |
return -1; |
277 |
/* check if augmentation string is nul-terminated */ |
278 |
- if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL) |
279 |
+ if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL) |
280 |
return -1; |
281 |
++ptr; /* skip terminator */ |
282 |
get_uleb128(&ptr, end); /* skip code alignment */ |
283 |
@@ -267,6 +278,10 @@ static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value, s |
284 |
} |
285 |
} |
286 |
|
287 |
+/* Limit the number of instructions we process. Arbitrary limit. |
288 |
+ 512 should be enough for anybody... */ |
289 |
+#define MAX_CFI 512 |
290 |
+ |
291 |
static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, signed ptrType, struct unwind_state *state) |
292 |
{ |
293 |
union { |
294 |
@@ -276,6 +291,9 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s |
295 |
} ptr; |
296 |
int result = 1; |
297 |
|
298 |
+ if (end - start > MAX_CFI) |
299 |
+ return 0; |
300 |
+ |
301 |
dbug_unwind(1, "targetLoc=%lx state->loc=%lx\n", targetLoc, state->loc); |
302 |
if (start != state->cieStart) { |
303 |
state->loc = state->org; |
304 |
@@ -606,10 +624,10 @@ static int unwind_frame(struct unwind_frame_info *frame, |
305 |
|
306 |
/* found the fde, now set startLoc and endLoc */ |
307 |
if (fde != NULL) { |
308 |
- cie = cie_for_fde(fde, table, is_ehframe); |
309 |
+ cie = cie_for_fde(fde, table, table_len, is_ehframe); |
310 |
if (likely(cie != NULL && cie != &bad_cie && cie != ¬_fde)) { |
311 |
ptr = (const u8 *)(fde + 2); |
312 |
- ptrType = fde_pointer_type(cie); |
313 |
+ ptrType = fde_pointer_type(cie, table, table_len); |
314 |
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType); |
315 |
startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe); |
316 |
|
317 |
@@ -632,12 +650,12 @@ static int unwind_frame(struct unwind_frame_info *frame, |
318 |
for (fde = table, tableSize = table_len; cie = NULL, tableSize > sizeof(*fde) |
319 |
&& tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { |
320 |
dbug_unwind(3, "fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize); |
321 |
- cie = cie_for_fde(fde, table, is_ehframe); |
322 |
+ cie = cie_for_fde(fde, table, table_len, is_ehframe); |
323 |
if (cie == &bad_cie) { |
324 |
cie = NULL; |
325 |
break; |
326 |
} |
327 |
- if (cie == NULL || cie == ¬_fde || (ptrType = fde_pointer_type(cie)) < 0) |
328 |
+ if (cie == NULL || cie == ¬_fde || (ptrType = fde_pointer_type(cie, table, table_len)) < 0) |
329 |
continue; |
330 |
|
331 |
ptr = (const u8 *)(fde + 2); |
332 |
@@ -666,6 +684,12 @@ static int unwind_frame(struct unwind_frame_info *frame, |
333 |
state.cieEnd = ptr; /* keep here temporarily */ |
334 |
ptr = (const u8 *)(cie + 2); |
335 |
end = (const u8 *)(cie + 1) + *cie; |
336 |
+ |
337 |
+ /* end should fall within unwind table. */ |
338 |
+ if (((void *)end) < table |
339 |
+ || ((void *)end) > ((void *)(table + table_len))) |
340 |
+ goto err; |
341 |
+ |
342 |
frame->call_frame = 1; |
343 |
if ((state.version = *ptr) != 1) { |
344 |
dbug_unwind(1, "CIE version number is %d. 1 is supported.\n", state.version); |
345 |
@@ -723,6 +747,11 @@ static int unwind_frame(struct unwind_frame_info *frame, |
346 |
state.cieEnd = end; |
347 |
end = (const u8 *)(fde + 1) + *fde; |
348 |
|
349 |
+ /* end should fall within unwind table. */ |
350 |
+ if (((void*)end) < table |
351 |
+ || ((void *)end) > ((void *)(table + table_len))) |
352 |
+ goto err; |
353 |
+ |
354 |
/* skip augmentation */ |
355 |
if (((const char *)(cie + 2))[1] == 'z') { |
356 |
uleb128_t augSize = get_uleb128(&ptr, end); |
357 |
diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h |
358 |
index 285a3a3..023ea60 100644 |
359 |
--- a/runtime/unwind/unwind.h |
360 |
+++ b/runtime/unwind/unwind.h |
361 |
@@ -143,8 +143,10 @@ static unsigned long read_pointer(const u8 **pLoc, |
362 |
const void *end, |
363 |
signed ptrType); |
364 |
static const u32 bad_cie, not_fde; |
365 |
-static const u32 *cie_for_fde(const u32 *fde, void *table, int is_ehframe); |
366 |
-static signed fde_pointer_type(const u32 *cie); |
367 |
+static const u32 *cie_for_fde(const u32 *fde, void *table, |
368 |
+ uint32_t table_len, int is_ehframe); |
369 |
+static signed fde_pointer_type(const u32 *cie, |
370 |
+ void *table, uint32_t table_len); |
371 |
|
372 |
|
373 |
#endif /* STP_USE_DWARF_UNWINDER */ |
374 |
diff --git a/translate.cxx b/translate.cxx |
375 |
index bc5d615..9d456bc 100644 |
376 |
--- a/translate.cxx |
377 |
+++ b/translate.cxx |
378 |
@@ -29,6 +29,11 @@ extern "C" { |
379 |
#include <elfutils/libdwfl.h> |
380 |
} |
381 |
|
382 |
+// Max unwind table size (debug or eh) per module. Somewhat arbitrary |
383 |
+// limit (a bit more than twice the .debug_frame size of my local |
384 |
+// vmlinux for 2.6.31.4-83.fc12.x86_64) |
385 |
+#define MAX_UNWIND_TABLE_SIZE (3 * 1024 * 1024) |
386 |
+ |
387 |
using namespace std; |
388 |
|
389 |
struct var; |
390 |
@@ -4785,6 +4790,9 @@ dump_unwindsyms (Dwfl_Module *m, |
391 |
get_unwind_data (m, &debug_frame, &eh_frame, &debug_len, &eh_len, &eh_addr); |
392 |
if (debug_frame != NULL && debug_len > 0) |
393 |
{ |
394 |
+ if (debug_len > MAX_UNWIND_TABLE_SIZE) |
395 |
+ throw semantic_error ("module debug unwind table size too big"); |
396 |
+ |
397 |
c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; |
398 |
c->output << "static uint8_t _stp_module_" << stpmod_idx |
399 |
<< "_debug_frame[] = \n"; |
400 |
@@ -4802,6 +4810,9 @@ dump_unwindsyms (Dwfl_Module *m, |
401 |
|
402 |
if (eh_frame != NULL && eh_len > 0) |
403 |
{ |
404 |
+ if (eh_len > MAX_UNWIND_TABLE_SIZE) |
405 |
+ throw semantic_error ("module eh unwind table size too big"); |
406 |
+ |
407 |
c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n"; |
408 |
c->output << "static uint8_t _stp_module_" << stpmod_idx |
409 |
<< "_eh_frame[] = \n"; |