svcrdma: Reject inline replies that overflow the pull-up buffer
Subsystems (3)
Chuck Lever
maintainerPATCH 1/1 svcrdma: Reject inline replies that overflow the pull-up buffer
An RPC-over-RDMA client can request a reply, such as an NFS READ payload, without providing a Write list or a Reply chunk to carry it. When such a reply needs more scatter/gather entries than the device's Send Queue supports, svc_rdma_pull_up_needed() selects pull-up and svc_rdma_pull_up_reply_msg() linearizes the whole reply into sctxt->sc_xprt_buf. That buffer is only sc_max_req_size bytes, while the reply on this path is bounded only by the client's request, so svc_rdma_xb_linearize() copies past the end of the buffer and corrupts adjacent slab memory. The oversized length is then stored in sc_sges[0].length and posted, so the device also reads beyond the mapped region.
The SGE-exhaustion branch is the only pull-up path that can exceed the buffer: the threshold branch pulls up only replies smaller than RPCRDMA_PULLUP_THRESH, and replies that fit the device's SGE budget are sent directly without linearization. Make svc_rdma_pull_up_needed() report -E2BIG when the reply it would pull up cannot fit sc_max_req_size, and fail the request with ERR_CHUNK as RFC 8166 Section 4.5.3 directs rather than dropping the connection.
The helper no longer answers a simple yes/no question: it now reports pull-up, no pull-up, or -E2BIG for a reply too large to linearize. Rename svc_rdma_pull_up_needed() to svc_rdma_check_pull_up() so its name no longer implies a boolean predicate.
--- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 47 ++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-)
net/sunrpc/xprtrdma/svc_rdma_sendto.c +32 -15
@@ -825,20 +825,21 @@ static int svc_rdma_xb_count_sges(const struct xdr_buf *xdr, }/** -* svc_rdma_pull_up_needed - Determine whether to use pull-up +* svc_rdma_check_pull_up - Determine whether to use pull-up * @rdma: controlling transport * @sctxt: send_ctxt for the Send WR * @write_pcl: Write chunk list provided by client * @xdr: xdr_buf containing RPC message to transmit * * Returns: -* %true if pull-up must be used -* %false otherwise +* %1 if pull-up must be used +* %0 if pull-up is not needed +* %-E2BIG if the reply is too large to be pulled up */ -static bool svc_rdma_pull_up_needed (const struct svcxprt_rdma *rdma, -const struct svc_rdma_send_ctxt *sctxt, -const struct svc_rdma_pcl *write_pcl, -const struct xdr_buf *xdr) +static int svc_rdma_check_pull_up (const struct svcxprt_rdma *rdma, +const struct svc_rdma_send_ctxt *sctxt, +const struct svc_rdma_pcl *write_pcl, +const struct xdr_buf *xdr) {/* Resources needed for the transport header */ struct svc_rdma_pullup_data args = {
@@ -850,11 +851,22 @@ static bool svc_rdma_pull_up_needed(const struct svcxprt_rdma *rdma, ret =pcl_process_nonpayloads (write_pcl, xdr, svc_rdma_xb_count_sges, &args);if (ret <0 ) -return false; +return 0 ;if (args.pd_length <RPCRDMA_PULLUP_THRESH ) -return true; -return args.pd_num_sges >= rdma->sc_max_send_sges; +return 1 ; +if (args.pd_num_sges < rdma->sc_max_send_sges) +return 0 ; + +/* +* The reply has too many SGEs to Send inline, so it has to be +* linearized into sc_xprt_buf. That buffer holds only +* sc_max_req_size bytes, so a larger reply cannot be pulled up. +* RFC 8166 Section 4.5.3 requires responding with ERR_CHUNK. +*/ +if (args.pd_length > rdma->sc_max_req_size) +return -E2BIG ; +return 1 ; }/**
@@ -910,7 +922,7 @@ static int svc_rdma_xb_linearize(const struct xdr_buf *xdr,* Assemble the elements of @xdr into the transport header buffer. * * Assumptions: -* pull_up_needed has determined that @xdr will fit in the buffer. +* check_pull_up has determined that @xdr will fit in the buffer. * * Returns: * %0 if pull-up was successful
@@ -945,6 +957,7 @@ static int svc_rdma_pull_up_reply_msg(const struct svcxprt_rdma *rdma,* * Returns: * %0 if DMA mapping was successful. +* %-E2BIG if the reply is too large to be pulled up * %-EMSGSIZE if a buffer manipulation problem occurred * %-EIO if DMA mapping failed *
@@ -960,6 +973,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, .md_rdma = rdma, .md_ctxt = sctxt, }; +int ret;/* Set up the (persistently-mapped) transport header SGE. */ sctxt->sc_send_wr.num_sge =1 ;
@@ -974,7 +988,10 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,/* For pull-up, svc_rdma_send() will sync the transport header. * No additional DMA mapping is necessary. */ -if (svc_rdma_pull_up_needed (rdma, sctxt, write_pcl, xdr)) + ret =svc_rdma_check_pull_up (rdma, sctxt, write_pcl, xdr); +if (ret <0 ) +return ret; +if (ret)return svc_rdma_pull_up_reply_msg (rdma, sctxt, write_pcl, xdr); return pcl_process_nonpayloads(write_pcl, xdr,
@@ -1162,7 +1179,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) &rctxt->rc_reply_pcl, sctxt, &rqstp->rq_res);if (ret <0 ) - goto reply_chunk; + goto send_err; rc_size = ret; }
@@ -1183,10 +1200,10 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) ret =svc_rdma_send_reply_msg (rdma, sctxt, rctxt, rqstp);if (ret <0 ) - goto put_ctxt; + goto send_err;return 0 ; -reply_chunk: +send_err:if (ret != -E2BIG && ret != -EINVAL ) goto put_ctxt;
Signature · 1 line
2.54.0