libmdb: fixed potention NULL deref in mdb_is_reachable().
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Fri, 5 Dec 2014 18:38:15 +0000 (19:38 +0100)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Fri, 5 Dec 2014 18:38:15 +0000 (19:38 +0100)
lib/mdb/mdb_tree.c

index 2cc1fd5..bf8b3c5 100644 (file)
@@ -26,8 +26,7 @@
 #endif
 #define C(cte) (&(cte)->cap)
 
-// PP switch to change behaviour if invariants fail
-#ifdef MDB_FAIL_INVARIANTS
+// define panic() for user-land build
 #ifndef IN_KERNEL
 #define panic(msg...) \
     do { \
@@ -35,6 +34,9 @@
         abort(); \
     }while(0)
 #endif
+
+// PP switch to change behaviour if invariants fail
+#ifdef MDB_FAIL_INVARIANTS
 // on failure, dump mdb and terminate
 __attribute__((noreturn))
 static void
@@ -51,13 +53,15 @@ mdb_dump_and_fail(struct cte *cte, enum mdb_invariant failure)
 
 // PP switch to toggle top-level checking of invariants
 #ifdef MDB_CHECK_INVARIANTS
-#define CHECK_INVARIANTS(cte, assertion) \
+#define CHECK_INVARIANTS(root, cte, reach) \
 do { \
-    assert(assertion); \
+    if (mdb_is_reachable(root, cte) != reach) { \
+        panic("mdb_is_reachable(%p,%p) != %d", root, cte, reach); \
+    } \
     mdb_check_subtree_invariants(cte); \
 } while(0)
 #else
-#define CHECK_INVARIANTS(cte, assertion) ((void)0)
+#define CHECK_INVARIANTS(root, cte, reach) ((void)0)
 #endif
 
 // PP switch to toggle recursive checking of invariants by default
@@ -65,7 +69,12 @@ do { \
 // disable toplevel invariants checks except for the assertion clause as we're
 // doing them anyway in CHECK_INVARIANTS_SUB
 #undef CHECK_INVARIANTS
-#define CHECK_INVARIANTS(cte, assertion) assert(assertion)
+#define CHECK_INVARIANTS(root, cte, reach) \
+do { \
+    if (mdb_is_reachable(root, cte) != reach) { \
+        panic("mdb_is_reachable(%p,%p) != %d", root, cte, reach); \
+    } \
+} while(0)
 #define CHECK_INVARIANTS_SUB(cte) mdb_check_subtree_invariants(cte)
 #else
 #define CHECK_INVARIANTS_SUB(cte) ((void)0)
@@ -349,6 +358,9 @@ mdb_check_invariants(void)
 static bool
 mdb_is_reachable(struct cte *root, struct cte *cte)
 {
+    if (!root) {
+        return false;
+    }
     if (root == cte) {
         return true;
     }
@@ -597,7 +609,6 @@ errval_t
 mdb_insert(struct cte *new_node)
 {
     MDB_TRACE_ENTER(mdb_root, "%p", new_node);
-    CHECK_INVARIANTS(mdb_root, !mdb_is_reachable(mdb_root, new_node));
 #ifdef IN_KERNEL
 #ifdef MDB_TRACE_NO_RECURSIVE
     char prefix[50];
@@ -606,7 +617,7 @@ mdb_insert(struct cte *new_node)
 #endif
 #endif
     errval_t ret = mdb_sub_insert(new_node, &mdb_root);
-    CHECK_INVARIANTS(mdb_root, mdb_is_reachable(mdb_root, new_node));
+    CHECK_INVARIANTS(mdb_root, new_node, true);
     MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, ret, mdb_root);
 }
 
@@ -827,7 +838,7 @@ errval_t
 mdb_remove(struct cte *target)
 {
     MDB_TRACE_ENTER(mdb_root, "%p", target);
-    CHECK_INVARIANTS(mdb_root, mdb_is_reachable(mdb_root, target));
+    CHECK_INVARIANTS(mdb_root, target, true);
 #ifdef IN_KERNEL
 #ifdef MDB_TRACE_NO_RECURSIVE
     char prefix[50];
@@ -836,7 +847,7 @@ mdb_remove(struct cte *target)
 #endif
 #endif
     errval_t err = mdb_subtree_remove(target, &mdb_root, NULL);
-    CHECK_INVARIANTS(mdb_root, !mdb_is_reachable(mdb_root, target));
+    CHECK_INVARIANTS(mdb_root, target, false);
     MDB_TRACE_LEAVE_SUB_RET("%"PRIuPTR, err, mdb_root);
 }