From: Jiwoong Wi <dwdnlzj@gmail.com>
To: Chuck Lever <cel@kernel.org>, 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, linux-kernel@vger.kernel.org,
stable@vger.kernel.org, bobtobabz@gmail.com
Subject: [PATCH] svcrdma: account for inline bytes in Read chunk page budget
Date: Thu, 15 Oct 2026 22:58:32 +0900 [thread overview]
Message-ID: <20261015135832.67889-1-dwdnlzj@gmail.com> (raw)
The Read-list check limits Read bytes to the request page budget. With
multiple data item Read chunks, svc_rdma_read_multiple_chunks() copies
the inline RPC body into those same pages. The reconstructed message
can overflow the budget even when its Read bytes alone fit.
A short final Read segment escapes the existing page-overrun check
because that check runs only if len remains nonzero. The inflated
rc_page_count then makes svc_rdma_clear_rqst_pages() write past
rc_pages, followed by an out-of-bounds read during cleanup.
Include inline bytes in the budget only when multiple data item Read
chunks share the page array. Count the final Read chunk, and replace
the late, len-conditional page check with checks of both page-array
capacities before using each destination page. Single Read chunks and
Position Zero Call chunks use different reconstruction paths.
Validation used nfsd-testing 78c334bc5ae61d23ca1cc2e43079c620f1d40866.
The unmodified Generic KASAN kernel reproduced an out-of-bounds write
in svc_rdma_process_read_list(), followed by an oops during cleanup.
With this patch, the full kernel and modules built and booted. In an
isolated run, all 61 instances of the same frame were rejected during
RPC/RDMA header parsing. A two-Read-chunk NFSv4 NULL request completed:
the server issued two RDMA Reads and returned a successful RPC reply
with the matching XID. Concurrent NFSv4.2/RDMA direct I/O completed 20
repeated 8 MiB write/read transfers; the final readback matched the source
SHA-256. No KASAN report or oops occurred in the direct I/O run, and
kernel taint remained zero. The reproducer and baseline KASAN log are
available privately on request.
The vulnerability research and validation were conducted by members of
the Tobabz team as part of the Best of the Best 15th program.
Fixes: d7cc73972661 ("svcrdma: support multiple Read chunks per RPC")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Jiwoong Wi <dwdnlzj@gmail.com>
---
net/sunrpc/xprtrdma/svc_rdma_pcl.c | 12 ++++++++----
net/sunrpc/xprtrdma/svc_rdma_rw.c | 10 ++++++----
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_pcl.c b/net/sunrpc/xprtrdma/svc_rdma_pcl.c
index 862372279..8da0f0dc7 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_pcl.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_pcl.c
@@ -238,8 +238,8 @@ bool pcl_alloc_write(struct svc_rdma_recv_ctxt *rctxt,
* before comparing against @inline_len or the Call chunk length.
*
* Rejects frames where a Read chunk's inline-body offset exceeds
- * the bound, where adjacent Read chunks overlap, or where any
- * single chunk length exceeds the page budget.
+ * the bound, where adjacent Read chunks overlap, or where Read bytes,
+ * plus inline bytes when they share the page array, exceed its budget.
*
* Return values:
* %true: Read chunk positions and lengths are valid
@@ -269,8 +269,9 @@ bool pcl_check_read_chunk_positions(struct svc_rdma_recv_ctxt *rctxt,
pcl_for_each_chunk(chunk, &rctxt->rc_read_pcl) {
if (chunk->ch_position - total_read > bound)
return false;
- if (chunk->ch_length > max_len)
+ if (chunk->ch_length > max_len - total_read)
return false;
+ total_read += chunk->ch_length;
next = pcl_next_chunk(&rctxt->rc_read_pcl, chunk);
if (!next)
@@ -278,8 +279,11 @@ bool pcl_check_read_chunk_positions(struct svc_rdma_recv_ctxt *rctxt,
if (chunk->ch_position + chunk->ch_length > next->ch_position)
return false;
- total_read += chunk->ch_length;
}
+ if (pcl_is_empty(&rctxt->rc_call_pcl) &&
+ rctxt->rc_read_pcl.cl_count > 1 &&
+ inline_len > max_len - total_read)
+ return false;
return true;
}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c
index 63d00f0cc..1f1ccf80a 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
@@ -794,6 +794,10 @@ static int svc_rdma_build_read_segment(struct svc_rqst *rqstp,
ctxt->rw_nents = nr_bvec;
for (bvec_idx = 0; bvec_idx < ctxt->rw_nents; bvec_idx++) {
+ if (head->rc_curpage >= head->rc_maxpages ||
+ head->rc_curpage >= rqstp->rq_maxpages)
+ goto out_put;
+
seg_len = min_t(unsigned int, len,
PAGE_SIZE - head->rc_pageoff);
@@ -810,9 +814,6 @@ static int svc_rdma_build_read_segment(struct svc_rqst *rqstp,
head->rc_pageoff = 0;
}
len -= seg_len;
-
- if (len && ((head->rc_curpage + 1) > rqstp->rq_maxpages))
- goto out_put;
}
ret = svc_rdma_rw_ctx_init(rdma, ctxt, segment->rs_offset,
@@ -893,7 +894,8 @@ static int svc_rdma_copy_inline_range(struct svc_rqst *rqstp,
for (page_no = 0; page_no < numpages; page_no++) {
unsigned int page_len;
- if (head->rc_curpage >= rqstp->rq_maxpages)
+ if (head->rc_curpage >= head->rc_maxpages ||
+ head->rc_curpage >= rqstp->rq_maxpages)
return -EINVAL;
page_len = min_t(unsigned int, remaining,
base-commit: 78c334bc5ae61d23ca1cc2e43079c620f1d40866
--
2.39.5
next reply other threads:[~2026-10-15 13:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-15 13:58 Jiwoong Wi [this message]
2026-10-16 15:08 ` 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=20261015135832.67889-1-dwdnlzj@gmail.com \
--to=dwdnlzj@gmail.com \
--cc=Dai.Ngo@oracle.com \
--cc=bobtobabz@gmail.com \
--cc=cel@kernel.org \
--cc=jlayton@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=stable@vger.kernel.org \
--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
all inboxes | Powered by JetHome®