In the Linux kernel, the following vulnerability has been resolved:
f2fs: fix race in concurrent f2fsstopgc_thread
In my test case, concurrent calls to f2fs shutdown report the following stack trace:
Oops: general protection fault, probably for non-canonical address 0xc6cfff63bb5513fc: 0000 [#1] PREEMPT SMP PTI CPU: 0 UID: 0 PID: 678 Comm: f2fsrepshutdo Not tainted 6.12.0-rc5-next-20241029-g6fb2fa9805c5-dirty #85 Call Trace: <TASK> ? showregs+0x8b/0xa0 ? _diebody+0x26/0xa0 ? dieaddr+0x54/0x90 ? excgeneralprotection+0x24b/0x5c0 ? asmexcgeneralprotection+0x26/0x30 ? kthreadstop+0x46/0x390 f2fsstopgcthread+0x6c/0x110 f2fsdoshutdown+0x309/0x3a0 f2fsiocshutdown+0x150/0x1c0 _f2fsioctl+0xffd/0x2ac0 f2fsioctl+0x76/0xe0 vfsioctl+0x23/0x60 _x64sysioctl+0xce/0xf0 x64syscall+0x2b1b/0x4540 dosyscall64+0xa7/0x240 entrySYSCALL64afterhwframe+0x76/0x7e
The root cause is a race condition in f2fsstopgc_thread() called from different f2fs shutdown paths:
[CPU0] [CPU1] ---------------------- ----------------------- f2fsstopgcthread f2fsstopgcthread gcth = sbi->gcthread gcth = sbi->gcthread kfree(gcth) sbi->gcthread = NULL < gcth != NULL > kthreadstop(gcth->f2fsgc_task) //UAF
The commit c7f114d864ac ("f2fs: fix to avoid use-after-free in f2fsstopgc_thread()") attempted to fix this issue by using a read semaphore to prevent races between shutdown and remount threads, but it fails to prevent all race conditions.
Fix it by converting to write lock of sumount in f2fsdo_shutdown().