[PATCH] svcrdma: bound check rc_curpage in svc_rdma_build_read_segment

From: Giorgi Kobakhia

Date: Wed Oct 21 2026 - 16:39:16 EST


The existing guard in the end of loop is not enough for bounding
rc_curpage, because it only checks if some part of the chunk goes beyond
the rq_maxpages.

if (len && ((head->rc_curpage + 1) > rqstp->rq_maxpages))
goto out_put;

If the chunk exactly fills up the pages, then len is 0, guard is skipped
and the next chunk makes head->rc_curpage go over rq_maxpages.

Commit 81381d1a90de ("svcrdma: Adjust the number of entries in
svc_rdma_recv_ctxt::rc_pages") made OOB accessible, since it
shrunk the rc_pages array size to rc_maxpages.

Commit d1bea0ce35b6 ("svcrdma: bound check rq_pages index in inline
path") added a loop-top "rc_curpage >= rq_maxpages" guard in nearby
function svc_rdma_copy_inline_range(). The same check would guard it in
svc_rdma_build_read_segment().

OOB write is triggered in svc_rdma_process_read_list():

BUG: KASAN: slab-out-of-bounds in svc_rdma_process_read_list
(svc_rdma_rw.c:1148 svc_rdma_rw.c:1197)
Write of size 8

Call Trace:
svc_rdma_process_read_list (svc_rdma_rw.c:1148 svc_rdma_rw.c:1197)
svc_rdma_recvfrom (net/sunrpc/xprtrdma/svc_rdma_recvfrom.c:1022)
svc_recv (net/sunrpc/svc_xprt.c:870 net/sunrpc/svc_xprt.c:968)
nfsd (fs/nfsd/nfssvc.c:919)

Add bound check for rc_curpage in the beginning of the loop.

Fixes: 81381d1a90de ("svcrdma: Adjust the number of entries in svc_rdma_recv_ctxt::rc_pages")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Tested-by: Xiang Mei <xmei5@xxxxxxx>
Signed-off-by: Giorgi Kobakhia <gkobakhi@xxxxxxx>
---
net/sunrpc/xprtrdma/svc_rdma_rw.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c
index 9aaaade99e6e..a98041139075 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
@@ -777,6 +777,9 @@ 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 >= rqstp->rq_maxpages)
+ goto out_put;
+
seg_len = min_t(unsigned int, len,
PAGE_SIZE - head->rc_pageoff);

--
2.43.0