[PATCH 2/5] 9p: ignore a zero-copy reply that arrives after a fatal signal

From: Lianjie Wang

Date: Mon Nov 09 2026 - 05:56:03 EST


When a fatal signal ends the wait of p9_virtio_zc_request() for a
zero-copy TREAD or TREADDIR, the device can still answer the request
before the RFLUSH, and p9_client_zc_rpc() parses that reply.
p9_virtio_zc_request() has returned by then, so it neither bounds the
reply size nor moves the error string of an RERROR from the reply pages
into rc.sdata, and p9_check_errors() skips its size check for zero-copy
requests, so it parses the error string of an oversized reply past the
end of rc.sdata:

BUG: KASAN: slab-out-of-bounds in p9pdu_readf+0x151e/0x1c50
Read of size 8179 at addr ffff888004724009 by task zc9p/155
Call Trace:
p9pdu_readf+0x151e/0x1c50
p9_check_errors+0x23d/0x510
p9_client_zc_rpc+0x4f0/0x970
p9_client_read_once+0x237/0x6c0

Also, the error string that fits within rc.sdata is parsed from
rc.sdata, but the device wrote only the header there, so
p9_errstr2errno() can print the error from uninitialized memory.

Fix this by ignoring the reply when a fatal signal ends the wait of a
zero-copy request, since p9_client_zc_rpc() already returns -ERESTARTSYS
when the server cancels such a request.

This patch is assisted by Claude Opus 5.5.

Fixes: f615625a44c4 ("9p: handling Rerror without copy_from_iter_full()")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Lianjie Wang <lian@xxxxxxxxxxxxxxxxxx>
---
net/9p/client.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/net/9p/client.c b/net/9p/client.c
index e63e8c2a853df..66980ad52bca8 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -706,10 +706,11 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,

if (c->trans_mod->cancel(c, req))
p9_client_flush(c, req);
-
- /* if we received the response anyway, don't signal error */
- if (READ_ONCE(req->status) == REQ_STATUS_RCVD)
- err = 0;
+ /*
+ * err stays -ERESTARTSYS even if the reply has arrived, since
+ * the transport moves the error string of a zero-copy reply
+ * into rc only while it waits.
+ */
}
recalc_sigpending:
if (sigpending) {
--
2.56.0