From: Jan Lieskovsky Subject: Three SystemTap-1.0 denial of service issues References: CVE-2009-2911, BNC#548361 Upstream: yes Three denial of service flaws were found in the SystemTap instrumentation system of version 1.0, when the --unprivileged mode was activated: b, Kernel stack frame overflow allows local attackers to cause denial of service via specially-crafted user-provided DWARF information. diff --git a/dwflpp.cxx b/dwflpp.cxx index 636cd38..c31548d 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -2272,7 +2272,15 @@ dwflpp::express_as_string (string prelude, fprintf(memstream, "{\n"); fprintf(memstream, "%s", prelude.c_str()); - bool deref = c_emit_location (memstream, head, 1); + + unsigned int stack_depth; + bool deref = c_emit_location (memstream, head, 1, &stack_depth); + + // Ensure that DWARF keeps loc2c to a "reasonable" stack size + // 32 intptr_t leads to max 256 bytes on the stack + if (stack_depth > 32) + throw semantic_error("oversized DWARF stack"); + fprintf(memstream, "%s", postlude.c_str()); fprintf(memstream, " goto out;\n"); diff --git a/loc2c-test.c b/loc2c-test.c index 495a95f..ed7aa4b 100644 --- a/loc2c-test.c +++ b/loc2c-test.c @@ -329,11 +329,14 @@ handle_variable (Dwarf_Die *lscopes, int lnscopes, int out, "{\n" " intptr_t value;"); - bool deref = c_emit_location (stdout, head, 1); + unsigned int stack_depth; + bool deref = c_emit_location (stdout, head, 1, &stack_depth); obstack_free (&pool, NULL); - puts (store ? " return;" : + printf (" /* max expression stack depth %u */\n", stack_depth); + + puts (store ? " return;" : " printk (\" ---> %ld\\n\", (unsigned long) value);\n" " return;"); diff --git a/loc2c.c b/loc2c.c index 5d6b549..0716c7d 100644 --- a/loc2c.c +++ b/loc2c.c @@ -2071,7 +2071,8 @@ emit_loc_address (FILE *out, struct location *loc, unsigned int indent, assign it to an address-sized value. */ static void emit_loc_value (FILE *out, struct location *loc, unsigned int indent, - const char *target, bool declare) + const char *target, bool declare, + bool *used_deref, unsigned int *max_stack) { if (declare) emit ("%*s%s %s;\n", indent * 2, "", STACK_TYPE, target); @@ -2091,6 +2092,9 @@ emit_loc_value (FILE *out, struct location *loc, unsigned int indent, case loc_address: case loc_value: emit_loc_address (out, loc, indent, target); + *used_deref = *used_deref || loc->address.used_deref; + if (loc->address.stack_depth > *max_stack) + *max_stack = loc->address.stack_depth; break; } @@ -2098,7 +2102,8 @@ emit_loc_value (FILE *out, struct location *loc, unsigned int indent, } bool -c_emit_location (FILE *out, struct location *loc, int indent) +c_emit_location (FILE *out, struct location *loc, int indent, + unsigned int *max_stack) { emit ("%*s{\n", indent * 2, ""); @@ -2134,9 +2139,11 @@ c_emit_location (FILE *out, struct location *loc, int indent) } bool deref = false; + *max_stack = 0; if (loc->frame_base != NULL) - emit_loc_value (out, loc->frame_base, indent, "frame_base", true); + emit_loc_value (out, loc->frame_base, indent, "frame_base", true, + &deref, max_stack); for (; loc->next != NULL; loc = loc->next) switch (loc->type) @@ -2144,8 +2151,7 @@ c_emit_location (FILE *out, struct location *loc, int indent) case loc_address: case loc_value: /* Emit the program fragment to calculate the address. */ - emit_loc_value (out, loc, indent + 1, "addr", false); - deref = deref || loc->address.used_deref; + emit_loc_value (out, loc, indent + 1, "addr", false, &deref, max_stack); break; case loc_fragment: @@ -2172,6 +2178,9 @@ c_emit_location (FILE *out, struct location *loc, int indent) emit ("%s%*s}\n", loc->address.program, indent * 2, ""); + if (loc->address.stack_depth > *max_stack) + *max_stack = loc->address.stack_depth; + return deref || loc->address.used_deref; } diff --git a/loc2c.h b/loc2c.h index becf2d8..45d9382 100644 --- a/loc2c.h +++ b/loc2c.h @@ -112,6 +112,7 @@ struct location *c_translate_argument (struct obstack *, Writes complete lines of C99, code forming a complete C block, to STREAM. Return value is true iff that code uses the `deref' runtime macros. */ -bool c_emit_location (FILE *stream, struct location *loc, int indent); +bool c_emit_location (FILE *stream, struct location *loc, int indent, + unsigned int *max_stack); /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */