Re: [PATCH] btrfs: fix NULL pointer deref during assertion in btrfs_backref_free_node()
Qu Wenruo <[email protected]>
| Newsgroups | org.kernel.vger.linux-btrfs |
|---|---|
| Message-ID | <[email protected]> |
在 2026/6/30 00:39, [email protected] 写道: > From: Filipe Manana <[email protected]> > > In btrfs_backref_free_node() we have the following assertion: > > ASSERT(node->eb == NULL, "node->eb->start=%llu", node->eb->start); > > and a user reported the following crash: > > Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI > KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] > CPU: 0 UID: 0 PID: 10422 Comm: syz.0.17 Not tainted 7.1.0-02765-g6b5a2b7d9bc1-dirty #44 PREEMPT(full) > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 > RIP: 0010:btrfs_backref_free_node fs/btrfs/backref.c:3057 [inline] > RIP: 0010:btrfs_backref_free_node+0xb9/0x200 fs/btrfs/backref.c:3051 > Code: 00 fc ff (...) > RSP: 0018:ffa0000006b0f3c0 EFLAGS: 00010246 > RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffffffff840eb78b > RDX: 0000000000000000 RSI: ffffffff840eafa5 RDI: ff110000742ab768 > RBP: ff110000742ab700 R08: 0000000000000000 R09: 0000000000000000 > R10: ff110000742ab700 R11: 00000000000a81f9 R12: ff11000107a92020 > R13: ff1100005c182ea8 R14: 0000000000000000 R15: dffffc0000000000 > FS: 0000555575536500(0000) GS:ff11000183985000(0000) knlGS:0000000000000000 > CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 > CR2: 00007fa3d0e9d580 CR3: 000000002232a000 CR4: 0000000000753ef0 > PKRU: 00000000 > Call Trace: > <TASK> > btrfs_backref_cleanup_node+0x27/0x30 fs/btrfs/backref.c:3133 > relocate_tree_block fs/btrfs/relocation.c:2604 [inline] > relocate_tree_blocks+0x11b0/0x1a20 fs/btrfs/relocation.c:2707 > relocate_block_group+0x499/0xf30 fs/btrfs/relocation.c:3635 > do_nonremap_reloc fs/btrfs/relocation.c:5323 [inline] > btrfs_relocate_block_group+0x1749/0x5fb0 fs/btrfs/relocation.c:5490 > btrfs_relocate_chunk+0x12b/0x950 fs/btrfs/volumes.c:3647 > __btrfs_balance fs/btrfs/volumes.c:4586 [inline] > btrfs_balance+0x1c7f/0x55c0 fs/btrfs/volumes.c:4973 > btrfs_ioctl_balance fs/btrfs/ioctl.c:3474 [inline] > btrfs_ioctl+0x38a4/0x5d20 fs/btrfs/ioctl.c:5570 > vfs_ioctl fs/ioctl.c:51 [inline] > __do_sys_ioctl fs/ioctl.c:597 [inline] > __se_sys_ioctl fs/ioctl.c:583 [inline] > __x64_sys_ioctl+0x18f/0x210 fs/ioctl.c:583 > do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] > do_syscall_64+0x11f/0x860 arch/x86/entry/syscall_64.c:94 > entry_SYSCALL_64_after_hwframe+0x77/0x7f > RIP: 0033:0x7fb38e3b56dd > Code: 02 b8 ff (...) > RSP: 002b:00007fff04115788 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 > RAX: ffffffffffffffda RBX: 00007fb38f6b0020 RCX: 00007fb38e3b56dd > RDX: 00002000000003c0 RSI: 00000000c4009420 RDI: 0000000000000004 > RBP: 00007fb38e451b48 R08: 0000000000000000 R09: 0000000000000000 > R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 > R13: 0000000000000000 R14: 00007fb38f6b0020 R15: 00007fb38f6b002c > </TASK> > > It seems that this happens on some systems for some reason, when the > ASSERT() macro calls the inline function verify_assert_printk_format() > to evaluate the format string and arguments, causing the NULL pointer > dereference on node->eb. > > So change the assertion to check for a NULL node->eb before dereferencing > it. Also, while at it, make the assertion more useful by printing the > owner of the extent buffer as well as its level. > > Reported-by: Yue Sun <[email protected]> > Link: https://lore.kernel.org/linux-btrfs/[email protected]/ > Fixes: c4e7778580d6 ("btrfs: use verbose assertions in backref.c") > Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: Qu Wenruo <[email protected]> Thanks, Qu > --- > fs/btrfs/backref.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c > index 23c3eeb58dc1..1be632c742bd 100644 > --- a/fs/btrfs/backref.c > +++ b/fs/btrfs/backref.c > @@ -3054,7 +3054,10 @@ void btrfs_backref_free_node(struct btrfs_backref_cache *cache, > if (node) { > ASSERT(list_empty(&node->list)); > ASSERT(list_empty(&node->lower)); > - ASSERT(node->eb == NULL, "node->eb->start=%llu", node->eb->start); > + ASSERT(node->eb == NULL, "node->eb->start=%llu level=%d owner=%llu", > + node->eb ? node->eb->start : 0, > + node->eb ? btrfs_header_level(node->eb) : 0, > + node->eb ? btrfs_header_owner(node->eb) : 0); > cache->nr_nodes--; > btrfs_put_root(node->root); > kfree(node);