FAILED: patch "[PATCH] svcrdma: Validate Read chunk positions before reconstruction" failed to apply to 6.1-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 3779b7b9e7d1c8ba4738f9d327de3b0288cefe9b
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090310-onto-impotence-7944@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 3779b7b9e7d1c8ba4738f9d327de3b0288cefe9b Mon Sep 17 00:00:00 2001
From: Chuck Lever <[email protected]>
Date: Tue, 26 May 2026 09:35:55 -0400
Subject: [PATCH] svcrdma: Validate Read chunk positions before reconstruction
The RPC/RDMA Read chunk position field is supplied by the remote client and stored verbatim in the parsed chunk list. xdr_count_read_segments() checks only 4-byte alignment; it never compares the position against the received inline body length.
In the single-chunk path, svc_rdma_read_complete_one() splits the head and tail kvecs at ch_position. A position past the inline body underflows the tail length, exposing adjacent slab memory to the upper XDR decoder.
In the multi-chunk path, svc_rdma_read_multiple_chunks() computes gap lengths between chunks as unsigned subtractions from ch_position. Overlapping Read chunks cause these subtractions to underflow. A final position past the inline body likewise underflows the trailing gap length. svc_rdma_copy_inline_range() then copies past the receive buffer into request pages that are returned to the client through the Reply channel.
Bound inline-range copies in svc_rdma_copy_inline_range() against the decoded inline RPC body saved in rc_saved_arg. Reject a single Read chunk positioned beyond that body, and reject multi-chunk lists where accumulated read bytes exceed the next chunk's position. Apply the same position and overlap checks in the call-chunk interleaving path.
net/sunrpc/xprtrdma/svc_rdma_rw.c +30 -8
@@ -847,7 +847,7 @@ static int svc_rdma_build_read_chunk(struct svc_rqst *rqstp,* svc_rdma_copy_inline_range - Copy part of the inline content into pages * @rqstp: RPC transaction context * @head: context for ongoing I/O -* @offset: offset into the Receive buffer of region to copy +* @offset: offset into the inline content of region to copy * @remaining: length of region to copy * * Take a page at a time from rqstp->rq_pages and copy the inline
@@ -864,9 +864,13 @@ static int svc_rdma_copy_inline_range(struct svc_rqst *rqstp,unsigned int offset, unsigned int remaining) { - unsigned char *dst, *src = head->rc_recv_buf; + unsigned char *dst, *src = head->rc_saved_arg.head[0].iov_base; +unsigned int inline_len = head->rc_saved_arg.head[0 ].iov_len;unsigned int page_no, numpages; +if (offset > inline_len || remaining > inline_len - offset) +return -EINVAL ; + numpages =PAGE_ALIGN (head->rc_pageoff + remaining) >>PAGE_SHIFT ;for (page_no =0 ; page_no < numpages; page_no++) {unsigned int page_len;
@@ -917,9 +921,10 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp, {const struct svc_rdma_pcl *pcl = &head->rc_read_pcl;struct svc_rdma_chunk *chunk, *next; -unsigned int start, length; +unsigned int inline_len, start, length;int ret; + inline_len = head->rc_saved_arg.head[0 ].iov_len; start =0 ; chunk =pcl_first_chunk (pcl); length = chunk->ch_position;
@@ -937,6 +942,8 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp,break ; start += length; +if (head->rc_readbytes > next->ch_position) +return -EINVAL ; length = next->ch_position - head->rc_readbytes; ret =svc_rdma_copy_inline_range (rqstp, head, start, length);if (ret <0 )
@@ -944,7 +951,9 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp, } start += length; - length = head->rc_byte_len - start; +if (start > inline_len) +return -EINVAL ; + length = inline_len - start;return svc_rdma_copy_inline_range (rqstp, head, start, length); }
@@ -969,8 +978,12 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp,static int svc_rdma_read_data_item (struct svc_rqst *rqstp,struct svc_rdma_recv_ctxt *head) { -return svc_rdma_build_read_chunk (rqstp, head, -pcl_first_chunk (&head->rc_read_pcl)); +struct svc_rdma_chunk *chunk =pcl_first_chunk (&head->rc_read_pcl); + +if (chunk->ch_position > head->rc_saved_arg.head[0 ].iov_len) +return -EINVAL ; + +return svc_rdma_build_read_chunk (rqstp, head, chunk); }/**
@@ -1039,14 +1052,17 @@ static int svc_rdma_read_call_chunk(struct svc_rqst *rqstp,pcl_first_chunk (&head->rc_call_pcl);const struct svc_rdma_pcl *pcl = &head->rc_read_pcl;struct svc_rdma_chunk *chunk, *next; -unsigned int start, length; +unsigned int call_len, start, length;int ret;if (pcl_is_empty (pcl))return svc_rdma_build_read_chunk (rqstp, head, call_chunk); + call_len = call_chunk->ch_length; start =0 ; chunk =pcl_first_chunk (pcl); +if (chunk->ch_position > call_len) +return -EINVAL ; length = chunk->ch_position; ret =svc_rdma_read_chunk_range (rqstp, head, call_chunk, start, length);
@@ -1063,6 +1079,10 @@ static int svc_rdma_read_call_chunk(struct svc_rqst *rqstp,break ; start += length; +if (next->ch_position > call_len) +return -EINVAL ; +if (head->rc_readbytes > next->ch_position) +return -EINVAL ; length = next->ch_position - head->rc_readbytes; ret =svc_rdma_read_chunk_range (rqstp, head, call_chunk, start, length);
@@ -1071,7 +1091,9 @@ static int svc_rdma_read_call_chunk(struct svc_rqst *rqstp, } start += length; - length = call_chunk->ch_length - start; +if (start > call_len) +return -EINVAL ; + length = call_len - start;return svc_rdma_read_chunk_range (rqstp, head, call_chunk, start, length); }
Sasha Levin
maintainerPATCH 1/5 svcrdma: Update synopsis of svc_rdma_read_multiple_chunks()
From: Chuck Lever <[email protected]>
[ Upstream commit 740a3c895d94fc72494f2a4abf1ab31b6be482e8 ]
Since the RDMA Read I/O state is now contained in the recv_ctxt, svc_rdma_read_multiple_chunks() can use that recv_ctxt to derive the read_info rather than the other way around. This removes another usage of the ri_readctxt field, enabling its removal in a subsequent patch.
[Stable 6.1 dependency adaptation]
The stable tree still stores Read I/O state in svc_rdma_read_info and reconstructs rq_arg inside the Read builders. Fold the necessary context and synopsis conversions into this dependency so that upstream commit 3779b7b9e7d1 ("svcrdma: Validate Read chunk positions before reconstruction") can be cherry-picked without editing its patch.
Move the existing chunk context and Read counters into svc_rdma_recv_ctxt, convert the existing Read helpers to rqstp/head arguments, and remove the now-unused read_info allocation and free helpers. Preserve the stable transport pointer, synchronous completion wait, and RDMA context cleanup.
Save the decoded inline rq_arg before constructing Reads. Move the existing single-chunk and whole-message reconstruction into svc_rdma_process_read_list, after the builders return successfully, leaving the target's validation sites in the same form as upstream without adding any functions.
Retain the upstream inline-copy page-offset correction and page-array bound, using rq_page_end for the latter on 6.1. Set the reconstructed whole-message length from rc_readbytes, which already includes copied inline bytes, so that those bytes are not counted twice.
Stable-dep-of: 3779b7b9e7d1 ("svcrdma: Validate Read chunk positions before reconstruction")
--- include/linux/sunrpc/svc_rdma.h | 22 +++ net/sunrpc/xprtrdma/svc_rdma_rw.c | 318 ++++++++++++------------------ 2 files changed, 144 insertions(+), 196 deletions(-)
include/linux/sunrpc/svc_rdma.h +22 -0
@@ -126,6 +126,21 @@ enum {#define RPCSVC_MAXPAYLOAD_RDMA RPCSVC_MAXPAYLOAD +/* A chunk context tracks all I/O for moving one Read or Write +* chunk. This is a set of rdma_rw's that handle data movement +* for all segments of one chunk. +*/ +struct svc_rdma_chunk_ctxt { +struct rpc_rdma_cid cc_cid; +struct ib_cqe cc_cqe; +struct svcxprt_rdma *cc_rdma; +struct list_head cc_rwctxts; +ktime_t cc_posttime; +int cc_sqecount; +enum ib_wc_status cc_status; +struct completion cc_done; +}; +struct svc_rdma_recv_ctxt {struct llist_node rc_node;struct list_head rc_list;
@@ -141,6 +156,13 @@ struct svc_rdma_recv_ctxt {u32 rc_inv_rkey;__be32 rc_msgtype; +/* State for pulling Read chunks */ +unsigned int rc_pageoff; +unsigned int rc_curpage; +unsigned int rc_readbytes; +struct xdr_buf rc_saved_arg; +struct svc_rdma_chunk_ctxt rc_cc; +struct svc_rdma_pcl rc_call_pcl;struct svc_rdma_pcl rc_read_pcl;
net/sunrpc/xprtrdma/svc_rdma_rw.c +122 -196
567 lines not on this page · raw message
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 svcrdma: Move the svc_rdma_cc_init() call
From: Chuck Lever <[email protected]>
[ Upstream commit 018f34051bc9f4908336b3fe9e52931bb8410ced ]
Now that the chunk_ctxt for Reads is no longer dynamically allocated it can be initialized once for the life of the object that contains it (struct svc_rdma_recv_ctxt).
[Stable 6.1 dependency adaptation]
Keep rc_temp initialization in svc_rdma_recv_ctxt_alloc(), since this stable tree still distinguishes temporary receive contexts. Initialize the embedded rc_cc alongside it using the existing svc_rdma_cc_init(), retaining cc_rdma for the stable completion and cleanup paths.
Replace per-Read chunk-context initialization with a cc_sqecount reset, keeping the existing Read counter initialization order and synchronous completion/release path. The release path drains cc_rwctxts before a receive context is reused, so its list and transport can be initialized once at allocation. No functions are added.
Preserve the preceding dependency's reconstruction changes and saved inline argument. All hunks of target 3779b7b9e7d1 apply cleanly to this adapted tree.
Stable-dep-of: 3779b7b9e7d1 ("svcrdma: Validate Read chunk positions before reconstruction")
--- include/linux/sunrpc/svc_rdma.h | 2 ++ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 1 + net/sunrpc/xprtrdma/svc_rdma_rw.c | 11 ++++++++--- 3 files changed, 11 insertions(+), 3 deletions(-)
include/linux/sunrpc/svc_rdma.h +2 -0
@@ -203,6 +203,8 @@ extern int svc_rdma_recvfrom(struct svc_rqst *);/* svc_rdma_rw.c */ extern void svc_rdma_destroy_rw_ctxts (struct svcxprt_rdma *rdma); +extern void svc_rdma_cc_init (struct svcxprt_rdma *rdma, +struct svc_rdma_chunk_ctxt *cc);extern int svc_rdma_send_write_chunk (struct svcxprt_rdma *rdma,const struct svc_rdma_chunk *chunk,const struct xdr_buf *xdr);
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +1 -0
@@ -156,6 +156,7 @@ svc_rdma_recv_ctxt_alloc(struct svcxprt_rdma *rdma) ctxt->rc_recv_sge.lkey = rdma->sc_pd->local_dma_lkey; ctxt->rc_recv_buf = buffer; ctxt->rc_temp = false; +svc_rdma_cc_init (rdma, &ctxt->rc_cc);return ctxt; fail2:
net/sunrpc/xprtrdma/svc_rdma_rw.c +8 -3
@@ -149,8 +149,13 @@ static void svc_rdma_cc_cid_init(struct svcxprt_rdma *rdma, cid->ci_completion_id =atomic_inc_return (&rdma->sc_completion_ids); } -static void svc_rdma_cc_init (struct svcxprt_rdma *rdma, -struct svc_rdma_chunk_ctxt *cc) +/** +* svc_rdma_cc_init - Initialize an svc_rdma_chunk_ctxt +* @rdma: controlling transport instance +* @cc: svc_rdma_chunk_ctxt to be initialized +*/ +void svc_rdma_cc_init (struct svcxprt_rdma *rdma, +struct svc_rdma_chunk_ctxt *cc) {svc_rdma_cc_cid_init (rdma, &cc->cc_cid); cc->cc_rdma = rdma;
@@ -1023,8 +1028,8 @@ int svc_rdma_process_read_list(struct svcxprt_rdma *rdma,struct xdr_buf *buf = &rqstp->rq_arg;int ret; -svc_rdma_cc_init (rdma, cc); cc->cc_cqe.done = svc_rdma_wc_read_done; + cc->cc_sqecount =0 ; head->rc_curpage =0 ; head->rc_pageoff =0 ; head->rc_readbytes =0 ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 svcrdma: Add back svc_rdma_recv_ctxt::rc_pages
In reply to Sasha LevinFrom: Chuck Lever <[email protected]>
[ Upstream commit 4d9d69db898d05bd063548eee65d16a020676fec ]
Having an nfsd thread waiting for an RDMA Read completion is problematic if the Read responder (the client) stops responding. We need to go back to handling RDMA Reads by allowing the nfsd thread to return to the svc scheduler, then waking a second thread finish the RPC message once the Read completion fires.
To start with, restore the rc_pages field so that RDMA Read pages can be managed across calls to svc_rdma_recvfrom().
Stable-dep-of: 3779b7b9e7d1 ("svcrdma: Validate Read chunk positions before reconstruction")
--- include/linux/sunrpc/svc_rdma.h | 4 +++- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 5 +++++ net/sunrpc/xprtrdma/svc_rdma_rw.c | 4 +++- 3 files changed, 11 insertions(+), 2 deletions(-)
include/linux/sunrpc/svc_rdma.h +3 -1
@@ -152,7 +152,6 @@ struct svc_rdma_recv_ctxt {struct xdr_stream rc_stream;bool rc_temp;u32 rc_byte_len; -unsigned int rc_page_count;u32 rc_inv_rkey;__be32 rc_msgtype;
@@ -169,6 +168,9 @@ struct svc_rdma_recv_ctxt {struct svc_rdma_chunk *rc_cur_result_payload;struct svc_rdma_pcl rc_write_pcl;struct svc_rdma_pcl rc_reply_pcl; + +unsigned int rc_page_count; +struct page *rc_pages[RPCSVC_MAXPAGES ]; };struct svc_rdma_send_ctxt {
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +5 -0
@@ -228,6 +228,11 @@ struct svc_rdma_recv_ctxt *svc_rdma_recv_ctxt_get(struct svcxprt_rdma *rdma)void svc_rdma_recv_ctxt_put (struct svcxprt_rdma *rdma,struct svc_rdma_recv_ctxt *ctxt) { +/* @rc_page_count is normally zero here, but error flows +* can leave pages in @rc_pages. +*/ +release_pages (ctxt->rc_pages, ctxt->rc_page_count); +pcl_free (&ctxt->rc_call_pcl);pcl_free (&ctxt->rc_read_pcl);pcl_free (&ctxt->rc_write_pcl);
net/sunrpc/xprtrdma/svc_rdma_rw.c +3 -1
@@ -1087,7 +1087,9 @@ int svc_rdma_process_read_list(struct svcxprt_rdma *rdma, rqstp->rq_respages = &rqstp->rq_pages[head->rc_page_count]; rqstp->rq_next_page = rqstp->rq_respages +1 ; -/* Ensure svc_rdma_recv_ctxt_put() does not try to release pages */ +/* Ensure svc_rdma_recv_ctxt_put() does not release pages +* left in @rc_pages while I/O proceeds. +*/ head->rc_page_count =0 ; out_err:
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 svcrdma: Add back svcxprt_rdma::sc_read_complete_q
In reply to Sasha LevinFrom: Chuck Lever <[email protected]>
[ Upstream commit a937693a82fd2211c5e52b638959d1486a77d16a ]
Having an nfsd thread waiting for an RDMA Read completion is problematic if the Read responder (ie, the client) stops responding. We need to go back to handling RDMA Reads by allowing the nfsd thread to return to the svc scheduler, then waking a second thread finish the RPC message once the Read completion fires.
As a next step, add a list_head upon which completed Reads are queued. A subsequent patch will make use of this queue.
Stable-dep-of: 3779b7b9e7d1 ("svcrdma: Validate Read chunk positions before reconstruction")
--- include/linux/sunrpc/svc_rdma.h | 1 + net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 37 +++++++++++++++++++++++- net/sunrpc/xprtrdma/svc_rdma_transport.c | 1 + 3 files changed, 38 insertions(+), 1 deletion(-)
include/linux/sunrpc/svc_rdma.h +1 -0
@@ -97,6 +97,7 @@ struct svcxprt_rdma {u32 sc_pending_recvs;u32 sc_recv_batch;struct list_head sc_rq_dto_q; +struct list_head sc_read_complete_q;spinlock_t sc_rq_dto_lock;struct ib_qp *sc_qp;struct ib_cq *sc_rq_cq;
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +36 -1
@@ -383,6 +383,10 @@ void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma) {struct svc_rdma_recv_ctxt *ctxt; +while ((ctxt =svc_rdma_next_recv_ctxt (&rdma->sc_read_complete_q))) { +list_del (&ctxt->rc_list); +svc_rdma_recv_ctxt_put (rdma, ctxt); + }while ((ctxt =svc_rdma_next_recv_ctxt (&rdma->sc_rq_dto_q))) {list_del (&ctxt->rc_list);svc_rdma_recv_ctxt_put (rdma, ctxt);
@@ -770,6 +774,30 @@ static bool svc_rdma_is_reverse_direction_reply(struct svc_xprt *xprt,return true; } +static noinline void svc_rdma_read_complete(struct svc_rqst *rqstp, +struct svc_rdma_recv_ctxt *ctxt) +{ +int i; + +/* Transfer the Read chunk pages into @rqstp.rq_pages, replacing +* the rq_pages that were already allocated for this rqstp. +*/ +release_pages (rqstp->rq_respages, ctxt->rc_page_count); +for (i =0 ; i < ctxt->rc_page_count; i++) + rqstp->rq_pages[i] = ctxt->rc_pages[i]; + +/* Update @rqstp's result send buffer to start after the +* last page in the RDMA Read payload. +*/ + rqstp->rq_respages = &rqstp->rq_pages[ctxt->rc_page_count]; + rqstp->rq_next_page = rqstp->rq_respages +1 ; + +/* Prevent svc_rdma_recv_ctxt_put() from releasing the +* pages in ctxt::rc_pages a second time. +*/ + ctxt->rc_page_count =0 ; +} +/** * svc_rdma_recvfrom - Receive an RPC call * @rqstp: request structure into which to receive an RPC Call
@@ -816,8 +844,14 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) rqstp->rq_xprt_ctxt =NULL ; - ctxt =NULL ;spin_lock (&rdma_xprt->sc_rq_dto_lock); + ctxt =svc_rdma_next_recv_ctxt (&rdma_xprt->sc_read_complete_q); +if (ctxt) { +list_del (&ctxt->rc_list); +spin_unlock_bh (&rdma_xprt->sc_rq_dto_lock); +svc_rdma_read_complete (rqstp, ctxt); + goto complete; + } ctxt =svc_rdma_next_recv_ctxt (&rdma_xprt->sc_rq_dto_q);if (ctxt)list_del (&ctxt->rc_list);
@@ -855,6 +889,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) goto out_readfail; } +complete: rqstp->rq_xprt_ctxt = ctxt; rqstp->rq_prot =IPPROTO_MAX ;svc_xprt_copy_addrs (rqstp, xprt);
net/sunrpc/xprtrdma/svc_rdma_transport.c +1 -0
@@ -136,6 +136,7 @@ static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv,svc_xprt_init (net, &svc_rdma_class, &cma_xprt->sc_xprt, serv);INIT_LIST_HEAD (&cma_xprt->sc_accept_q);INIT_LIST_HEAD (&cma_xprt->sc_rq_dto_q); +INIT_LIST_HEAD (&cma_xprt->sc_read_complete_q);init_llist_head (&cma_xprt->sc_send_ctxts);init_llist_head (&cma_xprt->sc_recv_ctxts);init_llist_head (&cma_xprt->sc_rw_ctxts);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/5 svcrdma: Validate Read chunk positions before reconstruction
In reply to Sasha LevinFrom: Chuck Lever <[email protected]>
[ Upstream commit 3779b7b9e7d1c8ba4738f9d327de3b0288cefe9b ]
The RPC/RDMA Read chunk position field is supplied by the remote client and stored verbatim in the parsed chunk list. xdr_count_read_segments() checks only 4-byte alignment; it never compares the position against the received inline body length.
In the single-chunk path, svc_rdma_read_complete_one() splits the head and tail kvecs at ch_position. A position past the inline body underflows the tail length, exposing adjacent slab memory to the upper XDR decoder.
In the multi-chunk path, svc_rdma_read_multiple_chunks() computes gap lengths between chunks as unsigned subtractions from ch_position. Overlapping Read chunks cause these subtractions to underflow. A final position past the inline body likewise underflows the trailing gap length. svc_rdma_copy_inline_range() then copies past the receive buffer into request pages that are returned to the client through the Reply channel.
Bound inline-range copies in svc_rdma_copy_inline_range() against the decoded inline RPC body saved in rc_saved_arg. Reject a single Read chunk positioned beyond that body, and reject multi-chunk lists where accumulated read bytes exceed the next chunk's position. Apply the same position and overlap checks in the call-chunk interleaving path.
--- net/sunrpc/xprtrdma/svc_rdma_rw.c | 38 ++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-)
net/sunrpc/xprtrdma/svc_rdma_rw.c +30 -8
@@ -743,7 +743,7 @@ static int svc_rdma_build_read_chunk(struct svc_rqst *rqstp,* svc_rdma_copy_inline_range - Copy part of the inline content into pages * @rqstp: RPC transaction context * @head: context for ongoing I/O -* @offset: offset into the Receive buffer of region to copy +* @offset: offset into the inline content of region to copy * @remaining: length of region to copy * * Take a page at a time from rqstp->rq_pages and copy the inline
@@ -760,9 +760,13 @@ static int svc_rdma_copy_inline_range(struct svc_rqst *rqstp,unsigned int offset, unsigned int remaining) { - unsigned char *dst, *src = head->rc_recv_buf; + unsigned char *dst, *src = head->rc_saved_arg.head[0].iov_base; +unsigned int inline_len = head->rc_saved_arg.head[0 ].iov_len;unsigned int page_no, numpages; +if (offset > inline_len || remaining > inline_len - offset) +return -EINVAL ; + numpages =PAGE_ALIGN (head->rc_pageoff + remaining) >>PAGE_SHIFT ;for (page_no =0 ; page_no < numpages; page_no++) {unsigned int page_len;
@@ -813,9 +817,10 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp, {const struct svc_rdma_pcl *pcl = &head->rc_read_pcl;struct svc_rdma_chunk *chunk, *next; -unsigned int start, length; +unsigned int inline_len, start, length;int ret; + inline_len = head->rc_saved_arg.head[0 ].iov_len; start =0 ; chunk =pcl_first_chunk (pcl); length = chunk->ch_position;
@@ -833,6 +838,8 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp,break ; start += length; +if (head->rc_readbytes > next->ch_position) +return -EINVAL ; length = next->ch_position - head->rc_readbytes; ret =svc_rdma_copy_inline_range (rqstp, head, start, length);if (ret <0 )
@@ -840,7 +847,9 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp, } start += length; - length = head->rc_byte_len - start; +if (start > inline_len) +return -EINVAL ; + length = inline_len - start;return svc_rdma_copy_inline_range (rqstp, head, start, length); }
@@ -865,8 +874,12 @@ svc_rdma_read_multiple_chunks(struct svc_rqst *rqstp,static int svc_rdma_read_data_item (struct svc_rqst *rqstp,struct svc_rdma_recv_ctxt *head) { -return svc_rdma_build_read_chunk (rqstp, head, -pcl_first_chunk (&head->rc_read_pcl)); +struct svc_rdma_chunk *chunk =pcl_first_chunk (&head->rc_read_pcl); + +if (chunk->ch_position > head->rc_saved_arg.head[0 ].iov_len) +return -EINVAL ; + +return svc_rdma_build_read_chunk (rqstp, head, chunk); }/**
@@ -935,14 +948,17 @@ static int svc_rdma_read_call_chunk(struct svc_rqst *rqstp,pcl_first_chunk (&head->rc_call_pcl);const struct svc_rdma_pcl *pcl = &head->rc_read_pcl;struct svc_rdma_chunk *chunk, *next; -unsigned int start, length; +unsigned int call_len, start, length;int ret;if (pcl_is_empty (pcl))return svc_rdma_build_read_chunk (rqstp, head, call_chunk); + call_len = call_chunk->ch_length; start =0 ; chunk =pcl_first_chunk (pcl); +if (chunk->ch_position > call_len) +return -EINVAL ; length = chunk->ch_position; ret =svc_rdma_read_chunk_range (rqstp, head, call_chunk, start, length);
@@ -959,6 +975,10 @@ static int svc_rdma_read_call_chunk(struct svc_rqst *rqstp,break ; start += length; +if (next->ch_position > call_len) +return -EINVAL ; +if (head->rc_readbytes > next->ch_position) +return -EINVAL ; length = next->ch_position - head->rc_readbytes; ret =svc_rdma_read_chunk_range (rqstp, head, call_chunk, start, length);
@@ -967,7 +987,9 @@ static int svc_rdma_read_call_chunk(struct svc_rqst *rqstp, } start += length; - length = call_chunk->ch_length - start; +if (start > call_len) +return -EINVAL ; + length = call_len - start;return svc_rdma_read_chunk_range (rqstp, head, call_chunk, start, length); }
Signature · 1 line
2.53.0