[PATCH 2/3] btrfs: avoid NULL pointer dereference when raid stripe tree root is missing

"Dongjiang Zhu" <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <[email protected]>
[BUG]
For a filesystem using the raid stripe tree feature, corrupting the raid
stripe tree root and mounting with rescue=ibadroots triggers the following
NULL pointer dereference:

  BTRFS warning (device loop1 state E): checksum verify failed on logical 30523392 mirror 1 wanted 0x74eeb205 found 0x9fa5ae1b level 0
  BTRFS warning (device loop1 state E): checksum verify failed on logical 30523392 mirror 2 wanted 0x74eeb205 found 0x9fa5ae1b level 0
  BUG: kernel NULL pointer dereference, address: 0000000000000100
  #PF: supervisor read access in kernel mode
  #PF: error_code(0x0000) - not-present page
  Oops: Oops: 0000 [#1] SMP NOPTI
  RIP: 0010:btrfs_update_global_block_rsv+0xb5/0x1c0 [btrfs]
  Call Trace:
   btrfs_read_block_groups+0x7d1/0xa10 [btrfs]
   open_ctree+0xc6e/0x1ca0 [btrfs]
   btrfs_get_tree+0x50d/0xa40 [btrfs]

[CAUSE]
With rescue=ibadroots, btrfs_read_roots() ignores a failure to read the
raid stripe tree root and leaves fs_info->stripe_root NULL.

After reading the block groups, btrfs_read_block_groups() initializes the
global block reserve.  btrfs_update_global_block_rsv() checks only the
RAID_STRIPE_TREE feature bit before dereferencing fs_info->stripe_root.

[FIX]
Check that the raid stripe tree root was successfully loaded before
accounting it in the global block reserve.  A missing root cannot
contribute to the reserve calculation, so skip both its size and minimum
item count.

This does not affect regular mounts, which fail earlier if the root cannot
be loaded.

Fixes: 515020900d44 ("btrfs: read raid stripe tree from disk")
Signed-off-by: Dongjiang Zhu <[email protected]>
---
 fs/btrfs/block-rsv.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
index 647a065356f4..114342ef500c 100644
--- a/fs/btrfs/block-rsv.c
+++ b/fs/btrfs/block-rsv.c
@@ -353,7 +353,8 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
 		min_items++;
 	}
 
-	if (btrfs_fs_incompat(fs_info, RAID_STRIPE_TREE)) {
+	if (btrfs_fs_incompat(fs_info, RAID_STRIPE_TREE) &&
+	    fs_info->stripe_root) {
 		num_bytes += btrfs_root_used(&fs_info->stripe_root->root_item);
 		min_items++;
 	}
-- 
2.39.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.