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>
Cc: linux-nfs@vger.kernel.org,
"Jérémy Jean" <Jeremy.Jean@oss.cyber.gouv.fr>,
"Chuck Lever" <cel@kernel.org>
Subject: [PATCH 1/2] nfsd: preflight SEQUENCE replies before accepting a slot
Date: Mon, 17 Aug 2026 20:57:14 -0400 [thread overview]
Message-ID: <20260817-jean-v1-1-9e356596ab85@kernel.org> (raw)
In-Reply-To: <20260817-jean-v1-0-9e356596ab85@kernel.org>
From: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
nfsd4_sequence() narrows the reply buffer to the session's cached
reply limit before it accepts the slot seqid. A client may negotiate
ca_maxresponsesize_cached down to NFSD_MIN_HDR_SEQ_SZ, and
nfsd4_alloc_slot() then gives every slot a zero-length sl_data[]. A
COMPOUND tag can fill that narrowed buffer until it holds the
SEQUENCE opcode but not the status word that follows.
nfsd4_encode_operation() returns without running
nfsd4_encode_sequence(), so cstate.data_offset stays zero. It leaves
op->status at nfs_ok as well, so the COMPOUND is treated as having
succeeded.
nfsd4_store_cache_entry() declines to cache a lone SEQUENCE that
returned an error. That test reads the status the operation
reported, so it passes here. The copy starts at offset zero and
takes the whole reply, RPC and COMPOUND headers included, into the
zero-length sl_data[]. The COMPOUND tag is copied along with it, so
the client picks most of the bytes written past the end of the slot:
BUG: KASAN: slab-out-of-bounds in read_bytes_from_xdr_buf+0x1bc/0x390
Write of size 80 at addr ffff888003a549cd by task kunit_try_catch/24
__asan_memcpy+0x38/0x60
read_bytes_from_xdr_buf+0x1bc/0x390
nfsd4_sequence_done+0x5b0/0x810
nfs4svc_encode_compoundres+0x1bf/0x240
Check that the fixed-size SEQUENCE result, plus room for a following
operation's error status, fits the negotiated limit before narrowing
the buffer and consuming the slot seqid. The slot and its reply
cache are left unchanged, as RFC 8881 Section 2.10.6.1.2 requires of
an error returned from SEQUENCE.
Fixes: 47ee52986472 ("nfsd4: adjust buflen to session channel limit")
Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs4state.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1ba97e3f65eb..3fc5bed85bab 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5044,6 +5044,7 @@ __be32
nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
union nfsd4_op_u *u)
{
+ struct nfsd4_compoundargs *args = rqstp->rq_argp;
struct nfsd4_sequence *seq = &u->sequence;
struct nfsd4_compoundres *resp = rqstp->rq_resp;
struct xdr_stream *xdr = resp->xdr;
@@ -5053,6 +5054,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_conn *conn;
__be32 status;
int buflen;
+ u32 maxlen, respsize;
struct net *net = SVC_NET(rqstp);
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -5130,7 +5132,22 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
session->se_fchannel.maxresp_sz;
status = (seq->cachethis) ? nfserr_rep_too_big_to_cache :
nfserr_rep_too_big;
- if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack))
+ if (buflen < rqstp->rq_auth_slack)
+ goto out_put_session;
+ maxlen = buflen - rqstp->rq_auth_slack;
+
+ /*
+ * A SEQUENCE result too large for maxlen never reaches
+ * nfsd4_encode_sequence(), so cstate.data_offset stays zero and
+ * the reply cache overruns the slot.
+ */
+ respsize = nfsd4_max_reply(rqstp, &args->ops[0]);
+ if (!nfsd4_last_compound_op(rqstp))
+ respsize += COMPOUND_ERR_SLACK_SPACE;
+ if (xdr->buf->len + respsize > maxlen)
+ goto out_put_session;
+
+ if (xdr_restrict_buflen(xdr, maxlen))
goto out_put_session;
svc_reserve_auth(rqstp, buflen);
--
2.54.0
next prev parent reply other threads:[~2026-08-18 0:57 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-18 0:57 [PATCH 0/2] nfsd: fix a slab overwrite in the NFSv4.1 session reply cache Chuck Lever
2026-08-18 0:57 ` Chuck Lever [this message]
2026-08-18 0:57 ` [PATCH 2/2] nfsd: set op->status when an operation's header cannot be encoded 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=20260817-jean-v1-1-9e356596ab85@kernel.org \
--to=cel@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=Jeremy.Jean@oss.cyber.gouv.fr \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox