In the Linux kernel, the following vulnerability has been resolved:
btrfs: wait for fixup workers before stopping cleaner kthread during umount
During unmount, at close_ctree(), we have the following steps in this order:
1) Park the cleaner kthread - this doesn't destroy the kthread, it basically halts its execution (wake ups against it work but do nothing);
2) We stop the cleaner kthread - this results in freeing the respective struct task_struct;
3) We call btrfsstopall_workers() which waits for any jobs running in all the work queues and then free the work queues.
Syzbot reported a case where a fixup worker resulted in a crash when doing a delayed iput on its inode while attempting to wake up the cleaner at btrfsadddelayediput(), because the taskstruct of the cleaner kthread was already freed. This can happen during unmount because we don't wait for any fixup workers still running before we call kthread_stop() against the cleaner kthread, which stops and free all its resources.
Fix this by waiting for any fixup workers at closectree() before we call kthreadstop() against the cleaner and run pending delayed iputs.
The stack traces reported by syzbot were the following:
BUG: KASAN: slab-use-after-free in _lockacquire+0x77/0x2050 kernel/locking/lockdep.c:5065 Read of size 8 at addr ffff8880272a8a18 by task kworker/u8:3/52
CPU: 1 UID: 0 PID: 52 Comm: kworker/u8:3 Not tainted 6.12.0-rc1-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024 Workqueue: btrfs-fixup btrfsworkhelper Call Trace: <TASK> _dumpstack lib/dumpstack.c:94 [inline] dumpstacklvl+0x241/0x360 lib/dumpstack.c:120 printaddressdescription mm/kasan/report.c:377 [inline] printreport+0x169/0x550 mm/kasan/report.c:488 kasanreport+0x143/0x180 mm/kasan/report.c:601 _lockacquire+0x77/0x2050 kernel/locking/lockdep.c:5065 lockacquire+0x1ed/0x550 kernel/locking/lockdep.c:5825 _rawspinlockirqsave include/linux/spinlockapismp.h:110 [inline] _rawspinlockirqsave+0xd5/0x120 kernel/locking/spinlock.c:162 classrawspinlockirqsaveconstructor include/linux/spinlock.h:551 [inline] trytowakeup+0xb0/0x1480 kernel/sched/core.c:4154 btrfswritepagefixupworker+0xc16/0xdf0 fs/btrfs/inode.c:2842 btrfsworkhelper+0x390/0xc50 fs/btrfs/async-thread.c:314 processonework kernel/workqueue.c:3229 [inline] processscheduledworks+0xa63/0x1850 kernel/workqueue.c:3310 workerthread+0x870/0xd30 kernel/workqueue.c:3391 kthread+0x2f0/0x390 kernel/kthread.c:389 retfromfork+0x4b/0x80 arch/x86/kernel/process.c:147 retfromforkasm+0x1a/0x30 arch/x86/entry/entry_64.S:244 </TASK>
Allocated by task 2: kasansavestack mm/kasan/common.c:47 [inline] kasansavetrack+0x3f/0x80 mm/kasan/common.c:68 unpoisonslabobject mm/kasan/common.c:319 [inline] _kasanslaballoc+0x66/0x80 mm/kasan/common.c:345 kasanslaballoc include/linux/kasan.h:247 [inline] slabpostallochook mm/slub.c:4086 [inline] slaballocnode mm/slub.c:4135 [inline] kmemcacheallocnodenoprof+0x16b/0x320 mm/slub.c:4187 alloctaskstructnode kernel/fork.c:180 [inline] duptaskstruct+0x57/0x8c0 kernel/fork.c:1107 copyprocess+0x5d1/0x3d50 kernel/fork.c:2206 kernelclone+0x223/0x880 kernel/fork.c:2787 kernelthread+0x1bc/0x240 kernel/fork.c:2849 createkthread kernel/kthread.c:412 [inline] kthreadd+0x60d/0x810 kernel/kthread.c:765 retfromfork+0x4b/0x80 arch/x86/kernel/process.c:147 retfromforkasm+0x1a/0x30 arch/x86/entry/entry_64.S:244
Freed by task 61: kasansavestack mm/kasan/common.c:47 [inline] kasansavetrack+0x3f/0x80 mm/kasan/common.c:68 kasansavefreeinfo+0x40/0x50 mm/kasan/generic.c:579 poisonslabobject mm/kasan/common.c:247 [inline] _kasanslabfree+0x59/0x70 mm/kasan/common.c:264 kasanslabfree include/linux/kasan.h:230 [inline] slabfreeh ---truncated---