linux-stable/fs/btrfs
Qu Wenruo f546c42826 btrfs: scrub: avoid use-after-free when chunk length is not 64K aligned
[BUG]
There is a bug report that, on a ext4-converted btrfs, scrub leads to
various problems, including:

- "unable to find chunk map" errors
  BTRFS info (device vdb): scrub: started on devid 1
  BTRFS critical (device vdb): unable to find chunk map for logical 2214744064 length 4096
  BTRFS critical (device vdb): unable to find chunk map for logical 2214744064 length 45056

  This would lead to unrepariable errors.

- Use-after-free KASAN reports:
  ==================================================================
  BUG: KASAN: slab-use-after-free in __blk_rq_map_sg+0x18f/0x7c0
  Read of size 8 at addr ffff8881013c9040 by task btrfs/909
  CPU: 0 PID: 909 Comm: btrfs Not tainted 6.7.0-x64v3-dbg #11 c50636e9419a8354555555245df535e380563b2b
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 2023.11-2 12/24/2023
  Call Trace:
   <TASK>
   dump_stack_lvl+0x43/0x60
   print_report+0xcf/0x640
   kasan_report+0xa6/0xd0
   __blk_rq_map_sg+0x18f/0x7c0
   virtblk_prep_rq.isra.0+0x215/0x6a0 [virtio_blk 19a65eeee9ae6fcf02edfad39bb9ddee07dcdaff]
   virtio_queue_rqs+0xc4/0x310 [virtio_blk 19a65eeee9ae6fcf02edfad39bb9ddee07dcdaff]
   blk_mq_flush_plug_list.part.0+0x780/0x860
   __blk_flush_plug+0x1ba/0x220
   blk_finish_plug+0x3b/0x60
   submit_initial_group_read+0x10a/0x290 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965]
   flush_scrub_stripes+0x38e/0x430 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965]
   scrub_stripe+0x82a/0xae0 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965]
   scrub_chunk+0x178/0x200 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965]
   scrub_enumerate_chunks+0x4bc/0xa30 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965]
   btrfs_scrub_dev+0x398/0x810 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965]
   btrfs_ioctl+0x4b9/0x3020 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965]
   __x64_sys_ioctl+0xbd/0x100
   do_syscall_64+0x5d/0xe0
   entry_SYSCALL_64_after_hwframe+0x63/0x6b
  RIP: 0033:0x7f47e5e0952b

- Crash, mostly due to above use-after-free

[CAUSE]
The converted fs has the following data chunk layout:

    item 2 key (FIRST_CHUNK_TREE CHUNK_ITEM 2214658048) itemoff 16025 itemsize 80
        length 86016 owner 2 stripe_len 65536 type DATA|single

For above logical bytenr 2214744064, it's at the chunk end
(2214658048 + 86016 = 2214744064).

This means btrfs_submit_bio() would split the bio, and trigger endio
function for both of the two halves.

However scrub_submit_initial_read() would only expect the endio function
to be called once, not any more.
This means the first endio function would already free the bbio::bio,
leaving the bvec freed, thus the 2nd endio call would lead to
use-after-free.

[FIX]
- Make sure scrub_read_endio() only updates bits in its range
  Since we may read less than 64K at the end of the chunk, we should not
  touch the bits beyond chunk boundary.

- Make sure scrub_submit_initial_read() only to read the chunk range
  This is done by calculating the real number of sectors we need to
  read, and add sector-by-sector to the bio.

Thankfully the scrub read repair path won't need extra fixes:

- scrub_stripe_submit_repair_read()
  With above fixes, we won't update error bit for range beyond chunk,
  thus scrub_stripe_submit_repair_read() should never submit any read
  beyond the chunk.

Reported-by: Rongrong <i@rong.moe>
Fixes: e02ee89baa ("btrfs: scrub: switch scrub_simple_mirror() to scrub_stripe infrastructure")
Tested-by: Rongrong <i@rong.moe>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2024-01-18 23:42:06 +01:00
..
tests btrfs: migrate extent_buffer::pages[] to folio 2023-12-15 23:01:04 +01:00
accessors.c btrfs: migrate get_eb_page_index() and get_eb_offset_in_page() to folios 2023-12-15 23:03:58 +01:00
accessors.h btrfs: migrate extent_buffer::pages[] to folio 2023-12-15 23:01:04 +01:00
acl.c fs: port acl to mnt_idmap 2023-01-19 09:24:28 +01:00
acl.h fs: port ->set_acl() to pass mnt_idmap 2023-01-19 09:24:27 +01:00
async-thread.c btrfs: merge ordered work callbacks in btrfs_work into one 2023-10-12 16:44:10 +02:00
async-thread.h btrfs: merge ordered work callbacks in btrfs_work into one 2023-10-12 16:44:10 +02:00
backref.c for-6.7-tag 2023-10-30 10:42:06 -10:00
backref.h for-6.7-tag 2023-10-30 10:42:06 -10:00
bio.c btrfs: migrate btrfs_repair_io_failure() to folio interfaces 2023-12-15 23:03:58 +01:00
bio.h btrfs: migrate btrfs_repair_io_failure() to folio interfaces 2023-12-15 23:03:58 +01:00
block-group.c btrfs: fix typos found by codespell 2023-12-15 23:00:04 +01:00
block-group.h btrfs: use a dedicated data structure for chunk maps 2023-12-15 20:27:02 +01:00
block-rsv.c btrfs: read raid stripe tree from disk 2023-10-12 16:44:09 +02:00
block-rsv.h btrfs: move btrfs_check_trunc_cache_free_space into block-rsv.c 2023-06-19 13:59:24 +02:00
btrfs_inode.h btrfs: fix mismatching parameter names for btrfs_get_extent() 2023-12-15 22:59:30 +01:00
compression.c btrfs: zlib: fix and simplify the inline extent decompression 2024-01-18 23:35:26 +01:00
compression.h btrfs: zstd: fix and simplify the inline extent decompression 2024-01-18 23:35:35 +01:00
ctree.c btrfs: migrate get_eb_page_index() and get_eb_offset_in_page() to folios 2023-12-15 23:03:58 +01:00
ctree.h btrfs: switch btrfs_root::delayed_nodes_tree to xarray from radix-tree 2023-12-15 23:01:03 +01:00
defrag.c btrfs: migrate subpage code to folio interfaces 2023-12-15 23:03:58 +01:00
defrag.h btrfs: move btrfs_defrag_root() to defrag.{c,h} 2023-10-12 16:44:13 +02:00
delalloc-space.c btrfs: fix qgroup_free_reserved_data int overflow 2023-12-06 22:32:46 +01:00
delalloc-space.h btrfs: move delalloc space related prototypes to delalloc-space.h 2022-12-05 18:00:44 +01:00
delayed-inode.c btrfs: switch btrfs_root::delayed_nodes_tree to xarray from radix-tree 2023-12-15 23:01:03 +01:00
delayed-inode.h btrfs: remove redundant root argument from btrfs_delayed_update_inode() 2023-10-12 16:44:12 +02:00
delayed-ref.c btrfs: fix qgroup record leaks when using simple quotas 2023-11-09 14:01:59 +01:00
delayed-ref.h btrfs: stop reserving excessive space for block group item insertions 2023-10-12 16:44:16 +02:00
dev-replace.c btrfs: use a dedicated data structure for chunk maps 2023-12-15 20:27:02 +01:00
dev-replace.h btrfs: move dev-replace prototypes into dev-replace.h 2022-12-05 18:00:47 +01:00
dir-item.c btrfs: abort transaction on generation mismatch when marking eb as dirty 2023-10-12 16:44:07 +02:00
dir-item.h btrfs: add fscrypt related dependencies to respective headers 2023-10-12 16:44:02 +02:00
discard.c btrfs: unexport btrfs_run_discard_work and make it static 2023-06-19 13:59:25 +02:00
discard.h btrfs: unexport btrfs_run_discard_work and make it static 2023-06-19 13:59:25 +02:00
disk-io.c btrfs: migrate btrfs_repair_io_failure() to folio interfaces 2023-12-15 23:03:58 +01:00
disk-io.h btrfs: move one shot mount option clearing to super.c 2023-12-15 20:27:04 +01:00
export.c btrfs: move super_block specific helpers into super.h 2022-12-05 18:00:47 +01:00
export.h btrfs: simplify generation check in btrfs_get_dentry 2022-12-05 18:00:41 +01:00
extent-io-tree.c btrfs: allocate btrfs_inode::file_extent_tree only without NO_HOLES 2023-12-15 22:59:01 +01:00
extent-io-tree.h btrfs: always set extent_io_tree::inode and drop fs_info 2023-12-15 20:27:02 +01:00
extent-tree.c btrfs: don't warn if discard range is not aligned to sector 2024-01-18 23:35:57 +01:00
extent-tree.h btrfs: get correct owning_root when dropping snapshot 2023-11-03 16:39:06 +01:00
extent_io.c btrfs: migrate eb_bitmap_offset() to folio interfaces 2023-12-15 23:03:58 +01:00
extent_io.h btrfs: migrate get_eb_page_index() and get_eb_offset_in_page() to folios 2023-12-15 23:03:58 +01:00
extent_map.c btrfs: use the flags of an extent map to identify the compression type 2023-12-15 22:59:02 +01:00
extent_map.h btrfs: use the flags of an extent map to identify the compression type 2023-12-15 22:59:02 +01:00
file-item.c btrfs: use the flags of an extent map to identify the compression type 2023-12-15 22:59:02 +01:00
file-item.h btrfs: scrub: avoid unnecessary csum tree search preparing stripes 2023-08-21 14:54:48 +02:00
file.c btrfs: migrate subpage code to folio interfaces 2023-12-15 23:03:58 +01:00
file.h btrfs: use cached state when looking for delalloc ranges with fiemap 2022-12-05 18:00:56 +01:00
free-space-cache.c btrfs: migrate subpage code to folio interfaces 2023-12-15 23:03:58 +01:00
free-space-cache.h btrfs: move btrfs_check_trunc_cache_free_space into block-rsv.c 2023-06-19 13:59:24 +02:00
free-space-tree.c btrfs: abort transaction on generation mismatch when marking eb as dirty 2023-10-12 16:44:07 +02:00
free-space-tree.h btrfs: make clear_cache mount option to rebuild FST without disabling it 2023-05-10 14:51:27 +02:00
fs.c btrfs: sysfs: update fs features directory asynchronously 2023-02-13 17:50:35 +01:00
fs.h btrfs: remove old mount API code 2023-12-15 20:27:04 +01:00
inode-item.c btrfs: track owning root in btrfs_ref 2023-10-12 16:44:11 +02:00
inode-item.h btrfs: add fscrypt related dependencies to respective headers 2023-10-12 16:44:02 +02:00
inode.c btrfs: avoid copying BTRFS_ROOT_SUBVOL_DEAD flag to snapshot of subvolume being deleted 2024-01-12 02:00:21 +01:00
ioctl.c btrfs: defrag: reject unknown flags of btrfs_ioctl_defrag_range_args 2024-01-12 02:04:19 +01:00
ioctl.h fs: port ->fileattr_set() to pass mnt_idmap 2023-01-19 09:24:27 +01:00
Kconfig btrfs: check-integrity: remove CONFIG_BTRFS_FS_CHECK_INTEGRITY option 2023-10-12 16:44:05 +02:00
locking.c btrfs: add raid stripe tree definitions 2023-10-12 16:44:09 +02:00
locking.h btrfs: do not block starts waiting on previous transaction commit 2023-09-08 14:10:49 +02:00
lru_cache.c btrfs: fix typos found by codespell 2023-12-15 23:00:04 +01:00
lru_cache.h btrfs: remove btrfs_lru_cache_is_full() inline function 2023-04-17 18:01:18 +02:00
lzo.c btrfs: lzo: fix and simplify the inline extent decompression 2024-01-18 23:35:30 +01:00
Makefile btrfs: add support for inserting raid stripe extents 2023-10-12 16:44:09 +02:00
messages.c btrfs: constify fs_info parameter in __btrfs_panic() 2023-12-15 20:27:02 +01:00
messages.h btrfs: constify fs_info parameter in __btrfs_panic() 2023-12-15 20:27:02 +01:00
misc.h minmax: add in_range() macro 2023-08-24 16:20:18 -07:00
ordered-data.c btrfs: migrate subpage code to folio interfaces 2023-12-15 23:03:58 +01:00
ordered-data.h btrfs: remove unused btrfs_ordered_extent::outstanding_isize 2023-12-15 20:27:01 +01:00
orphan.c btrfs: move orphan prototypes into orphan.h 2022-12-05 18:00:47 +01:00
orphan.h btrfs: move orphan prototypes into orphan.h 2022-12-05 18:00:47 +01:00
print-tree.c btrfs: new inline ref storing owning subvol of data extents 2023-10-12 16:44:11 +02:00
print-tree.h btrfs: print-tree: pass const extent buffer pointer 2023-06-19 13:59:22 +02:00
props.c btrfs: move btrfs_name_hash to dir-item.h 2023-10-12 16:44:02 +02:00
props.h btrfs: make module init/exit match their sequence 2022-12-05 18:00:40 +01:00
qgroup.c btrfs: fix typos found by codespell 2023-12-15 23:00:04 +01:00
qgroup.h btrfs: ensure releasing squota reserve on head refs 2023-12-06 22:32:57 +01:00
raid-stripe-tree.c btrfs: directly return 0 on no error code in btrfs_insert_raid_extent() 2023-11-03 16:38:51 +01:00
raid-stripe-tree.h btrfs: zoned: support RAID0/1/10 on top of raid stripe tree 2023-10-12 16:44:09 +02:00
raid56.c btrfs: refactor alloc_extent_buffer() to allocate-then-attach method 2023-12-15 23:01:04 +01:00
raid56.h btrfs: use a dedicated data structure for chunk maps 2023-12-15 20:27:02 +01:00
rcu-string.h btrfs: replace strncpy() with strscpy() 2022-12-05 18:00:59 +01:00
ref-verify.c btrfs: ref-verify: free ref cache before clearing mount opt 2024-01-12 01:59:49 +01:00
ref-verify.h
reflink.c btrfs: migrate subpage code to folio interfaces 2023-12-15 23:03:58 +01:00
reflink.h
relocation.c btrfs: migrate subpage code to folio interfaces 2023-12-15 23:03:58 +01:00
relocation.h btrfs: relocation: constify parameters where possible 2023-10-12 16:44:13 +02:00
root-tree.c btrfs: qgroup: add new quota mode for simple quotas 2023-10-12 16:44:10 +02:00
root-tree.h btrfs: drop __must_check annotations 2023-10-12 16:44:04 +02:00
scrub.c btrfs: scrub: avoid use-after-free when chunk length is not 64K aligned 2024-01-18 23:42:06 +01:00
scrub.h btrfs: scrub: remove scrub_bio structure 2023-04-17 18:01:24 +02:00
send.c btrfs: fix kvcalloc() arguments order in btrfs_ioctl_send() 2024-01-12 01:59:45 +01:00
send.h btrfs: send add define for v2 buffer size 2022-12-05 18:00:41 +01:00
space-info.c btrfs: adjust overcommit logic when very close to full 2023-10-12 16:44:16 +02:00
space-info.h btrfs: pass a space_info argument to btrfs_reserve_metadata_bytes() 2023-10-12 16:44:05 +02:00
subpage.c btrfs: don't unconditionally call folio_start_writeback in subpage 2024-01-18 23:39:59 +01:00
subpage.h btrfs: migrate subpage code to folio interfaces 2023-12-15 23:03:58 +01:00
super.c btrfs: use the original mount's mount options for the legacy reconfigure 2024-01-18 23:38:54 +01:00
super.h btrfs: remove old mount API code 2023-12-15 20:27:04 +01:00
sysfs.c btrfs: sysfs: validate scrub_speed_max value 2023-12-15 23:01:04 +01:00
sysfs.h btrfs: sysfs: update fs features directory asynchronously 2023-02-13 17:50:35 +01:00
transaction.c for-6.7-rc5-tag 2023-12-14 11:53:00 -08:00
transaction.h btrfs: free qgroup pertrans reserve on transaction abort 2023-12-06 22:32:49 +01:00
tree-checker.c btrfs: tree-checker: fix inline ref size in error messages 2024-01-18 23:35:50 +01:00
tree-checker.h btrfs: fix typos found by codespell 2023-12-15 23:00:04 +01:00
tree-log.c btrfs: use the flags of an extent map to identify the compression type 2023-12-15 22:59:02 +01:00
tree-log.h btrfs: change for_rename argument of btrfs_record_unlink_dir() to bool 2023-06-19 13:59:26 +02:00
tree-mod-log.c btrfs: avoid tree mod log ENOMEM failures when we don't need to log 2023-06-19 13:59:38 +02:00
tree-mod-log.h btrfs: fix SPDX comment in tree-mod-log.h 2022-12-05 18:00:48 +01:00
ulist.c btrfs: reformat remaining kdoc style comments 2023-10-12 16:44:04 +02:00
ulist.h btrfs: constify ulist parameter of ulist_next() 2022-12-05 18:00:50 +01:00
uuid-tree.c btrfs: abort transaction on generation mismatch when marking eb as dirty 2023-10-12 16:44:07 +02:00
uuid-tree.h btrfs: move uuid tree prototypes to uuid-tree.h 2022-12-05 18:00:46 +01:00
verity.c btrfs: remove redundant root argument from btrfs_update_inode() 2023-10-12 16:44:12 +02:00
verity.h btrfs: move verity prototypes into verity.h 2022-12-05 18:00:47 +01:00
volumes.c btrfs: fix unbalanced unlock of mapping_tree_lock 2024-01-12 01:59:59 +01:00
volumes.h btrfs: fix typos found by codespell 2023-12-15 23:00:04 +01:00
xattr.c btrfs: cache that we don't have security.capability set 2023-12-15 20:27:05 +01:00
xattr.h btrfs: move btrfs_xattr_handlers to .rodata 2023-10-09 16:24:17 +02:00
zlib.c btrfs: zlib: fix and simplify the inline extent decompression 2024-01-18 23:35:26 +01:00
zoned.c btrfs: zoned: fix lock ordering in btrfs_zone_activate() 2024-01-12 02:00:09 +01:00
zoned.h btrfs: fix typos found by codespell 2023-12-15 23:00:04 +01:00
zstd.c btrfs: zstd: fix and simplify the inline extent decompression 2024-01-18 23:35:35 +01:00