Skip to content

Commit 3ae93b3

Browse files
adam900710gregkh
authored andcommitted
btrfs: reject invalid reloc tree root keys with stack dump
commit 6ebcd02 upstream. [BUG] Syzbot reported a crash that an ASSERT() got triggered inside prepare_to_merge(). That ASSERT() makes sure the reloc tree is properly pointed back by its subvolume tree. [CAUSE] After more debugging output, it turns out we had an invalid reloc tree: BTRFS error (device loop1): reloc tree mismatch, root 8 has no reloc root, expect reloc root key (-8, 132, 8) gen 17 Note the above root key is (TREE_RELOC_OBJECTID, ROOT_ITEM, QUOTA_TREE_OBJECTID), meaning it's a reloc tree for quota tree. But reloc trees can only exist for subvolumes, as for non-subvolume trees, we just COW the involved tree block, no need to create a reloc tree since those tree blocks won't be shared with other trees. Only subvolumes tree can share tree blocks with other trees (thus they have BTRFS_ROOT_SHAREABLE flag). Thus this new debug output proves my previous assumption that corrupted on-disk data can trigger that ASSERT(). [FIX] Besides the dedicated fix and the graceful exit, also let tree-checker to check such root keys, to make sure reloc trees can only exist for subvolumes. CC: [email protected] # 5.15+ Reported-by: [email protected] Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 9d04716 commit 3ae93b3

File tree

2 files changed

+16
-1
lines changed

2 files changed

+16
-1
lines changed

fs/btrfs/disk-io.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,8 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
14551455
goto fail;
14561456

14571457
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID &&
1458-
!btrfs_is_data_reloc_root(root)) {
1458+
!btrfs_is_data_reloc_root(root) &&
1459+
is_fstree(root->root_key.objectid)) {
14591460
set_bit(BTRFS_ROOT_SHAREABLE, &root->state);
14601461
btrfs_check_and_init_root_item(&root->root_item);
14611462
}

fs/btrfs/tree-checker.c

+14
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,20 @@ static int check_root_key(struct extent_buffer *leaf, struct btrfs_key *key,
442442
btrfs_item_key_to_cpu(leaf, &item_key, slot);
443443
is_root_item = (item_key.type == BTRFS_ROOT_ITEM_KEY);
444444

445+
/*
446+
* Bad rootid for reloc trees.
447+
*
448+
* Reloc trees are only for subvolume trees, other trees only need
449+
* to be COWed to be relocated.
450+
*/
451+
if (unlikely(is_root_item && key->objectid == BTRFS_TREE_RELOC_OBJECTID &&
452+
!is_fstree(key->offset))) {
453+
generic_err(leaf, slot,
454+
"invalid reloc tree for root %lld, root id is not a subvolume tree",
455+
key->offset);
456+
return -EUCLEAN;
457+
}
458+
445459
/* No such tree id */
446460
if (unlikely(key->objectid == 0)) {
447461
if (is_root_item)

0 commit comments

Comments
 (0)