* [PATCH] svcrdma: account for inline bytes in Read chunk page budget
@ 2026-10-15 13:58 Jiwoong Wi
2026-10-16 15:08 ` Chuck Lever
0 siblings, 1 reply; 2+ messages in thread
From: Jiwoong Wi @ 2026-10-15 13:58 UTC (permalink / raw)
To: Chuck Lever, Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo,
Tom Talpey
Cc: linux-nfs, linux-kernel, stable, bobtobabz
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
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] svcrdma: account for inline bytes in Read chunk page budget
2026-10-15 13:58 [PATCH] svcrdma: account for inline bytes in Read chunk page budget Jiwoong Wi
@ 2026-10-16 15:08 ` Chuck Lever
0 siblings, 0 replies; 2+ messages in thread
From: Chuck Lever @ 2026-10-16 15:08 UTC (permalink / raw)
To: Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Jiwoong Wi
Cc: linux-nfs, linux-kernel, stable, bobtobabz
On Thu, 15 Oct 2026 22:58:32 +0900, Jiwoong Wi wrote:
> 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.
>
> [...]
Applied to nfsd-testing, thanks!
[1/1] svcrdma: account for inline bytes in Read chunk page budget
commit: 4e84914d70a0194e18bba6d814cfe71b340aadc8
--
Chuck Lever
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-16 15:08 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-15 13:58 [PATCH] svcrdma: account for inline bytes in Read chunk page budget Jiwoong Wi
2026-10-16 15:08 ` Chuck Lever
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®