• Anand Jain's avatar
    btrfs: check for missing device in btrfs_trim_fs · 16a200f6
    Anand Jain authored
    A fstrim on a degraded raid1 can trigger the following null pointer
    dereference:
    
      BTRFS info (device loop0): allowing degraded mounts
      BTRFS info (device loop0): disk space caching is enabled
      BTRFS info (device loop0): has skinny extents
      BTRFS warning (device loop0): devid 2 uuid 97ac16f7-e14d-4db1-95bc-3d489b424adb is missing
      BTRFS warning (device loop0): devid 2 uuid 97ac16f7-e14d-4db1-95bc-3d489b424adb is missing
      BTRFS info (device loop0): enabling ssd optimizations
      BUG: kernel NULL pointer dereference, address: 0000000000000620
      PGD 0 P4D 0
      Oops: 0000 [#1] SMP NOPTI
      CPU: 0 PID: 4574 Comm: fstrim Not tainted 5.13.0-rc7+ #31
      Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
      RIP: 0010:btrfs_trim_fs+0x199/0x4a0 [btrfs]
      RSP: 0018:ffff959541797d28 EFLAGS: 00010293
      RAX: 0000000000000000 RBX: ffff946f84eca508 RCX: a7a67937adff8608
      RDX: ffff946e8122d000 RSI: 0000000000000000 RDI: ffffffffc02fdbf0
      RBP: ffff946ea4615000 R08: 0000000000000001 R09: 0000000000000000
      R10: 0000000000000000 R11: ffff946e8122d960 R12: 0000000000000000
      R13: ffff959541797db8 R14: ffff946e8122d000 R15: ffff959541797db8
      FS:  00007f55917a5080(0000) GS:ffff946f9bc00000(0000) knlGS:0000000000000000
      CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
      CR2: 0000000000000620 CR3: 000000002d2c8001 CR4: 00000000000706f0
      Call Trace:
      btrfs_ioctl_fitrim+0x167/0x260 [btrfs]
      btrfs_ioctl+0x1c00/0x2fe0 [btrfs]
      ? selinux_file_ioctl+0x140/0x240
      ? syscall_trace_enter.constprop.0+0x188/0x240
      ? __x64_sys_ioctl+0x83/0xb0
      __x64_sys_ioctl+0x83/0xb0
    
    Reproducer:
    
      $ mkfs.btrfs -fq -d raid1 -m raid1 /dev/loop0 /dev/loop1
      $ mount /dev/loop0 /btrfs
      $ umount /btrfs
      $ btrfs dev scan --forget
      $ mount -o degraded /dev/loop0 /btrfs
    
      $ fstrim /btrfs
    
    The reason is we call btrfs_trim_free_extents() for the missing device,
    which uses device->bdev (NULL for missing device) to find if the device
    supports discard.
    
    Fix is to check if the device is missing before calling
    btrfs_trim_free_extents().
    
    CC: stable@vger.kernel.org # 5.4+
    Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarAnand Jain <anand.jain@oracle.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    16a200f6
extent-tree.c 163 KB