• Qu Wenruo's avatar
    btrfs: trim: fix underflow in trim length to prevent access beyond device boundary · c57dd1f2
    Qu Wenruo authored
    [BUG]
    The following script can lead to tons of beyond device boundary access:
    
      mkfs.btrfs -f $dev -b 10G
      mount $dev $mnt
      trimfs $mnt
      btrfs filesystem resize 1:-1G $mnt
      trimfs $mnt
    
    [CAUSE]
    Since commit 929be17a ("btrfs: Switch btrfs_trim_free_extents to
    find_first_clear_extent_bit"), we try to avoid trimming ranges that's
    already trimmed.
    
    So we check device->alloc_state by finding the first range which doesn't
    have CHUNK_TRIMMED and CHUNK_ALLOCATED not set.
    
    But if we shrunk the device, that bits are not cleared, thus we could
    easily got a range starts beyond the shrunk device size.
    
    This results the returned @start and @end are all beyond device size,
    then we call "end = min(end, device->total_bytes -1);" making @end
    smaller than device size.
    
    Then finally we goes "len = end - start + 1", totally underflow the
    result, and lead to the beyond-device-boundary access.
    
    [FIX]
    This patch will fix the problem in two ways:
    
    - Clear CHUNK_TRIMMED | CHUNK_ALLOCATED bits when shrinking device
      This is the root fix
    
    - Add extra safety check when trimming free device extents
      We check and warn if the returned range is already beyond current
      device.
    
    Link: https://github.com/kdave/btrfs-progs/issues/282
    Fixes: 929be17a ("btrfs: Switch btrfs_trim_free_extents to find_first_clear_extent_bit")
    CC: stable@vger.kernel.org # 5.4+
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    c57dd1f2
volumes.c 204 KB