⬢ DragonFlyBSD Kernel Audit
DF-3254 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/hammer/hammer_dedup.c
+++ b/sys/vfs/hammer/hammer_dedup.c
@@ -60,14 +60,24 @@ hammer_ioc_dedup(hammer_transaction_t trans, hammer_inode_t ip,
 	error = hammer_btree_lookup(&cursor1);
 	if (error)
 		goto done_cursor;
+	/*
+	 * DF-3254: validate the data zone BEFORE dereferencing
+	 * data_offset -- extract_data() feeds the offset straight into
+	 * hammer_bread() (_hammer_bread KKASSERTs on zone 0 on INVARIANTS
+	 * kernels and does a raw-zone wild read on production ones).
+	 * Zone-check jumps for cursor1 go to done_cursor (cursor2 is not
+	 * initialized yet at this point).
+	 */
+	error = hammer_btree_extract_leaf(&cursor1);
+	if (error)
+		goto done_cursor;
+	if (!hammer_is_zone_data(cursor1.leaf->data_offset)) {
+		dedup->head.flags |= HAMMER_IOC_DEDUP_INVALID_ZONE;
+		goto done_cursor;
+	}
 	error = hammer_btree_extract_data(&cursor1);
 	if (error)
 		goto done_cursor;
 
 	/*
 	 * Cursor2, return an error -> candidate goes to pass2 list
@@ -78,6 +88,14 @@ hammer_ioc_dedup(hammer_transaction_t trans, hammer_inode_t ip,
 	error = hammer_btree_lookup(&cursor2);
 	if (error)
 		goto done_cursors;
+	error = hammer_btree_extract_leaf(&cursor2);
+	if (error)
+		goto done_cursors;
+	if (!hammer_is_zone_data(cursor2.leaf->data_offset)) {
+		dedup->head.flags |= HAMMER_IOC_DEDUP_INVALID_ZONE;
+		goto done_cursors;
+	}
 	error = hammer_btree_extract_data(&cursor2);
 	if (error)
 		goto done_cursors;