DragonFlyBSD Kernel Audit
DF-0776 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/hammer/hammer_ondisk.c b/sys/vfs/hammer/hammer_ondisk.c
--- a/sys/vfs/hammer/hammer_ondisk.c
+++ b/sys/vfs/hammer/hammer_ondisk.c
@@ -1323,6 +1323,31 @@
 				node->flags |= HAMMER_NODE_CRCGOOD;
 			}
 		}
+
+		/*
+		 * Validate B-Tree node type and element count.  These fields
+		 * are read from disk and used as loop/bcopy bounds against the
+		 * fixed-size elms[HAMMER_BTREE_LEAF_ELMS] array; without
+		 * validation a forged node (CRC32C is not crypto-secure) can
+		 * supply an out-of-range count, causing OOB reads/writes.
+		 * Reject the node the same way a bad CRC is rejected.
+		 */
+		if (isnew == 0 &&
+		    (node->flags & HAMMER_NODE_CRCBAD) == 0) {
+			int max_elms;
+
+			max_elms = hammer_node_max_elements(node->ondisk->type);
+			if (max_elms < 0 ||
+			    node->ondisk->count < 0 ||
+			    node->ondisk->count > max_elms) {
+				hdkprintf("B-TREE NODE @ %016jx BAD "
+				    "type=%d count=%d\n",
+				    (intmax_t)node->node_offset,
+				    node->ondisk->type,
+				    node->ondisk->count);
+				node->flags |= HAMMER_NODE_CRCBAD;
+			}
+		}
 	}
 	if (node->flags & HAMMER_NODE_CRCBAD) {
 		if (trans->flags & HAMMER_TRANSF_CRCDOM)
diff --git a/sys/vfs/hammer/hammer_cursor.c b/sys/vfs/hammer/hammer_cursor.c
--- a/sys/vfs/hammer/hammer_cursor.c
+++ b/sys/vfs/hammer/hammer_cursor.c
@@ -199,8 +199,8 @@
 	cursor->node = node;
 	if (error == 0)
 		error = hammer_load_cursor_parent(cursor, 0);
-	KKASSERT(error == 0);
-	/* if (error) hammer_done_cursor(cursor); */
+	if (error)
+		hammer_done_cursor(cursor);
 	return(error);
 }
 
diff --git a/sys/vfs/hammer/hammer_inode.c b/sys/vfs/hammer/hammer_inode.c
--- a/sys/vfs/hammer/hammer_inode.c
+++ b/sys/vfs/hammer/hammer_inode.c
@@ -496,7 +496,11 @@
 		else
 			cachep = &dip->cache[0];
 	}
-	hammer_init_cursor(trans, &cursor, cachep, NULL);
+	*errorp = hammer_init_cursor(trans, &cursor, cachep, NULL);
+	if (*errorp) {
+		hammer_free_inode(ip);
+		return NULL;
+	}
 	cursor.key_beg.localization = localization | HAMMER_LOCALIZE_INODE;
 	cursor.key_beg.obj_id = ip->obj_id;
 	cursor.key_beg.key = 0;