public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] btrfs: reject empty non-root tree blocks at read time
@ 2026-04-09  8:11 ZhengYuan Huang
  2026-04-09  9:09 ` Qu Wenruo
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: ZhengYuan Huang @ 2026-04-09  8:11 UTC (permalink / raw)
  To: dsterba, clm, zheng.yan
  Cc: linux-btrfs, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
	ZhengYuan Huang

[BUG]
A corrupted tree can contain an empty non-root tree block linked from
its parent. If that block is later used by normal tree balancing,
btrfs can hit:

kernel BUG at fs/btrfs/ctree.c:3388!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
RIP: 0010:__push_leaf_left+0x11f8/0x1610 fs/btrfs/ctree.c:3388
Code: ff48c1ea 03803c02 000f85bd 00000048
Call Trace:
 push_leaf_left+0x3b3/0x540 fs/btrfs/ctree.c:3511
 btrfs_del_items+0x74d/0xf10 fs/btrfs/ctree.c:4541
 btrfs_del_csums+0x44d/0xa50 fs/btrfs/file-item.c:969
 do_free_extent_accounting fs/btrfs/extent-tree.c:2984 [inline]
 __btrfs_free_extent.isra.0+0xded/0x41d0 fs/btrfs/extent-tree.c:3372
 run_delayed_data_ref fs/btrfs/extent-tree.c:1599 [inline]
 run_one_delayed_ref fs/btrfs/extent-tree.c:1779 [inline]
 btrfs_run_delayed_refs_for_head fs/btrfs/extent-tree.c:1972 [inline]
 __btrfs_run_delayed_refs+0x86e/0x39a0 fs/btrfs/extent-tree.c:2047
 btrfs_run_delayed_refs+0x181/0x420 fs/btrfs/extent-tree.c:2159
 btrfs_commit_transaction+0xc9b/0x3d90 fs/btrfs/transaction.c:2211
 btrfs_sync_fs+0xf0/0x630 fs/btrfs/super.c:1057
 sync_fs_one_sb fs/sync.c:84 [inline]
 sync_fs_one_sb+0xf4/0x140 fs/sync.c:80
 __iterate_supers+0x1be/0x290 fs/super.c:923
 iterate_supers+0x24/0x40 fs/super.c:938
 ksys_sync+0xb4/0x160 fs/sync.c:104
 __do_sys_sync+0x13/0x20 fs/sync.c:113
 ...

[CAUSE]
The old btrfs_verify_level_key() path rejected tree blocks with
nritems == 0 whenever the parent check provided a first key.
Commit 947a629988f1 ("btrfs: move tree block parentness check into
validate_extent_buffer()") moved the parentness checks into the read-time
validation path, but it dropped that guard. This lets an empty non-root
tree block pass read-time validation even though slot 0 must exist if the
parent provides a first key.

[FIX]
Restore the nritems == 0 rejection in btrfs_validate_extent_buffer()
when check->has_first_key is set. This rejects empty non-root tree
blocks as soon as they are read from disk, before later btree
operations can hit BUG_ONs while trying to use them.

Fixes: 947a629988f1 ("btrfs: move tree block parentness check into validate_extent_buffer()")
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
v2:
- Move the corruption check from push_leaf_left() to read-time validation
- Restore the old nritems == 0 guard before reading slot 0

 fs/btrfs/disk-io.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0aa7e5d1b05f..ab2044d83155 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -430,6 +430,15 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,
 		const struct btrfs_key *expect_key = &check->first_key;
 		struct btrfs_key found_key;
 
+		/* We have @first_key, so this @eb must have at least one item. */
+		if (unlikely(btrfs_header_nritems(eb) == 0)) {
+			btrfs_err(fs_info,
+				  "invalid tree nritems, bytenr=%llu nritems=0 expect >0",
+				  eb->start);
+			ret = -EUCLEAN;
+			goto out;
+		}
+
 		if (found_level)
 			btrfs_node_key_to_cpu(eb, &found_key, 0);
 		else
-- 
2.43.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-04-12  4:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09  8:11 [PATCH v2] btrfs: reject empty non-root tree blocks at read time ZhengYuan Huang
2026-04-09  9:09 ` Qu Wenruo
2026-04-09  9:38   ` Qu Wenruo
2026-04-12  3:29 ` kernel test robot
2026-04-12  4:07 ` kernel test robot
2026-04-12  4:53 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox