mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-06 05:02:31 +00:00
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>
This commit is contained in:
parent
05d7ce5045
commit
6ebcd021c9
@ -1103,7 +1103,8 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
|
||||
btrfs_drew_lock_init(&root->snapshot_lock);
|
||||
|
||||
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID &&
|
||||
!btrfs_is_data_reloc_root(root)) {
|
||||
!btrfs_is_data_reloc_root(root) &&
|
||||
is_fstree(root->root_key.objectid)) {
|
||||
set_bit(BTRFS_ROOT_SHAREABLE, &root->state);
|
||||
btrfs_check_and_init_root_item(&root->root_item);
|
||||
}
|
||||
|
@ -446,6 +446,20 @@ static int check_root_key(struct extent_buffer *leaf, struct btrfs_key *key,
|
||||
btrfs_item_key_to_cpu(leaf, &item_key, slot);
|
||||
is_root_item = (item_key.type == BTRFS_ROOT_ITEM_KEY);
|
||||
|
||||
/*
|
||||
* Bad rootid for reloc trees.
|
||||
*
|
||||
* Reloc trees are only for subvolume trees, other trees only need
|
||||
* to be COWed to be relocated.
|
||||
*/
|
||||
if (unlikely(is_root_item && key->objectid == BTRFS_TREE_RELOC_OBJECTID &&
|
||||
!is_fstree(key->offset))) {
|
||||
generic_err(leaf, slot,
|
||||
"invalid reloc tree for root %lld, root id is not a subvolume tree",
|
||||
key->offset);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
/* No such tree id */
|
||||
if (unlikely(key->objectid == 0)) {
|
||||
if (is_root_item)
|
||||
|
Loading…
Reference in New Issue
Block a user