Linux kernel -stable discussions
 help / color / mirror / Atom feed
* 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(&current->sighand->siglock, flags);
		recalc_sigpending();
		spin_unlock_irqrestore(&current->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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox