• Qu Wenruo's avatar
    btrfs: do not ASSERT() on duplicated global roots · 745806fb
    Qu Wenruo authored
    [BUG]
    Syzbot reports a reproducible ASSERT() when using rescue=usebackuproot
    mount option on a corrupted fs.
    
    The full report can be found here:
    https://syzkaller.appspot.com/bug?extid=c4614eae20a166c25bf0
    
      BTRFS error (device loop0: state C): failed to load root csum
      assertion failed: !tmp, in fs/btrfs/disk-io.c:1103
      ------------[ cut here ]------------
      kernel BUG at fs/btrfs/ctree.h:3664!
      invalid opcode: 0000 [#1] PREEMPT SMP KASAN
      CPU: 1 PID: 3608 Comm: syz-executor356 Not tainted 6.0.0-rc7-syzkaller-00029-g3800a713 #0
      Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/26/2022
      RIP: 0010:assertfail+0x1a/0x1c fs/btrfs/ctree.h:3663
      RSP: 0018:ffffc90003aaf250 EFLAGS: 00010246
      RAX: 0000000000000032 RBX: 0000000000000000 RCX: f21c13f886638400
      RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
      RBP: ffff888021c640a0 R08: ffffffff816bd38d R09: ffffed10173667f1
      R10: ffffed10173667f1 R11: 1ffff110173667f0 R12: dffffc0000000000
      R13: ffff8880229c21f7 R14: ffff888021c64060 R15: ffff8880226c0000
      FS:  0000555556a73300(0000) GS:ffff8880b9b00000(0000) knlGS:0000000000000000
      CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
      CR2: 000055a2637d7a00 CR3: 00000000709c4000 CR4: 00000000003506e0
      DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
      DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
      Call Trace:
       <TASK>
       btrfs_global_root_insert+0x1a7/0x1b0 fs/btrfs/disk-io.c:1103
       load_global_roots_objectid+0x482/0x8c0 fs/btrfs/disk-io.c:2467
       load_global_roots fs/btrfs/disk-io.c:2501 [inline]
       btrfs_read_roots fs/btrfs/disk-io.c:2528 [inline]
       init_tree_roots+0xccb/0x203c fs/btrfs/disk-io.c:2939
       open_ctree+0x1e53/0x33df fs/btrfs/disk-io.c:3574
       btrfs_fill_super+0x1c6/0x2d0 fs/btrfs/super.c:1456
       btrfs_mount_root+0x885/0x9a0 fs/btrfs/super.c:1824
       legacy_get_tree+0xea/0x180 fs/fs_context.c:610
       vfs_get_tree+0x88/0x270 fs/super.c:1530
       fc_mount fs/namespace.c:1043 [inline]
       vfs_kern_mount+0xc9/0x160 fs/namespace.c:1073
       btrfs_mount+0x3d3/0xbb0 fs/btrfs/super.c:1884
    
    [CAUSE]
    Since the introduction of global roots, we handle
    csum/extent/free-space-tree roots as global roots, even if no
    extent-tree-v2 feature is enabled.
    
    So for regular csum/extent/fst roots, we load them into
    fs_info::global_root_tree rb tree.
    
    And we should not expect any conflicts in that rb tree, thus we have an
    ASSERT() inside btrfs_global_root_insert().
    
    But rescue=usebackuproot can break the assumption, as we will try to
    load those trees again and again as long as we have bad roots and have
    backup roots slot remaining.
    
    So in that case we can have conflicting roots in the rb tree, and
    triggering the ASSERT() crash.
    
    [FIX]
    We can safely remove that ASSERT(), as the caller will properly put the
    offending root.
    
    To make further debugging easier, also add two explicit error messages:
    
    - Error message for conflicting global roots
    - Error message when using backup roots slot
    
    Reported-by: syzbot+a694851c6ab28cbcfb9c@syzkaller.appspotmail.com
    Fixes: abed4aaa ("btrfs: track the csum, extent, and free space trees in a rb tree")
    CC: stable@vger.kernel.org # 6.1+
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    745806fb
disk-io.c 146 KB