[PATCH] ipc: fix hung task in copy_ipcs()

From: Changyu Li via B4 Relay

Date: Tue Aug 11 2026 - 04:17:19 EST


From: Changyu Li <ihaveihaveihavea@xxxxxxxxx>

When the user_ns's UCOUNT_IPC_NAMESPACES limit is reached,
copy_ipcs eventually calls flush_work(&free_ipc_work) to wait for
in-flight work to reduce the number of ipc_namespaces so it can proceed.
Unfortunately flush_work() enters uninterruptible sleep and if there
are enough pending items to be freed by free_ipc_work then this would
trip hung task watchdog.

INFO: task blocked for more than 143 seconds.
Not tainted syzkaller #0
task:syz-executor845 state:D stack:27496 pid:5856
Call Trace:
<TASK>
__flush_work+0x9c2/0xd70 kernel/workqueue.c:4431
create_ipc_ns ipc/namespace.c:55 [inline]
copy_ipcs+0x19b/0x6c0 ipc/namespace.c:116
create_new_namespaces+0x210/0x6b0 kernel/nsproxy.c:112
unshare_nsproxy_namespaces+0x149/0x190 kernel/nsproxy.c:234
ksys_unshare+0x5a7/0x950 kernel/fork.c:3291
</TASK>

Replace the uninterruptible flush_work() with a polling loop that
checks if there's an in-flight free_ipc_work. If there is then wait
interruptibly a short interval for forward progress in free_ipc_work
and retry.

If free_ipc_work is not in-flight nothing will free up quota so bail
with -ENOSPC as before. Otherwise wait interruptibly to not trip hung
task watchdog.

Reported-by: syzbot+97a62389c5611b0477f3@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=97a62389c5611b0477f3
Signed-off-by: Changyu Li <ihaveihaveihavea@xxxxxxxxx>
---
ipc/namespace.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/ipc/namespace.c b/ipc/namespace.c
index 1e71353bdb..e8ea422d79 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -26,6 +26,8 @@
static void free_ipc(struct work_struct *unused);
static DECLARE_WORK(free_ipc_work, free_ipc);

+#define FREE_IPC_WAIT_JIFFIES 5
+
static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns)
{
return inc_ucount(ns, current_euid(), UCOUNT_IPC_NAMESPACES);
@@ -49,12 +51,19 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
if (!ucounts) {
/*
* IPC namespaces are freed asynchronously, by free_ipc_work.
- * If frees were pending, flush_work will wait, and
- * return true. Fail the allocation if no frees are pending.
+ * If there is in flight free_ipc_work, we'll wait for it to
+ * make progress otherwise fail immediately.
*/
- if (flush_work(&free_ipc_work))
- goto again;
- goto fail;
+ if (!work_busy(&free_ipc_work))
+ goto fail;
+
+ schedule_timeout_interruptible(FREE_IPC_WAIT_JIFFIES);
+ if (signal_pending(current)) {
+ err = -ERESTARTSYS;
+ goto fail;
+ }
+
+ goto again;
}

err = -ENOMEM;

---
base-commit: 3d08ff75a47a3e7e2ab45a3bcab6723b4d906422
change-id: 20260811-work-53289e81bd3f

Best regards,
--
Changyu Li <ihaveihaveihavea@xxxxxxxxx>