• Qu Wenruo's avatar
    btrfs: extent-tree: Make sure we only allocate extents from block groups with the same type · c5dbd74f
    Qu Wenruo authored
    [ Upstream commit 2a28468e ]
    
    [BUG]
    With fuzzed image and MIXED_GROUPS super flag, we can hit the following
    BUG_ON():
    
      kernel BUG at fs/btrfs/delayed-ref.c:491!
      invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
      CPU: 0 PID: 1849 Comm: sync Tainted: G           O      5.2.0-custom #27
      RIP: 0010:update_existing_head_ref.cold+0x44/0x46 [btrfs]
      Call Trace:
       add_delayed_ref_head+0x20c/0x2d0 [btrfs]
       btrfs_add_delayed_tree_ref+0x1fc/0x490 [btrfs]
       btrfs_free_tree_block+0x123/0x380 [btrfs]
       __btrfs_cow_block+0x435/0x500 [btrfs]
       btrfs_cow_block+0x110/0x240 [btrfs]
       btrfs_search_slot+0x230/0xa00 [btrfs]
       ? __lock_acquire+0x105e/0x1e20
       btrfs_insert_empty_items+0x67/0xc0 [btrfs]
       alloc_reserved_file_extent+0x9e/0x340 [btrfs]
       __btrfs_run_delayed_refs+0x78e/0x1240 [btrfs]
       ? kvm_clock_read+0x18/0x30
       ? __sched_clock_gtod_offset+0x21/0x50
       btrfs_run_delayed_refs.part.0+0x4e/0x180 [btrfs]
       btrfs_run_delayed_refs+0x23/0x30 [btrfs]
       btrfs_commit_transaction+0x53/0x9f0 [btrfs]
       btrfs_sync_fs+0x7c/0x1c0 [btrfs]
       ? __ia32_sys_fdatasync+0x20/0x20
       sync_fs_one_sb+0x23/0x30
       iterate_supers+0x95/0x100
       ksys_sync+0x62/0xb0
       __ia32_sys_sync+0xe/0x20
       do_syscall_64+0x65/0x240
       entry_SYSCALL_64_after_hwframe+0x49/0xbe
    
    [CAUSE]
    This situation is caused by several factors:
    - Fuzzed image
      The extent tree of this fs missed one backref for extent tree root.
      So we can allocated space from that slot.
    
    - MIXED_BG feature
      Super block has MIXED_BG flag.
    
    - No mixed block groups exists
      All block groups are just regular ones.
    
    This makes data space_info->block_groups[] contains metadata block
    groups.  And when we reserve space for data, we can use space in
    metadata block group.
    
    Then we hit the following file operations:
    
    - fallocate
      We need to allocate data extents.
      find_free_extent() choose to use the metadata block to allocate space
      from, and choose the space of extent tree root, since its backref is
      missing.
    
      This generate one delayed ref head with is_data = 1.
    
    - extent tree update
      We need to update extent tree at run_delayed_ref time.
    
      This generate one delayed ref head with is_data = 0, for the same
      bytenr of old extent tree root.
    
    Then we trigger the BUG_ON().
    
    [FIX]
    The quick fix here is to check block_group->flags before using it.
    
    The problem can only happen for MIXED_GROUPS fs. Regular filesystems
    won't have space_info with DATA|METADATA flag, and no way to hit the
    bug.
    
    Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203255Reported-by: default avatarJungyeon Yoon <jungyeon.yoon@gmail.com>
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
    c5dbd74f
extent-tree.c 300 KB