When a filesystem is frozen via the FIFREEZE ioctl, the superblock's write
lock is acquired and held until the filesystem is explicitly thawed via
FITHAW. Any task attempting to write to the frozen filesystem (e.g.,
calling open(O_TMPFILE) or unlink) will block in sb_start_write(), waiting
for the superblock's read lock.
Currently, percpu_rwsem_wait() puts these waiting tasks into the
TASK_UNINTERRUPTIBLE state. Since thawing a filesystem relies on an
explicit user-space action, the wait can take an arbitrary amount of time.
If this wait exceeds the hung task timeout, the watchdog fires and can
panic the kernel:
INFO: task crond:5389 blocked for more than 15 seconds.
task:crond state:D stack:23720 pid:5389 tgid:5389 ppid:1
task_flags:0x400000 flags:0x00080000
Call Trace:
__schedule+0x16dc/0x5500 kernel/sched/core.c:7234
schedule+0x164/0x2b0 kernel/sched/core.c:7326
percpu_rwsem_wait+0x32d/0x4a0 kernel/locking/percpu-rwsem.c:164
__percpu_down_read+0xf8/0x140 kernel/locking/percpu-rwsem.c:180
percpu_down_read_freezable include/linux/percpu-rwsem.h:83 [inline]
__sb_start_write include/linux/fs/super.h:19 [inline]
sb_start_write+0x18e/0x1c0 include/linux/fs/super.h:125
mnt_want_write+0x41/0x90 fs/namespace.c:494
filename_unlinkat+0x148/0x610 fs/namei.c:5562
__do_sys_unlink fs/namei.c:5620 [inline]
__se_sys_unlink+0x2e/0x140 fs/namei.c:5617
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
This behavior allows an unprivileged user to intentionally trigger a kernel
panic by freezing a user namespace mount (like tmpfs or fuse) and
attempting to write to it, leading to a local denial of service.
Fix this by using TASK_IDLE (which is TASK_UNINTERRUPTIBLE | TASK_NOLOAD)
instead of TASK_UNINTERRUPTIBLE when freeze is true. This explicitly tells
the hung task watchdog to ignore these tasks, preventing false positive
panics while preserving the freeze/thaw mechanics and system suspend
capabilities (TASK_FREEZABLE). Since freeze is only true when called from
percpu_down_read_freezable() (used exclusively by __sb_start_write()), this
change safely and specifically targets tasks waiting on a frozen
superblock.
Fixes: 559b3bbfa978 ("locking/percpu-rwsem: add freezable alternative to down_read")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: syzbot+b3fba2e269970207b61d@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b3fba2e269970207b61d
Link: https://syzkaller.appspot.com/ai_job?id=1f731a02-676c-4f22-a26c-1ff8c1dd0a49
To: "Boqun Feng"
To:
To: "Ingo Molnar"
To: "Peter Zijlstra"
To: "Will Deacon"
To: "James Bottomley"
Cc: "Waiman Long"
---
diff --git a/kernel/locking/percpu-rwsem.c b/kernel/locking/percpu-rwsem.c
index f7e152c40..57e24fdc0 100644
--- a/kernel/locking/percpu-rwsem.c
+++ b/kernel/locking/percpu-rwsem.c
@@ -157,8 +157,7 @@ static void percpu_rwsem_wait(struct percpu_rw_semaphore *sem, bool reader,
spin_unlock_irq(&sem->waiters.lock);
while (wait) {
- set_current_state(TASK_UNINTERRUPTIBLE |
- (freeze ? TASK_FREEZABLE : 0));
+ set_current_state(freeze ? (TASK_IDLE | TASK_FREEZABLE) : TASK_UNINTERRUPTIBLE);
if (!smp_load_acquire(&wq_entry.private))
break;
schedule();
base-commit: 075b74841bd0065a3bda3440873c747938e69b68
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).
See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
The person who has signed off on the patch is responsible for
addressing comments.
syzbot engineers can be reached at syzkaller@googlegroups.com.