Commit 1f403b90 authored by Long Li's avatar Long Li
Browse files

xfs: fix a UAF in xfs_iflush_abort_clean

Offering: HULK
hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6I11V



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

KASAN reported a UAF bug while fault injection test:

 ==================================================================
 BUG: KASAN: use-after-free in __list_del_entry_valid+0x2b1/0x2c0
 Read of size 8 at addr ffff888023edb888 by task kworker/0:1/34

 CPU: 0 PID: 34 Comm: kworker/0:1 Not tainted 5.10.0-07305-g4c00b418452b-dirty #369
 Workqueue: xfs-reclaim/sda xfs_reclaim_worker
 Call Trace:
  dump_stack+0x115/0x16b
  print_address_description.constprop.0+0x2c/0x450
  kasan_report.cold+0x5d/0xdb
  __asan_report_load8_noabort+0x20/0x30
  __list_del_entry_valid+0x2b1/0x2c0
  xfs_iflush_abort_clean+0x11c/0x290
  xfs_iflush_abort+0xd2/0x2c0
  xfs_iflush_shutdown_abort+0x2e3/0x580
  xfs_icwalk_ag+0xe9d/0x1a00
  xfs_reclaim_worker+0x29/0x50
  process_one_work+0x71f/0x11d0
  worker_thread+0x5cb/0x10a0
  kthread+0x35b/0x490
  ret_from_fork+0x1f/0x30

 Allocated by task 642:
  kasan_save_stack+0x23/0x60
  __kasan_kmalloc.constprop.0+0xd9/0x140
  kasan_slab_alloc+0x12/0x20
  kmem_cache_alloc+0x1c4/0xa50
  _xfs_buf_alloc+0x72/0xd50
  xfs_buf_get_map+0x156/0x7c0
  xfs_trans_get_buf_map+0x41c/0x8c0
  xfs_ialloc_inode_init+0x455/0xaf0
  xfs_ialloc_ag_alloc+0x71f/0x1790
  xfs_dialloc+0x3f9/0x8a0
  xfs_ialloc+0x12e/0x1970
  xfs_dir_ialloc+0x144/0x730
  xfs_create+0x623/0xe80
  xfs_generic_create+0x571/0x820
  xfs_vn_create+0x31/0x40
  path_openat+0x209d/0x3b10
  do_filp_open+0x1c2/0x2e0
  do_sys_openat2+0x4fc/0x900
  do_sys_open+0xd8/0x150
  __x64_sys_open+0x87/0xd0
  do_syscall_64+0x45/0x70
  entry_SYSCALL_64_after_hwframe+0x61/0xc6

 The buggy address belongs to the object at ffff888023edb780
  which belongs to the cache xfs_buf of size 392
 The buggy address is located 264 bytes inside of
  392-byte region [ffff888023edb780, ffff888023edb908)
 The buggy address belongs to the page:
 page:ffffea00008fb600 refcount:1 mapcount:0 mapping:0000000000000000
 index:0xffff888023edb780 pfn:0x23ed8
 head:ffffea00008fb600 order:2 compound_mapcount:0 compound_pincount:0
 flags: 0x1fffff80010200(slab|head|node=0|zone=1|lastcpupid=0x1fffff)
 raw: 001fffff80010200 ffffea00008fb008 ffff888019016050 ffff888018ff4300
 raw: ffff888023edb780 000000000013000d 00000001ffffffff 0000000000000000
 page dumped because: kasan: bad access detected

 Memory state around the buggy address:
  ffff888023edb780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff888023edb800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 >ffff888023edb880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                       ^
  ffff888023edb900: fb fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
  ffff888023edb980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ==================================================================

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(), 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 8fdd98e8
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment