Commit 54b6bf14 authored by Long Li's avatar Long Li
Browse files

xfs: fix a UAF in xfs_iflush_abort_clean

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I8LHTR


CVE: NA

--------------------------------

KASAN reported a UAF bug while fault injection test:

 ==================================================================
 BUG: KASAN: slab-use-after-free in __list_del_entry_valid_or_report+0x63/0x200
 Read of size 8 at addr ffff888102aae0e8 by task kworker/2:1/48

 CPU: 2 PID: 48 Comm: kworker/2:1 Not tainted 6.6.0-01347-g0684c49b89e7-dirty #8
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
 BIOS ?-20190727_073836-buildvm-ppc64le-16.ppc.fedoraproject.org-3.fc31 04/01/2014
 Workqueue: xfs-reclaim/sda xfs_reclaim_worker
 Call Trace:
  <TASK>
  dump_stack_lvl+0x7f/0xb0
  print_report+0x12b/0x930
  kasan_report+0xc2/0x120
  __asan_load8+0x9d/0x140
  __list_del_entry_valid_or_report+0x63/0x200
  xfs_iflush_abort_clean+0x8e/0x100
  xfs_iflush_abort+0xa0/0x170
  xfs_iflush_shutdown_abort+0x17a/0x220
  xfs_icwalk_ag+0xa4b/0xed0
  xfs_icwalk+0x97/0xf0
  xfs_reclaim_worker+0x25/0x40
  process_scheduled_works+0x3a8/0x950
  worker_thread+0x302/0x710
  kthread+0x1f1/0x270
  ret_from_fork+0x52/0x70
  ret_from_fork_asm+0x11/0x20
  </TASK>

 Allocated by task 733:
  kasan_save_stack+0x2a/0x60
  kasan_set_track+0x2d/0x40
  kasan_save_alloc_info+0x23/0x40
  __kasan_slab_alloc+0x92/0xb0
  kmem_cache_alloc+0x229/0xaf0
  _xfs_buf_alloc+0x55/0x600
  xfs_buf_get_map+0xc29/0x1b30
  xfs_trans_get_buf_map+0x1bd/0x4b0
  xfs_ialloc_inode_init+0x2e6/0x690
  xfs_ialloc_ag_alloc+0x3ae/0xb00
  xfs_dialloc+0x786/0xda0
  xfs_create+0x4b7/0xaf0
  xfs_generic_create+0x538/0x6f0
  xfs_vn_create+0x1f/0x30
  path_openat+0x13e2/0x2150
  do_filp_open+0x16a/0x240
  do_sys_openat2+0x3be/0x4e0
  do_sys_open+0xa6/0x100
  __x64_sys_open+0x52/0x60
  do_syscall_64+0x39/0x80
  entry_SYSCALL_64_after_hwframe+0x63/0xcd

 Freed by task 0:
  kasan_save_stack+0x2a/0x60
  kasan_set_track+0x2d/0x40
  kasan_save_free_info+0x33/0x60
  __kasan_slab_free+0x171/0x2b0
  kmem_cache_free+0x313/0x8d0
  xfs_buf_free_callback+0x64/0x80
  rcu_do_batch+0x393/0xb10
  rcu_core+0x599/0x930
  rcu_core_si+0x16/0x20
  __do_softirq+0x127/0x5a0

 Last potentially related work creation:
  kasan_save_stack+0x2a/0x60
  __kasan_record_aux_stack+0xba/0x100
  kasan_record_aux_stack_noalloc+0x13/0x20
  __call_rcu_common.constprop.0+0xb2/0xdd0
  call_rcu+0x16/0x20
  xfs_buf_free+0x70/0x1d0
  xfs_buf_rele+0x44d/0xc00
  xfs_buf_ioend+0x2f2/0x1350
  xfs_buf_ioend_fail+0x77/0x190
  __xfs_buf_submit+0x4cd/0x4e0
  xfs_buf_delwri_submit_buffers+0x241/0x8b0
  xfs_buf_delwri_submit_nowait+0x18/0x30
  xfsaild+0x861/0x1720
  kthread+0x1f1/0x270
  ret_from_fork+0x52/0x70
  ret_from_fork_asm+0x11/0x20

 Second to last potentially related work creation:
  kasan_save_stack+0x2a/0x60
  __kasan_record_aux_stack+0xba/0x100
  kasan_record_aux_stack_noalloc+0x13/0x20
  insert_work+0x2d/0x160
  __queue_work+0x7b1/0x9d0
  queue_work_on+0x91/0xa0
  xfs_buf_bio_end_io+0x191/0x1a0
  bio_endio+0x403/0x440
  blk_update_request+0x228/0xa90
  scsi_end_request+0x59/0x310
  scsi_io_completion+0xec/0xbb0
  scsi_finish_command+0x18d/0x2b0
  scsi_complete+0xd2/0x1f0
  blk_complete_reqs+0x9e/0xc0
  blk_done_softirq+0x25/0x30
  __do_softirq+0x127/0x5a0

 The buggy address belongs to the object at ffff888102aae000
  which belongs to the cache xfs_buf of size 376
 The buggy address is located 232 bytes inside of
  freed 376-byte region [ffff888102aae000, ffff888102aae178)

 The buggy address belongs to the physical page:
 page:000000005e670ef6 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x102aae
 head:000000005e670ef6 order:1 entire_mapcount:0 nr_pages_mapped:0 pincount:0
 flags: 0x2fffff80000840(slab|head|node=0|zone=2|lastcpupid=0x1fffff)
 page_type: 0xffffffff()
 raw: 002fffff80000840 ffff8881009c32c0 dead000000000122 0000000000000000
 raw: 0000000000000000 0000000080120012 00000001ffffffff 0000000000000000
 page dumped because: kasan: bad access detected

 Memory state around the buggy address:
  ffff888102aadf80: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
  ffff888102aae000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 >ffff888102aae080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                                           ^
  ffff888102aae100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fc
  ffff888102aae180: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
 ==================================================================
This is a low probability problem, it tooks me a long time to find the
process that the problem occurred:

1. When creating a new file, if there are no free inodes, we need to
allocate a new chunk.  The buf item and inode items associated with inode
will be submitted to CIL independently. If all goes well, both the buf item
and the inode item will be inserted into the AIL, and the buf item will be
in front of the inode item.

2. At the first time, xfsaild only pushed buf item. If an error occurs
while writing back the inode buffer, the inode item will be set XFS_LI_FAILED
in xfs_buf_inode_io_fail() when buf io end, and the buf item will remain
in the AIL.

3. At the second time, xfsaild only pushed buf item again, while writing
back the inode buffer and the log has shut down, the inode buffer will be
set XBF_STALE and the buf item is removed from AIL when buf io end. Because
of inode is not flushed, ili_last_fields in xfs_inode is still 0, so inode
item will left in AIL.

4. Concurrently, a new transaction log inode that in the same cluster as
the previous inode, it will get the same inode buffer in xfs_buf_find(),
_XBF_INODES flag will be cleared in xfs_buf_find() due to buffer is staled.

5. At the third time, xfsaild push the inode item that has marked
XFS_LI_FAILED, AIL will resubmit the inode item in xfsaild_resubmit_item().
It will go to the wrong code path due to inode buffer missing _XBF_INODES
flag, all inode items that in bp->b_li_list will be reduced the references
to buffer, and inode item's li_buf set to null, but inode item still in
bp->b_li_list. After all reference count decreasing the inode buffer will
be freed.

6. When xfs reclaim inode, remove inode item from bp->b_li_list will cause
a uaf xfs_iflush_abort_clean().

Fix it by add xfs shutdown condition check in xfs_buf_find_lock(), if it
has been shutdown, it is useless to get the buffer. While the inode item
is still reference to the inode buffer, the _XBF_INODES flag will not be
missing.

Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent 50fab721
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment