[PATCH 1/3] btrfs: avoid NULL pointer dereference when block group tree root is missing

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

  BTRFS warning (device loop0 state E): checksum verify failed on logical 30654464 mirror 1 wanted 0x0f55b851 found 0xd7efdde7 level 0
  BTRFS warning (device loop0 state E): checksum verify failed on logical 30654464 mirror 2 wanted 0x0f55b851 found 0xd7efdde7 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+0x9d/0x1c0 [btrfs]
  Call Trace:
   fill_dummy_bgs+0xd4/0x120 [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
block group tree root and leaves fs_info->block_group_root NULL.

btrfs_read_block_groups() then falls back to fill_dummy_bgs(), which
initializes the global block reserve.  btrfs_update_global_block_rsv()
checks only the BLOCK_GROUP_TREE feature bit before dereferencing
fs_info->block_group_root.

[FIX]
Check that the block group tree root was successfully loaded before
accounting it in the global block reserve.  This does not affect regular
mounts, which fail earlier if the root cannot be loaded.

Also update the comment in btrfs_read_block_groups() to cover both the
extent tree root and the block group tree root being missing.

Fixes: 8dbfc14fc736 ("btrfs: account block group tree when calculating global reserve size")
Signed-off-by: Dongjiang Zhu <[email protected]>
---
 fs/btrfs/block-group.c | 7 ++++---
 fs/btrfs/block-rsv.c   | 3 ++-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index fe5de4928f6f..9d551372f37f 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -2673,9 +2673,10 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
 	u64 cache_gen;
 
 	/*
-	 * Either no extent root (with ibadroots rescue option) or we have
-	 * unsupported RO options. The fs can never be mounted read-write, so no
-	 * need to waste time searching block group items.
+	 * Either the extent tree root or the block group tree root is missing
+	 * (with the ibadroots rescue option), or we have unsupported RO options.
+	 * The fs can never be mounted read-write, so no need to waste time
+	 * searching block group items.
 	 *
 	 * This also allows new extent tree related changes to be RO compat,
 	 * no need for a full incompat flag.
diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
index 9efb3016ef11..647a065356f4 100644
--- a/fs/btrfs/block-rsv.c
+++ b/fs/btrfs/block-rsv.c
@@ -347,7 +347,8 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
 	}
 	read_unlock(&fs_info->global_root_lock);
 
-	if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) {
+	if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE) &&
+	    fs_info->block_group_root) {
 		num_bytes += btrfs_root_used(&fs_info->block_group_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.