From: Chuck Lever <cel@kernel.org>
To: Jeff Layton <jlayton@kernel.org>, NeilBrown <neil@brown.name>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>,
Scott Mayhew <smayhew@redhat.com>,
Trond Myklebust <trondmy@kernel.org>,
Anna Schumaker <anna@kernel.org>
Cc: linux-nfs@vger.kernel.org,
Farhad Alemi <farhad.alemi@berkeley.edu>,
Chuck Lever <cel@kernel.org>
Subject: [PATCH v2 1/8] NFSD: Don't complete a cld upcall the daemon has not read
Date: Tue, 01 Sep 2026 16:19:41 -0400 [thread overview]
Message-ID: <20260901-alemi-v2-1-e163f94a3a6e@kernel.org> (raw)
In-Reply-To: <20260901-alemi-v2-0-e163f94a3a6e@kernel.org>
cld_pipe_downcall() matches a reply to its upcall on the xid alone.
A write that arrives before the daemon has read that upcall
completes __cld_pipe_upcall() while its struct rpc_pipe_msg is still
queued on the pipe. The waiter returns, its stack frame goes away,
and the pipe keeps a list_head that points into it. The next
rpc_queue_upcall() walks that pointer:
BUG: KASAN: vmalloc-out-of-bounds in __list_add_valid_or_report
Read of size 8 at addr ffffc90007027950 by task syz.0.96/13066
__list_add_valid_or_report+0x6a/0x130
rpc_queue_upcall
cld_pipe_upcall
nfsd4_cld_grace_start
nfsd4_cld_tracking_init
The pipe is mode 0600 in rpc_pipefs, so the trigger is a broken or
hostile nfsdcld rather than an unprivileged task.
Record whether the daemon has consumed the whole message and
complete only when it has. cld_pipe_destroy_msg() runs on every path
by which the pipe releases a message, so it can maintain that flag
under cn_lock. nfsdcld sends its -EINPROGRESS downcalls only after
reading the upcall, so the new check does not break the GraceStart
record stream.
Fixes: f3f8014862d8 ("nfsd: add the infrastructure to handle the cld upcall")
Reported-by: Farhad Alemi <farhad.alemi@berkeley.edu>
Closes: https://lore.kernel.org/linux-nfs/CA+0ovCjVF58WLeen2ctdzHyWUASAAW3Y=Yjihyq0pFApYawtDg@mail.gmail.com/
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs4recover.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index aee3a0b22d1c..22a9a366d7eb 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -648,6 +648,8 @@ struct cld_upcall {
struct list_head cu_list;
struct cld_net *cu_net;
struct completion cu_done;
+ /* daemon has read the whole upcall; protected by cn_lock */
+ bool cu_inflight;
union {
struct cld_msg_hdr cu_hdr;
struct cld_msg cu_msg;
@@ -808,6 +810,13 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
spin_lock(&cn->cn_lock);
list_for_each_entry(tmp, &cn->cn_list, cu_list) {
if (get_unaligned(&tmp->cu_u.cu_hdr.cm_xid) == xid) {
+ /*
+ * Completing now would return the waiter
+ * while its message is still queued on the
+ * pipe.
+ */
+ if (!tmp->cu_inflight)
+ break;
cup = tmp;
if (status != -EINPROGRESS)
list_del_init(&cup->cu_list);
@@ -816,9 +825,9 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
}
spin_unlock(&cn->cn_lock);
- /* couldn't find upcall? */
+ /* no upcall to complete? */
if (!cup) {
- dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid);
+ dprintk("%s: no completable upcall -- xid=%u\n", __func__, xid);
return -EINVAL;
}
@@ -838,8 +847,16 @@ cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
struct cld_msg *cmsg = msg->data;
struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
cu_u.cu_msg);
+ struct cld_net *cn = cup->cu_net;
+
+ /*
+ * errno >= 0 means the daemon read the whole message and a
+ * downcall will complete the upcall.
+ */
+ spin_lock(&cn->cn_lock);
+ cup->cu_inflight = msg->errno >= 0;
+ spin_unlock(&cn->cn_lock);
- /* errno >= 0 means we got a downcall */
if (msg->errno >= 0)
return;
--
2.54.0
next prev parent reply other threads:[~2026-09-01 20:19 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 20:19 [PATCH v2 0/8] Fix premature completion of rpc_pipefs upcalls Chuck Lever
2026-09-01 20:19 ` Chuck Lever [this message]
2026-09-01 20:19 ` [PATCH v2 2/8] NFSD: Move the cld upcall message out of the caller's stack frame Chuck Lever
2026-09-01 20:19 ` [PATCH v2 3/8] NFSD: Complete a cld upcall when copying its reply fails Chuck Lever
2026-09-01 20:19 ` [PATCH v2 4/8] NFSD: Reject an oversized principal hash from nfsdcld Chuck Lever
2026-09-01 20:19 ` [PATCH v2 5/8] pnfs/blocklayout: Complete a device upcall only on its own reply Chuck Lever
2026-09-01 20:19 ` [PATCH v2 6/8] NFSD: Set nn->cld_net before registering the cld pipe Chuck Lever
2026-09-01 20:19 ` [PATCH v2 7/8] NFSD: Complete a cld upcall when the daemon closes the pipe Chuck Lever
2026-09-01 20:19 ` [PATCH v2 8/8] pnfs/blocklayout: Complete a device upcall when the pipe is closed Chuck Lever
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260901-alemi-v2-1-e163f94a3a6e@kernel.org \
--to=cel@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=anna@kernel.org \
--cc=farhad.alemi@berkeley.edu \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=smayhew@redhat.com \
--cc=tom@talpey.com \
--cc=trondmy@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.