* FAILED: patch "[PATCH] net/9p: fix infinite loop in p9_client_rpc on fatal signal" failed to apply to 5.10-stable tree
@ 2026-07-20 14:32 gregkh
2026-07-25 10:55 ` [PATCH 5.10.y 1/2] net/9p: fix infinite loop in p9_client_rpc on fatal signal Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: gregkh @ 2026-07-20 14:32 UTC (permalink / raw)
To: kovalev, asmadeus; +Cc: stable
The patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 6b4f48728faa8bb514368f7eacda05565dea8696
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026072024-extending-list-343c@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6b4f48728faa8bb514368f7eacda05565dea8696 Mon Sep 17 00:00:00 2001
From: Vasiliy Kovalev <kovalev@altlinux.org>
Date: Wed, 15 Apr 2026 18:52:37 +0300
Subject: [PATCH] net/9p: fix infinite loop in p9_client_rpc on fatal signal
When p9_client_rpc() is called with type P9_TFLUSH and the transport
has no peer (e.g. fd transport backed by pipes with no 9p server),
a fatal signal causes an infinite loop:
again:
err = io_wait_event_killable(req->wq, ...)
/* SIGKILL wakes the task, returns -ERESTARTSYS */
if (err == -ERESTARTSYS && c->status == Connected &&
type == P9_TFLUSH) {
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);
goto again;
}
clear_thread_flag() clears TIF_SIGPENDING before jumping back to
io_wait_event_killable(). signal_pending_state() checks TIF_SIGPENDING,
finds it zero, and the task goes to sleep again. The task can only wake
on the next signal delivery that calls signal_wake_up() and sets
TIF_SIGPENDING again. When that happens the loop repeats, clears
TIF_SIGPENDING, and sleeps again indefinitely.
This is triggered in practice by coredump_wait(): when a thread in a
multi-threaded process causes a coredump (e.g. via SIGSYS from Syscall
User Dispatch), coredump_wait() sends SIGKILL to all other threads and
waits for them to call mm_release(). If one of those threads is blocked
in p9_client_rpc() over an fd transport with no peer, it enters the
P9_TFLUSH loop and never calls mm_release(), so coredump_wait() stalls
forever:
INFO: task syz.0.18:676 blocked for more than 143 seconds.
Not tainted 6.12.77+ #1
task:syz.0.18 state:D stack:27600 pid:676 tgid:673 ppid:630 flags:0x00000004
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5344 [inline]
__schedule+0xcb4/0x5d50 kernel/sched/core.c:6724
__schedule_loop kernel/sched/core.c:6801 [inline]
schedule+0xe5/0x350 kernel/sched/core.c:6816
schedule_timeout+0x253/0x290 kernel/time/timer.c:2593
do_wait_for_common kernel/sched/completion.c:95 [inline]
__wait_for_common+0x409/0x600 kernel/sched/completion.c:116
wait_for_common kernel/sched/completion.c:127 [inline]
wait_for_completion_state+0x1d/0x40 kernel/sched/completion.c:264
coredump_wait fs/coredump.c:448 [inline]
do_coredump+0x854/0x4350 fs/coredump.c:629
get_signal+0x1425/0x2730 kernel/signal.c:2903
arch_do_signal_or_restart+0x81/0x880 arch/x86/kernel/signal.c:337
exit_to_user_mode_loop kernel/entry/common.c:111 [inline]
exit_to_user_mode_prepare include/linux/entry-common.h:328 [inline]
__syscall_exit_to_user_mode_work kernel/entry/common.c:207 [inline]
syscall_exit_to_user_mode+0xf9/0x160 kernel/entry/common.c:218
do_syscall_64+0x102/0x220 arch/x86/entry/common.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
Fix: check fatal_signal_pending() before clearing TIF_SIGPENDING in the
P9_TFLUSH retry loop. At that point TIF_SIGPENDING is still set, so
fatal_signal_pending() works correctly. If a fatal signal is pending,
jump to recalc_sigpending to restore TIF_SIGPENDING and return
-ERESTARTSYS to the caller.
The same defect is present in stable kernels back to 5.4. On those
kernels the infinite loop is broken earlier by a second SIGKILL from
the parent process (e.g. kill_and_wait() retrying after a timeout),
resulting in a zombie process and a shutdown delay rather than a
permanent D-state hang, but the underlying flaw is the same.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Fixes: 91b8534fa8f5 ("9p: make rpc code common and rework flush code")
Closes: https://syzkaller.appspot.com/bug?extid=3ce7863f8fc836a427e7
Cc: stable@vger.kernel.org
Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
Message-ID: <20260415155237.182891-1-kovalev@altlinux.org>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
diff --git a/net/9p/client.c b/net/9p/client.c
index b7d947910037..69d3efd340c0 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -600,6 +600,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
if (err == -ERESTARTSYS && c->status == Connected &&
type == P9_TFLUSH) {
+ if (fatal_signal_pending(current))
+ goto recalc_sigpending;
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);
goto again;
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 5.10.y 1/2] net/9p: fix infinite loop in p9_client_rpc on fatal signal 2026-07-20 14:32 FAILED: patch "[PATCH] net/9p: fix infinite loop in p9_client_rpc on fatal signal" failed to apply to 5.10-stable tree gregkh @ 2026-07-25 10:55 ` Sasha Levin 2026-07-25 10:55 ` [PATCH 5.10.y 2/2] [AUTOMATED CONFLICT RESOLUTION] Documentation for 6b4f48728faa8bb514368f7eacda05565dea8696 Sasha Levin 0 siblings, 1 reply; 3+ messages in thread From: Sasha Levin @ 2026-07-25 10:55 UTC (permalink / raw) To: stable; +Cc: Vasiliy Kovalev, Dominique Martinet, Sasha Levin From: Vasiliy Kovalev <kovalev@altlinux.org> [ Upstream commit 6b4f48728faa8bb514368f7eacda05565dea8696 ] When p9_client_rpc() is called with type P9_TFLUSH and the transport has no peer (e.g. fd transport backed by pipes with no 9p server), a fatal signal causes an infinite loop: again: err = io_wait_event_killable(req->wq, ...) /* SIGKILL wakes the task, returns -ERESTARTSYS */ if (err == -ERESTARTSYS && c->status == Connected && type == P9_TFLUSH) { sigpending = 1; clear_thread_flag(TIF_SIGPENDING); goto again; } clear_thread_flag() clears TIF_SIGPENDING before jumping back to io_wait_event_killable(). signal_pending_state() checks TIF_SIGPENDING, finds it zero, and the task goes to sleep again. The task can only wake on the next signal delivery that calls signal_wake_up() and sets TIF_SIGPENDING again. When that happens the loop repeats, clears TIF_SIGPENDING, and sleeps again indefinitely. This is triggered in practice by coredump_wait(): when a thread in a multi-threaded process causes a coredump (e.g. via SIGSYS from Syscall User Dispatch), coredump_wait() sends SIGKILL to all other threads and waits for them to call mm_release(). If one of those threads is blocked in p9_client_rpc() over an fd transport with no peer, it enters the P9_TFLUSH loop and never calls mm_release(), so coredump_wait() stalls forever: INFO: task syz.0.18:676 blocked for more than 143 seconds. Not tainted 6.12.77+ #1 task:syz.0.18 state:D stack:27600 pid:676 tgid:673 ppid:630 flags:0x00000004 Call Trace: <TASK> context_switch kernel/sched/core.c:5344 [inline] __schedule+0xcb4/0x5d50 kernel/sched/core.c:6724 __schedule_loop kernel/sched/core.c:6801 [inline] schedule+0xe5/0x350 kernel/sched/core.c:6816 schedule_timeout+0x253/0x290 kernel/time/timer.c:2593 do_wait_for_common kernel/sched/completion.c:95 [inline] __wait_for_common+0x409/0x600 kernel/sched/completion.c:116 wait_for_common kernel/sched/completion.c:127 [inline] wait_for_completion_state+0x1d/0x40 kernel/sched/completion.c:264 coredump_wait fs/coredump.c:448 [inline] do_coredump+0x854/0x4350 fs/coredump.c:629 get_signal+0x1425/0x2730 kernel/signal.c:2903 arch_do_signal_or_restart+0x81/0x880 arch/x86/kernel/signal.c:337 exit_to_user_mode_loop kernel/entry/common.c:111 [inline] exit_to_user_mode_prepare include/linux/entry-common.h:328 [inline] __syscall_exit_to_user_mode_work kernel/entry/common.c:207 [inline] syscall_exit_to_user_mode+0xf9/0x160 kernel/entry/common.c:218 do_syscall_64+0x102/0x220 arch/x86/entry/common.c:84 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK> Fix: check fatal_signal_pending() before clearing TIF_SIGPENDING in the P9_TFLUSH retry loop. At that point TIF_SIGPENDING is still set, so fatal_signal_pending() works correctly. If a fatal signal is pending, jump to recalc_sigpending to restore TIF_SIGPENDING and return -ERESTARTSYS to the caller. The same defect is present in stable kernels back to 5.4. On those kernels the infinite loop is broken earlier by a second SIGKILL from the parent process (e.g. kill_and_wait() retrying after a timeout), resulting in a zombie process and a shutdown delay rather than a permanent D-state hang, but the underlying flaw is the same. Found by Linux Verification Center (linuxtesting.org) with Syzkaller. Fixes: 91b8534fa8f5 ("9p: make rpc code common and rework flush code") Closes: https://syzkaller.appspot.com/bug?extid=3ce7863f8fc836a427e7 Cc: stable@vger.kernel.org Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org> Message-ID: <20260415155237.182891-1-kovalev@altlinux.org> Signed-off-by: Dominique Martinet <asmadeus@codewreck.org> [ adjusted context to match the older parenthesized `if ((err == -ERESTARTSYS) && ...)` condition style ] Signed-off-by: Sasha Levin <sashal@kernel.org> --- net/9p/client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/9p/client.c b/net/9p/client.c index f49f5fd98ad820..1bcab7176e5f89 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -771,6 +771,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) if ((err == -ERESTARTSYS) && (c->status == Connected) && (type == P9_TFLUSH)) { + if (fatal_signal_pending(current)) + goto recalc_sigpending; sigpending = 1; clear_thread_flag(TIF_SIGPENDING); goto again; -- 2.53.0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 5.10.y 2/2] [AUTOMATED CONFLICT RESOLUTION] Documentation for 6b4f48728faa8bb514368f7eacda05565dea8696 2026-07-25 10:55 ` [PATCH 5.10.y 1/2] net/9p: fix infinite loop in p9_client_rpc on fatal signal Sasha Levin @ 2026-07-25 10:55 ` Sasha Levin 0 siblings, 0 replies; 3+ messages in thread From: Sasha Levin @ 2026-07-25 10:55 UTC (permalink / raw) To: stable; +Cc: Sasha Levin This commit documents the automated conflict resolution performed by claude for upstream commit 6b4f48728faa8bb514368f7eacda05565dea8696. claude's resolution process: ================================================================================ Build still in progress (no output yet). Waiting for completion — I'll report once it lands. ================================================================================ Backport verification analysis (via claude): ================================================================================ ## Verdict: correct, faithful, minimal — context-only adaptation ### 1. Intent preservation The upstream fix is two lines added as the first statement inside the `type == P9_TFLUSH` retry branch of `p9_client_rpc()`. The backport adds those **exact same two lines, byte-identical, at the exact same logical position** (`net/9p/client.c:773-774`): ```c if ((err == -ERESTARTSYS) && (c->status == Connected) && (type == P9_TFLUSH)) { if (fatal_signal_pending(current)) goto recalc_sigpending; sigpending = 1; clear_thread_flag(TIF_SIGPENDING); goto again; } ``` The `recalc_sigpending:` label exists in 5.10's `p9_client_rpc()` at `client.c:797`, in the same relative position and with byte-identical body to upstream: ```c recalc_sigpending: if (sigpending) { spin_lock_irqsave(¤t->sighand->siglock, flags); recalc_sigpending(); spin_unlock_irqrestore(¤t->sighand->siglock, flags); } if (err < 0) goto reterr; ``` So both post-conditions the commit message promises hold in 5.10: - `sigpending == 1` (a signal was pending at RPC entry) → `recalc_sigpending()` restores `TIF_SIGPENDING`. - `sigpending == 0` → `TIF_SIGPENDING` was never cleared on this path, so it's still set. Correct either way. - `err == -ERESTARTSYS < 0` → `goto reterr` → `p9_tag_remove()` → `ERR_PTR(safe_errno(-ERESTARTSYS))`. `safe_errno()` (`client.c:94`) passes `-512` through unchanged (`-512 > -MAX_ERRNO`), so the caller genuinely sees `-ERESTARTSYS`, not a mangled `-EPROTO`. ### 2. Differences vs upstream — all pre-existing context, none functional The only diff-level deltas are blob hashes, hunk line numbers (600 → 771), and the `if` condition's parenthesization: | upstream | 5.10 | |---|---| | `if (err == -ERESTARTSYS && c->status == Connected &&`<br>` type == P9_TFLUSH) {` | `if ((err == -ERESTARTSYS) && (c->status == Connected)`<br>` && (type == P9_TFLUSH)) {` | That is purely the v5.17-era 9p checkpatch-style reflow, semantically identical. Other pre-existing divergences in the enclosing function (`wait_event_killable` vs `io_wait_event_killable`, no `READ_ONCE(req->status)`, `p9_req_put(req)` vs `p9_req_put(c, req)`, `p9_tag_remove()` vs `p9_req_put()` at `reterr:`) are all upstream-only refactors from 6.1/6.2 and are **orthogonal to this fix** — none of them is touched, and none changes the signal semantics the fix depends on. Critically, the killable-wait semantics are the same: 5.10's `wait_event_killable` returns `-ERESTARTSYS` only via `signal_pending_state(TASK_KILLABLE, ...)`, which for `TASK_KILLABLE` (`TASK_WAKEKILL|TASK_UNINTERRUPTIBLE`, no `TASK_INTERRUPTIBLE` bit) requires `__fatal_signal_pending()`. So at the new check `TIF_SIGPENDING` is still set and `SIGKILL` is still in `current->pending.signal` — nothing between the wait returning and the check dequeues signals or calls `recalc_sigpending()`. `fatal_signal_pending()` therefore evaluates exactly as upstream intends. `io_wait_event_killable` differs only in io_schedule accounting. ### 3. Concerns checked and cleared - **Build/compile**: `<linux/sched/signal.h>` is already included (`client.c:20`), and `signal_pending()` is already used ~25 lines above in the same function — `fatal_signal_pending()` needs no new include. `goto recalc_sigpending` targets a label already jumped to by the pre-existing `trans_mod->request()` failure path, so no "label used but not defined". Label vs. function name `recalc_sigpending` live in different C namespaces (already the case pre-patch). `git show --check` is clean; diffstat is exactly `1 file changed, 2 insertions(+)` — no stray hunks. - **Applicability**: `Fixes: 91b8534fa8f5` (v3.7) is confirmed an ancestor of HEAD, and the commit message explicitly states the defect reaches back to 5.4. 5.10.261 is in scope. - **No duplicate/competing fix**: `fatal_signal_pending` appears exactly once in all of `net/9p/`, at the new line. No prior stable-only patch to collide with. - **`p9_client_zc_rpc()`**: correctly untouched — 5.10's zc variant has no `again:`/`P9_TFLUSH` retry loop, matching upstream, so the one-site fix is complete. - **Abandoned-TFLUSH lifetime (the one thing worth naming)**: the new early exit means `p9_client_flush()` returns `-ERESTARTSYS` before calling `trans_mod->cancelled(oldreq)`, so `oldreq` stays on the transport's `req_list`. In 5.10 the flush req itself then goes through `reterr: p9_tag_remove()`, which does an *eager* `idr_remove()` + put, whereas upstream ≥6.1 removes from the idr only on the final `p9_req_put()`. I checked whether this makes 5.10 more exposed: it doesn't. `trans_fd` takes its own reference at `trans_fd.c:475` before moving a req to `req_list`, so refcount goes 2→1 and nothing is freed; a late response for a now-unknown tag hits the `!m->rreq` guard in `p9_read_work()` (`trans_fd.c:336`) which logs "Unexpected packet tag" and errors out rather than dereferencing; and `p9_conn_cancel()` completes and puts the stranded req at disconnect. Identical exposure to the pre-existing `err == -ERESTARTSYS && c->status == Connected` path and to `trans_mod->request()` failure. **No UAF, no leak beyond disconnect, and no 5.10-specific regression.** - **Behavioral note (upstream-inherited, not a backport defect)**: as analyzed above, whenever this branch is reached `fatal_signal_pending()` is necessarily true, so the `sigpending = 1; clear_thread_flag(); goto again;` retry becomes effectively unreachable. That is upstream's deliberate semantics ("return `-ERESTARTSYS` to the caller"), and 5.10 reproduces it exactly because its wait is equally killable-only. The backport does not amplify or alter this. ### 4. Overall assessment **High quality — accept.** This is the minimal possible adaptation: the added code is byte-identical to upstream, the target label and its body are identical, all supporting semantics (`safe_errno`, killable-wait signal conditions, `sigpending` bookkeeping) verify out in 5.10, and the surrounding version drift is entirely cosmetic/orthogonal. The only "resolution" required was matching the older parenthesized `if` context. Build verification is the one item still outstanding — `stable build log` (x86_64 + aarch64) is running now; I'll report the result when it lands. Given the change adds no new symbols or includes, a failure would be surprising. ================================================================================ This is an empty commit for documentation purposes only. -- 2.53.0 ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-25 10:55 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-20 14:32 FAILED: patch "[PATCH] net/9p: fix infinite loop in p9_client_rpc on fatal signal" failed to apply to 5.10-stable tree gregkh 2026-07-25 10:55 ` [PATCH 5.10.y 1/2] net/9p: fix infinite loop in p9_client_rpc on fatal signal Sasha Levin 2026-07-25 10:55 ` [PATCH 5.10.y 2/2] [AUTOMATED CONFLICT RESOLUTION] Documentation for 6b4f48728faa8bb514368f7eacda05565dea8696 Sasha Levin
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.