systemtap/bz702687.patch

130 lines
3.7 KiB
Diff

commit fa2e3415185a28542d419a641ecd6cddd52e3cd9
Author: Mark Wielaard <mjw@redhat.com>
Date: Wed May 11 15:27:48 2011 -0400
CVE-2011-1781, CVE-2011-1769: correct DW_OP_{mod,div} division-by-zero bug
Probing a process with corrupted DWARF information, it has been
possible to create a kernel-side divison-by-zero. This fixes.
Handle DW_OP_div/mod divide by zero. DW_OP_mod should work unsigned.
* loc2c.c (translate): Use helper functions div_op and mod_op for
DW_OP_div and DW_OP_mod operands. Set used_deref = true.
* translate.cxx (translate_runtime): Emit STAP_MSG_LOC2C_03 define.
* runtime/loc2c-runtime.h: Define dwarf_div_op and dwarf_mod_op macros.
* runtime/unwind.c (compute_expr): Check for zero before executing
DW_OP_mod or DW_OP_div.
diff --git a/loc2c.c b/loc2c.c
index 331090c..5f0dd09 100644
--- a/loc2c.c
+++ b/loc2c.c
@@ -681,7 +681,6 @@ translate (struct location_context *ctx, int indent,
UNOP (abs, op_abs);
BINOP (and, &);
BINOP (minus, -);
- BINOP (mod, %);
BINOP (mul, *);
UNOP (neg, -);
UNOP (not, ~);
@@ -716,9 +715,21 @@ translate (struct location_context *ctx, int indent,
{
POP (b);
POP (a);
- push ("(%s) " STACKFMT " / (%s)" STACKFMT,
+ push ("dwarf_div_op((%s) " STACKFMT ", (%s) " STACKFMT ")",
stack_slot_type (loc, true), a,
stack_slot_type (loc, true), b);
+ used_deref = true;
+ break;
+ }
+
+ case DW_OP_mod:
+ {
+ POP (b);
+ POP (a);
+ push ("dwarf_mod_op((%s) " STACKFMT ", (%s) " STACKFMT ")",
+ stack_slot_type (loc, false), a,
+ stack_slot_type (loc, false), b);
+ used_deref = true;
break;
}
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h
index d511087..968045f 100644
--- a/runtime/loc2c-runtime.h
+++ b/runtime/loc2c-runtime.h
@@ -82,6 +82,28 @@
})
#endif
+/* dwarf_div_op and dwarf_mod_op do division and modulo operations catching any
+ divide by zero issues. When they detect div_by_zero they "fault"
+ by jumping to the (slightly misnamed) deref_fault label. */
+#define dwarf_div_op(a,b) ({ \
+ if (b == 0) { \
+ snprintf(c->error_buffer, sizeof(c->error_buffer), \
+ "divide by zero in DWARF operand (%s)", "DW_OP_div"); \
+ c->last_error = c->error_buffer; \
+ goto deref_fault; \
+ } \
+ a / b; \
+})
+#define dwarf_mod_op(a,b) ({ \
+ if (b == 0) { \
+ snprintf(c->error_buffer, sizeof(c->error_buffer), \
+ "divide by zero in DWARF operand (%s)", "DW_OP_mod"); \
+ c->last_error = c->error_buffer; \
+ goto deref_fault; \
+ } \
+ a % b; \
+})
+
/* PR 10601: user-space (user_regset) register access. */
#if defined(STAPCONF_REGSET)
#include <linux/regset.h>
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 3e56965..810d9eb 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -856,12 +856,26 @@ static int compute_expr(const u8 *expr, struct unwind_frame_info *frame,
BINOP(plus, +);
BINOP(minus, -);
BINOP(mul, *);
- BINOP(div, /);
- BINOP(mod, %);
BINOP(shl, <<);
BINOP(shra, >>);
#undef BINOP
+ case DW_OP_mod: {
+ unsigned long b = POP;
+ unsigned long a = POP;
+ if (b == 0)
+ goto divzero;
+ PUSH (a % b);
+ }
+
+ case DW_OP_div: {
+ long b = POP;
+ long a = POP;
+ if (b == 0)
+ goto divzero;
+ PUSH (a / b);
+ }
+
case DW_OP_shr: {
unsigned long b = POP;
unsigned long a = POP;
@@ -944,6 +958,9 @@ overflow:
underflow:
_stp_warn("DWARF expression stack underflow in CFI\n");
return 1;
+divzero:
+ _stp_warn("DWARF expression stack divide by zero in CFI\n");
+ return 1;
#undef NEED
#undef PUSH