--- 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;