[PATCH] xfs: fix use-after-free in xfs_cui_release()

From: Ye Bin
Date: Thu Oct 10 2024 - 05:27:47 EST


From: Ye Bin <yebin10@xxxxxxxxxx>

There's issue as follows when do IO fault injection:
XFS (loop0): Filesystem has been shut down due to log error (0x2).
XFS (loop0): Please unmount the filesystem and rectify the problem(s).
XFS (loop0): Failed to recover intents
XFS (loop0): log mount finish failed
==================================================================
BUG: KASAN: slab-use-after-free in xfs_cui_release+0x20/0xe0
Read of size 4 at addr ffff88826d204098 by task kworker/u18:4/252

CPU: 7 PID: 252 Comm: kworker/u18:4 Not tainted 6.3.0-next #446
Workqueue: xfs-cil/loop0 xlog_cil_push_work
Call Trace:
<TASK>
dump_stack_lvl+0xd9/0x150
print_report+0xc1/0x5e0
kasan_report+0x96/0xc0
kasan_check_range+0x13f/0x1a0
xfs_cui_release+0x20/0xe0
xfs_cud_item_release+0x37/0x80
xfs_trans_committed_bulk+0x337/0x8f0
xlog_cil_committed+0xc08/0x1010
xlog_cil_push_work+0x1cb4/0x25f0
process_one_work+0x9cf/0x1610
worker_thread+0x63a/0x10a0
kthread+0x343/0x440
ret_from_fork+0x1f/0x30
</TASK>

Allocated by task 8537:
kasan_save_stack+0x22/0x40
kasan_set_track+0x25/0x30
__kasan_slab_alloc+0x7f/0x90
slab_post_alloc_hook+0x65/0x560
kmem_cache_alloc+0x1cf/0x440
xfs_cui_init+0x1a8/0x1e0
xlog_recover_cui_commit_pass2+0x137/0x440
xlog_recover_items_pass2+0xd8/0x310
xlog_recover_commit_trans+0x958/0xb20
xlog_recovery_process_trans+0x13a/0x1e0
xlog_recover_process_ophdr+0x1e9/0x410
xlog_recover_process_data+0x19c/0x400
xlog_recover_process+0x257/0x2e0
xlog_do_recovery_pass+0x70c/0xf90
xlog_do_log_recovery+0x9e/0x100
xlog_do_recover+0xdf/0x5a0
xlog_recover+0x2a8/0x500
xfs_log_mount+0x36e/0x790
xfs_mountfs+0x133a/0x2220
xfs_fs_fill_super+0x1376/0x1f10
get_tree_bdev+0x44a/0x770
vfs_get_tree+0x8d/0x350
path_mount+0x1228/0x1cc0
do_mount+0xf7/0x110
__x64_sys_mount+0x193/0x230
do_syscall_64+0x39/0xb0
entry_SYSCALL_64_after_hwframe+0x63/0xcd

Freed by task 8537:
kasan_save_stack+0x22/0x40
kasan_set_track+0x25/0x30
kasan_save_free_info+0x2e/0x40
__kasan_slab_free+0x11f/0x1b0
kmem_cache_free+0xf2/0x670
xfs_cui_item_free+0xa4/0xc0
xfs_cui_release+0xa0/0xe0
xlog_recover_cancel_intents.isra.0+0xf4/0x200
xlog_recover_finish+0x87f/0xa20
xfs_log_mount_finish+0x325/0x570
xfs_mountfs+0x16ba/0x2220
xfs_fs_fill_super+0x1376/0x1f10
get_tree_bdev+0x44a/0x770
vfs_get_tree+0x8d/0x350
path_mount+0x1228/0x1cc0
do_mount+0xf7/0x110
__x64_sys_mount+0x193/0x230
do_syscall_64+0x39/0xb0
entry_SYSCALL_64_after_hwframe+0x63/0xcd

As xlog_recover_process_intents() failed will trigger LOG shutdown will not
push CIL. Then xlog_recover_finish() will remove log item from AIL list and
release log item. However xlog_cil_push_work() perhaps concurrent
processing this log item, then trigger UAF.
To solve above issue, there's need to make sure all CIL is pushed before
cancel intent item.

Fixes: deb4cd8ba87f ("xfs: transfer recovered intent item ownership in ->iop_recover")
Signed-off-by: Ye Bin <yebin10@xxxxxxxxxx>
---
fs/xfs/xfs_log_recover.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 1997981827fb..54faa0608958 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3521,6 +3521,7 @@ xlog_recover_finish(
* (inode reclaim does this) before we get around to
* xfs_log_mount_cancel.
*/
+ xfs_log_force(log->l_mp, XFS_LOG_SYNC);
xlog_recover_cancel_intents(log);
xfs_alert(log->l_mp, "Failed to recover intents");
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
--
2.31.1