From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E2C3F355F22 for ; Tue, 23 Jun 2026 01:47:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782179254; cv=none; b=rj/oVgOlnCp3F/iVlcclgk7ExrYSE+jlBDK3yB1wiuIaBHk0A1AvnjDjaQX47RqdCxn/h1d/nGmQWKuo5EpVWoHv3ihFKUrisIaDq+bxX78fkJNCheB2IL0N182TOoEzWKG3RWOOQPKSzM6Z4DVobny+dw62ikLhKO5eGYR11zY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782179254; c=relaxed/simple; bh=mxQr6mZNPGMjsyxgd4tX/IKRtDhS6/zpnrop+y7+vU0=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=iCRROpz0bbvmFKoFuxdB9LdFQt2jNJywCf0bBSqXA4Qo6Xk+5NeitNZc41uvZiH3yLUKf2ua9TsR8i9DdWbqpqURlwgasPMpMolYNiz0K3WO50J+b8jpbNAHdIxJE3sQF9wQGxyG7nI4cKYVyqN1U52cIkmMO2iVWGXGV0UxMhs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gFClyCwJ; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gFClyCwJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 339DE1F000E9; Tue, 23 Jun 2026 01:47:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1782179252; bh=7vVC65Iy1yV6xpJAdVT0T+/tPu/s3vPRcQHSzz0ry9g=; h=From:To:Cc:Subject:Date; b=gFClyCwJYOoWycTczZIwHKjkGJJXUHYx6xZCCKYSwVAdVc7TW2d6YvOMp748ZTwKE Sc5vXQKcqiqcuKs6JXbvYnBFHT+izgGFJ1L8BpHUMkHDSq/wMmwrnRDell5jKrBGV8 bOWoqE7Ig57Sro8e4nv6kEJ8xDZWp9FJhcvmuvg0Vi8BrEUwsv3El4tSxMtNIXEUTV zEEPb76FEX4lMDS9HecWEUCLRJnsDyWzW6+9JvqXjbMweC53GV/fh38xelhKHUU5fP +mj8XkB3/ChYREEkm+pcliD6rWJMS2nbqzjADyT96QlNpqT55cIHMbLlRR2mBv0R20 Ac6FjkSQaXUlA== From: Chuck Lever To: NeilBrown , Jeff Layton , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: , Chris Mason Subject: [PATCH] svcrdma: Reject inline replies that overflow the pull-up buffer Date: Mon, 22 Jun 2026 21:47:28 -0400 Message-ID: <20260623014728.826032-1-cel@kernel.org> X-Mailer: git-send-email 2.54.0 Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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. Fixes: e248aa7be86e ("svcrdma: Remove max_sge check at connect time") Reported-by: Chris Mason Assisted-by: kres:claude-opus-4-7 Signed-off-by: Chuck Lever --- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 47 ++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 7f6d17bf8c1f..c09659b17351 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -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; -- 2.54.0