linux/fs/btrfs
Zixuan Fu 85f02d6c85 btrfs: unset reloc control if transaction commit fails in prepare_to_relocate()
In btrfs_relocate_block_group(), the rc is allocated.  Then
btrfs_relocate_block_group() calls

relocate_block_group()
  prepare_to_relocate()
    set_reloc_control()

that assigns rc to the variable fs_info->reloc_ctl. When
prepare_to_relocate() returns, it calls

btrfs_commit_transaction()
  btrfs_start_dirty_block_groups()
    btrfs_alloc_path()
      kmem_cache_zalloc()

which may fail for example (or other errors could happen). When the
failure occurs, btrfs_relocate_block_group() detects the error and frees
rc and doesn't set fs_info->reloc_ctl to NULL. After that, in
btrfs_init_reloc_root(), rc is retrieved from fs_info->reloc_ctl and
then used, which may cause a use-after-free bug.

This possible bug can be triggered by calling btrfs_ioctl_balance()
before calling btrfs_ioctl_defrag().

To fix this possible bug, in prepare_to_relocate(), check if
btrfs_commit_transaction() fails. If the failure occurs,
unset_reloc_control() is called to set fs_info->reloc_ctl to NULL.

The error log in our fault-injection testing is shown as follows:

  [   58.751070] BUG: KASAN: use-after-free in btrfs_init_reloc_root+0x7ca/0x920 [btrfs]
  ...
  [   58.753577] Call Trace:
  ...
  [   58.755800]  kasan_report+0x45/0x60
  [   58.756066]  btrfs_init_reloc_root+0x7ca/0x920 [btrfs]
  [   58.757304]  record_root_in_trans+0x792/0xa10 [btrfs]
  [   58.757748]  btrfs_record_root_in_trans+0x463/0x4f0 [btrfs]
  [   58.758231]  start_transaction+0x896/0x2950 [btrfs]
  [   58.758661]  btrfs_defrag_root+0x250/0xc00 [btrfs]
  [   58.759083]  btrfs_ioctl_defrag+0x467/0xa00 [btrfs]
  [   58.759513]  btrfs_ioctl+0x3c95/0x114e0 [btrfs]
  ...
  [   58.768510] Allocated by task 23683:
  [   58.768777]  ____kasan_kmalloc+0xb5/0xf0
  [   58.769069]  __kmalloc+0x227/0x3d0
  [   58.769325]  alloc_reloc_control+0x10a/0x3d0 [btrfs]
  [   58.769755]  btrfs_relocate_block_group+0x7aa/0x1e20 [btrfs]
  [   58.770228]  btrfs_relocate_chunk+0xf1/0x760 [btrfs]
  [   58.770655]  __btrfs_balance+0x1326/0x1f10 [btrfs]
  [   58.771071]  btrfs_balance+0x3150/0x3d30 [btrfs]
  [   58.771472]  btrfs_ioctl_balance+0xd84/0x1410 [btrfs]
  [   58.771902]  btrfs_ioctl+0x4caa/0x114e0 [btrfs]
  ...
  [   58.773337] Freed by task 23683:
  ...
  [   58.774815]  kfree+0xda/0x2b0
  [   58.775038]  free_reloc_control+0x1d6/0x220 [btrfs]
  [   58.775465]  btrfs_relocate_block_group+0x115c/0x1e20 [btrfs]
  [   58.775944]  btrfs_relocate_chunk+0xf1/0x760 [btrfs]
  [   58.776369]  __btrfs_balance+0x1326/0x1f10 [btrfs]
  [   58.776784]  btrfs_balance+0x3150/0x3d30 [btrfs]
  [   58.777185]  btrfs_ioctl_balance+0xd84/0x1410 [btrfs]
  [   58.777621]  btrfs_ioctl+0x4caa/0x114e0 [btrfs]
  ...

Reported-by: TOTE Robot <oslab@tsinghua.edu.cn>
CC: stable@vger.kernel.org # 5.15+
Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Zixuan Fu <r33s3n6@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2022-08-17 16:18:58 +02:00
..
tests btrfs: add optimized btrfs_ino() version for 64 bits systems 2022-07-25 17:45:41 +02:00
acl.c btrfs: reserve correct number of items for inode creation 2022-05-16 17:03:08 +02:00
async-thread.c btrfs: simplify WQ_HIGHPRI handling in struct btrfs_workqueue 2022-05-16 17:03:15 +02:00
async-thread.h btrfs: remove unused typedefs get_extent_t and btrfs_work_func_t 2022-07-25 17:45:36 +02:00
backref.c btrfs: sink iterator parameter to btrfs_ioctl_logical_to_ino 2022-07-25 17:45:36 +02:00
backref.h btrfs: sink iterator parameter to btrfs_ioctl_logical_to_ino 2022-07-25 17:45:36 +02:00
block-group.c btrfs: reset RO counter on block group if we fail to relocate 2022-07-27 21:23:16 +02:00
block-group.h btrfs: zoned: prevent allocation from previous data relocation BG 2022-06-21 14:43:48 +02:00
block-rsv.c btrfs: use enum for btrfs_block_rsv::type 2022-07-25 17:45:40 +02:00
block-rsv.h btrfs: use enum for btrfs_block_rsv::type 2022-07-25 17:45:40 +02:00
btrfs_inode.h btrfs: add optimized btrfs_ino() version for 64 bits systems 2022-07-25 17:45:41 +02:00
check-integrity.c btrfs: check-integrity: simplify bio allocation in btrfsic_read_block 2022-05-16 17:03:12 +02:00
check-integrity.h btrfs: check-integrity: split submit_bio from btrfsic checking 2022-05-16 17:03:12 +02:00
compression.c btrfs: don't call btrfs_page_set_checked in finish_compressed_bio_read 2022-07-25 19:56:16 +02:00
compression.h btrfs: fix repair of compressed extents 2022-07-25 19:56:16 +02:00
ctree.c btrfs: sink parameter is_data to btrfs_set_disk_extent_flags 2022-05-16 17:17:31 +02:00
ctree.h btrfs: fix repair of compressed extents 2022-07-25 19:56:16 +02:00
delalloc-space.c btrfs: convert count_max_extents() to use fs_info->max_extent_size 2022-07-25 17:45:41 +02:00
delalloc-space.h
delayed-inode.c btrfs: batch up release of reserved metadata for delayed items used for deletion 2022-07-25 17:45:37 +02:00
delayed-inode.h btrfs: reduce amount of reserved metadata for delayed item insertion 2022-07-25 17:44:36 +02:00
delayed-ref.c btrfs: switch btrfs_block_rsv::full to bool 2022-07-25 17:45:40 +02:00
delayed-ref.h btrfs: remove btrfs_delayed_extent_op::is_data 2022-05-16 17:17:31 +02:00
dev-replace.c btrfs: clean up chained assignments 2022-07-25 17:45:39 +02:00
dev-replace.h btrfs: zoned: mark block groups to copy for device-replace 2021-02-09 02:46:07 +01:00
dir-item.c btrfs: use btrfs_for_each_slot in btrfs_search_dir_index_item 2022-05-16 17:03:07 +02:00
discard.c btrfs: fix typos in comments 2021-06-22 14:11:57 +02:00
discard.h btrfs: cleanup btrfs_discard_update_discardable usage 2020-12-08 15:54:02 +01:00
disk-io.c btrfs: zoned: wait until zone is finished when allocation didn't progress 2022-07-25 17:45:42 +02:00
disk-io.h btrfs: handle allocation failure in btrfs_wq_submit_bio gracefully 2022-07-25 17:45:40 +02:00
export.c btrfs: locking: rip out path->leave_spinning 2020-12-08 15:54:02 +01:00
export.h
extent_io.c btrfs: fix repair of compressed extents 2022-07-25 19:56:16 +02:00
extent_io.h btrfs: fix repair of compressed extents 2022-07-25 19:56:16 +02:00
extent_map.c btrfs: assert we have a write lock when removing and replacing extent maps 2022-03-14 13:13:50 +01:00
extent_map.h btrfs: defrag: don't use merged extent map for their generation check 2022-02-23 17:43:13 +01:00
extent-io-tree.h btrfs: Convert from invalidatepage to invalidate_folio 2022-03-15 08:23:29 -04:00
extent-tree.c btrfs: zoned: write out partially allocated region 2022-07-25 17:45:42 +02:00
file-item.c btrfs: handle csum lookup errors properly on reads 2022-03-14 13:13:51 +01:00
file.c btrfs: don't fallback to buffered IO for NOWAIT direct IO writes 2022-07-25 17:45:40 +02:00
free-space-cache.c btrfs: clean up chained assignments 2022-07-25 17:45:39 +02:00
free-space-cache.h btrfs: change name and type of private member of btrfs_free_space_ctl 2022-01-03 15:09:50 +01:00
free-space-tree.c btrfs: use rbtree with leftmost node cached for tracking lowest block group 2022-05-16 17:03:13 +02:00
free-space-tree.h
inode-item.c btrfs: make should_throttle loop local in btrfs_truncate_inode_items 2022-01-07 14:18:25 +01:00
inode-item.h btrfs: add inode to truncate control 2022-01-07 14:18:24 +01:00
inode.c btrfs: don't call btrfs_page_set_checked in finish_compressed_bio_read 2022-07-25 19:56:16 +02:00
ioctl.c btrfs: use fs_info->max_extent_size in get_extent_max_capacity() 2022-07-25 17:45:41 +02:00
Kconfig btrfs: use generic Kconfig option for 256kB page size limit 2022-01-20 08:52:55 +02:00
locking.c btrfs: don't set lock_owner when locking extent buffer for reading 2022-06-21 14:46:56 +02:00
locking.h btrfs: assert that extent buffers are write locked instead of only locked 2021-10-26 19:08:02 +02:00
lzo.c btrfs: replace kmap() with kmap_local_page() in lzo.c 2022-07-25 17:45:33 +02:00
Makefile Kbuild: add -Wno-shift-negative-value where -Wextra is used 2022-03-13 17:30:31 +09:00
misc.h btrfs: use correct header for div_u64 in misc.h 2021-09-07 14:29:50 +02:00
ordered-data.c btrfs: remove the finish_func argument to btrfs_mark_ordered_io_finished 2022-07-25 17:45:37 +02:00
ordered-data.h btrfs: remove the finish_func argument to btrfs_mark_ordered_io_finished 2022-07-25 17:45:37 +02:00
orphan.c
print-tree.c btrfs: unify the error handling pattern for read_tree_block() 2022-03-14 13:13:53 +01:00
print-tree.h btrfs: print the actual offset in btrfs_root_name 2021-01-07 17:25:05 +01:00
props.c btrfs: move common inode creation code into btrfs_create_new_inode() 2022-05-16 17:03:08 +02:00
props.h btrfs: move common inode creation code into btrfs_create_new_inode() 2022-05-16 17:03:08 +02:00
qgroup.c btrfs: avoid blocking on space revervation when doing nowait dio writes 2022-05-16 17:03:10 +02:00
qgroup.h btrfs: avoid blocking on space revervation when doing nowait dio writes 2022-05-16 17:03:10 +02:00
raid56.c btrfs: raid56: transfer the bio counter reference to the raid submission helpers 2022-07-25 17:45:40 +02:00
raid56.h btrfs: do not return errors from raid56_parity_recover 2022-07-25 17:45:39 +02:00
rcu-string.h
ref-verify.c btrfs: stop accessing ->extent_root directly 2022-01-03 15:09:49 +01:00
ref-verify.h
reflink.c btrfs: clean up chained assignments 2022-07-25 17:45:39 +02:00
reflink.h
relocation.c btrfs: unset reloc control if transaction commit fails in prepare_to_relocate() 2022-08-17 16:18:58 +02:00
root-tree.c btrfs: avoid blocking on space revervation when doing nowait dio writes 2022-05-16 17:03:10 +02:00
scrub.c btrfs: do not return errors from raid56_parity_recover 2022-07-25 17:45:39 +02:00
send.c btrfs: send: always use the rbtree based inode ref management infrastructure 2022-07-25 17:45:42 +02:00
send.h btrfs: send: add new command FILEATTR for file attributes 2022-07-25 17:45:38 +02:00
space-info.c btrfs: zoned: activate metadata block group on flush_space 2022-07-25 17:45:42 +02:00
space-info.h btrfs: zoned: introduce space_info->active_total_bytes 2022-07-25 17:45:42 +02:00
struct-funcs.c btrfs: remove redundant check in up check_setget_bounds 2022-07-25 17:45:33 +02:00
subpage.c btrfs: remove extent writepage address space operation 2022-07-25 17:45:37 +02:00
subpage.h btrfs: make nodesize >= PAGE_SIZE case to reuse the non-subpage routine 2022-05-16 17:03:11 +02:00
super.c btrfs: use mask for all RAID1* profiles in btrfs_calc_avail_data_space 2022-07-25 17:45:38 +02:00
sysfs.c btrfs: sysfs: remove BIG_METADATA feature files 2022-07-25 17:45:39 +02:00
sysfs.h btrfs: split and refactor btrfs_sysfs_remove_devices_dir 2020-10-07 12:12:21 +02:00
transaction.c btrfs: clean up chained assignments 2022-07-25 17:45:39 +02:00
transaction.h btrfs: pass btrfs_fs_info for deleting snapshots and cleaner 2022-03-14 13:13:52 +01:00
tree-checker.c btrfs: tree-checker: check extent buffer owner against owner rootid 2022-05-16 17:03:09 +02:00
tree-checker.h btrfs: tree-checker: check extent buffer owner against owner rootid 2022-05-16 17:03:09 +02:00
tree-defrag.c btrfs: remove unnecessary extent root check in btrfs_defrag_leaves 2022-01-03 15:09:48 +01:00
tree-log.c btrfs: join running log transaction when logging new name 2022-07-25 17:45:42 +02:00
tree-log.h btrfs: tree-log: make the return value for log syncing consistent 2022-07-25 17:45:34 +02:00
tree-mod-log.c btrfs: fix race when picking most recent mod log operation for an old root 2021-04-20 19:27:17 +02:00
tree-mod-log.h btrfs: add and use helper to get lowest sequence number for the tree mod log 2021-04-19 17:25:17 +02:00
ulist.c
ulist.h
uuid-tree.c btrfs: drop the _nr from the item helpers 2022-01-03 15:09:43 +01:00
verity.c btrfs: drop the _nr from the item helpers 2022-01-03 15:09:43 +01:00
volumes.c btrfs: merge btrfs_dev_stat_print_on_error with its only caller 2022-07-25 17:45:42 +02:00
volumes.h btrfs: do not return errors from btrfs_map_bio 2022-07-25 17:45:39 +02:00
xattr.c btrfs: use btrfs_for_each_slot in btrfs_listxattr 2022-05-16 17:03:08 +02:00
xattr.h
zlib.c btrfs: zlib: replace kmap() with kmap_local_page() in zlib_decompress_bio() 2022-07-25 17:45:41 +02:00
zoned.c btrfs: zoned: wait until zone is finished when allocation didn't progress 2022-07-25 17:45:42 +02:00
zoned.h btrfs: zoned: activate metadata block group on flush_space 2022-07-25 17:45:42 +02:00
zstd.c btrfs: zstd: replace kmap() with kmap_local_page() 2022-07-25 17:45:40 +02:00