01651c963d
Copy from devel:tools/systemtap based on submit request 25953 from user jones_tony OBS-URL: https://build.opensuse.org/request/show/25953 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/systemtap?expand=0&rev=49
136 lines
4.5 KiB
Diff
136 lines
4.5 KiB
Diff
From: Jan Lieskovsky <jlieskov@redhat.com>
|
|
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 : */
|
|
|