Skip to content

Commit 6ebcd02

Browse files
adam900710kdave
authored andcommitted
btrfs: reject invalid reloc tree root keys with stack dump
[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: stable@vger.kernel.org # 5.15+ Reported-by: syzbot+ae97a827ae1c3336bbb4@syzkaller.appspotmail.com Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 05d7ce5 commit 6ebcd02

File tree

2 files changed

+16
-1
lines changed

2 files changed

+16
-1
lines changed

fs/btrfs/disk-io.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,8 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
11031103
btrfs_drew_lock_init(&root->snapshot_lock);
11041104

11051105
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID &&
1106-
!btrfs_is_data_reloc_root(root)) {
1106+
!btrfs_is_data_reloc_root(root) &&
1107+
is_fstree(root->root_key.objectid)) {
11071108
set_bit(BTRFS_ROOT_SHAREABLE, &root->state);
11081109
btrfs_check_and_init_root_item(&root->root_item);
11091110
}

fs/btrfs/tree-checker.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,20 @@ static int check_root_key(struct extent_buffer *leaf, struct btrfs_key *key,
446446
btrfs_item_key_to_cpu(leaf, &item_key, slot);
447447
is_root_item = (item_key.type == BTRFS_ROOT_ITEM_KEY);
448448

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

0 commit comments

Comments
 (0)