Sophie

Sophie

distrib > Fedora > 13 > i386 > by-pkgid > 86eb187d4659495187eef81f79ec0e8f > files > 1

systemtap-1.4-6.fc13.src.rpm

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