[PATCH] btrfs: fix NULL pointer deref during assertion in btrfs_backref_free_node()

[email protected]
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <8bc196601d6cd471a97a175a3f328425e1efc62f.1782745731.git.fdmanana@suse.com>
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]>
---
 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);
-- 
2.47.2
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.