From patchwork Thu Dec 26 16:28:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13921350 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D565A4C74 for ; Thu, 26 Dec 2024 16:28:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230537; cv=none; b=giovZwSLwP+aeknj/39wxrlFxS7IeEin+9v8bukfIeb1BjMw1QnMgHq8/dxbaqehxDrhCgTSAUeWAOX8/2o7k4PkuJLXyzxg/LfoSUGu6puUIDnpbDJ6+wb63GtL2Bsa+Cd28Ahi6y66dKY89ZT2jUAPVDPYSBL49ADTuyhCbyg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230537; c=relaxed/simple; bh=GQwAtmkyCs6amxoVHXGz+jecKwg86jAnP7qW6+XwFGI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=s1VDe2QS8/0ZXLa8CCucqaT9YWU93Wjh3H+Rl+g1zfviTothBAMjEixM+4XtRDkgbfz9M5LZXqfwLIN5GonT8qzY2CYndYKIeYa4p4dzS+wVF9gVyCCeGRMv4Tvj603WOp4Ubg1FNgjvALwcRG/hU53cmYaCzg10tjXlctTxjF4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jbhwZIQN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jbhwZIQN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 77C8BC4CED4; Thu, 26 Dec 2024 16:28:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735230537; bh=GQwAtmkyCs6amxoVHXGz+jecKwg86jAnP7qW6+XwFGI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jbhwZIQNKWHH2gWC8OLRp4J5r0gP7xN7G+rGjavOXz6/Hsk1uNytKSxpvRW6nkkcd BJ7om6S0FHiN0lAsV2X+9KA+vFF28frLG8Ne+89+IZqUbxq2i2AgHya8Kln9es0OXA ATJz9EhTuy85L2KefZuZigR03EgPByk4Ujx6vnU2vIHVqC5ZXiHImX31Nln/EjRAhn Tr/xiNEW9DlEUchm2z0Ba+t/LyhtzSerBAOzWiZe7sM+QlCixCyay60dj4LZQkoedu Bg5gDVdiUjVUi4I+f+qEdNk5T9gF05nlJTLWnNMb/rU2I8Mwmwe6tWs3STxTOxOdUR g08vma3SPCusA== From: cel@kernel.org To: Neil Brown , Jeff Layton , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: , Rick Macklem , j.david.lists@gmail.com, Chuck Lever , Rick Macklem Subject: [PATCH v3 1/6] NFSD: Encode COMPOUND operation status on page boundaries Date: Thu, 26 Dec 2024 11:28:48 -0500 Message-ID: <20241226162853.8940-2-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241226162853.8940-1-cel@kernel.org> References: <20241226162853.8940-1-cel@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Chuck Lever J. David reports an odd corruption of a READDIR reply sent to a FreeBSD client. xdr_reserve_space() has to do a special trick when the @nbytes value requests more space than there is in the current page of the XDR buffer. In that case, xdr_reserve_space() returns a pointer to the start of the next page, and then the next call to xdr_reserve_space() invokes __xdr_commit_encode() to copy enough of the data item back into the previous page to make that data item contiguous across the page boundary. But we need to be careful in the case where buffer space is reserved early for a data item whose value will be inserted into the buffer later. One such caller, nfsd4_encode_operation(), reserves 8 bytes in the encoding buffer for each COMPOUND operation. However, a READDIR result can sometimes encode file names so that there are only 4 bytes left at the end of the current XDR buffer page (though plenty of pages are left to handle the remaining encoding tasks). If a COMPOUND operation follows the READDIR result (say, a GETATTR), then nfsd4_encode_operation() will reserve 8 bytes for the op number (9) and the op status (usually NFS4_OK). In this weird case, xdr_reserve_space() returns a pointer to byte zero of the next buffer page, as it assumes the data item will be copied back into place (in the previous page) on the next call to xdr_reserve_space(). nfsd4_encode_operation() writes the op num into the buffer, then saves the next 4-byte location for the op's status code. The next xdr_reserve_space() call is part of GETATTR encoding, so the op num gets copied back into the previous page, but the saved location for the op status continues to point to the wrong spot in the current XDR buffer page because __xdr_commit_encode() moved that data item. After GETATTR encoding is complete, nfsd4_encode_operation() writes the op status over the first XDR data item in the GETATTR result. The NFS4_OK status code (0) makes it look like there are zero items in the GETATTR's attribute bitmask. The patch description of commit 2825a7f90753 ("nfsd4: allow encoding across page boundaries") [2014] remarks that NFSD "can't handle a new operation starting close to the end of a page." This bug appears to be one reason for that remark. Reported-by: J David Closes: https://lore.kernel.org/linux-nfs/3998d739-c042-46b4-8166-dbd6c5f0e804@oracle.com/T/#t Tested-by: Rick Macklem Reviewed-by: NeilBrown X-Cc: stable@vger.kernel.org Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 53fac037611c..efcb132c19d4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5760,15 +5760,14 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) struct nfs4_stateowner *so = resp->cstate.replay_owner; struct svc_rqst *rqstp = resp->rqstp; const struct nfsd4_operation *opdesc = op->opdesc; - int post_err_offset; + unsigned int op_status_offset; nfsd4_enc encoder; - __be32 *p; - p = xdr_reserve_space(xdr, 8); - if (!p) + if (xdr_stream_encode_u32(xdr, op->opnum) != XDR_UNIT) + goto release; + op_status_offset = xdr_stream_pos(xdr); + if (!xdr_reserve_space(xdr, XDR_UNIT)) goto release; - *p++ = cpu_to_be32(op->opnum); - post_err_offset = xdr->buf->len; if (op->opnum == OP_ILLEGAL) goto status; @@ -5809,20 +5808,21 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) * bug if we had to do this on a non-idempotent op: */ warn_on_nonidempotent_op(op); - xdr_truncate_encode(xdr, post_err_offset); + xdr_truncate_encode(xdr, op_status_offset + XDR_UNIT); } if (so) { - int len = xdr->buf->len - post_err_offset; + int len = xdr->buf->len - (op_status_offset + XDR_UNIT); so->so_replay.rp_status = op->status; so->so_replay.rp_buflen = len; - read_bytes_from_xdr_buf(xdr->buf, post_err_offset, + read_bytes_from_xdr_buf(xdr->buf, op_status_offset + XDR_UNIT, so->so_replay.rp_buf, len); } status: op->status = nfsd4_map_status(op->status, resp->cstate.minorversion); - *p = op->status; + write_bytes_to_xdr_buf(xdr->buf, op_status_offset, + &op->status, XDR_UNIT); release: if (opdesc && opdesc->op_release) opdesc->op_release(&op->u); From patchwork Thu Dec 26 16:28:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13921351 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 90DCC4C74 for ; Thu, 26 Dec 2024 16:28:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230538; cv=none; b=qJbrSO0Z0Xxk14NVsQUYkF69PwtGMw1BvaJPQqnOtDtXjGGF1CmEich/zAagHOK3Lzx6Cv2r9lsCuhZJPQC9P29t5Ew5HIHv7FLbSQ1qr/d7HkmUBFTZtYuEVwhVW3TwGJARMLgShKUlvLZsvtGGmeDByxGRCgUDWbndxA3H1To= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230538; c=relaxed/simple; bh=mTzUny1CMezcW1PIxqv5iGaLn8avZ/ysicpu9dh07AM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dNexhg3oYNWqgLNJOVPWhsdDl3+T5iOY8gVlruBHmeOFK1tdwZWMSTgKy9SbNvSqyLDF3hE79g/CjId39wBih4U2cPxhxkzrMt2JurOg8VWOq67u1nWaiQMGefGYCQxwvHNIeYMnXjlqNphzNDmDsIBnV164PIRh+Pnuar/TXkQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DndtlL9G; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DndtlL9G" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9508EC4CED1; Thu, 26 Dec 2024 16:28:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735230538; bh=mTzUny1CMezcW1PIxqv5iGaLn8avZ/ysicpu9dh07AM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DndtlL9GPv0uzQ4cbP1GbQm5mQWmP+DnosnbxpDtvsTKwJOPE/TgnzzrLzAh8mc0d UNoooftF1RFL5b+XmzI9QggkiMBtmWoXlKQ3x8V6vA38RyfONMwuWuWymncQCtozS6 Q3hHQxejmnZeKlzQfhUypW4GhSu5v+IMJlbSLDybHiGdnoLS1tu3ns3et+YqcClTGP Z0jpfflJztgGHRTq1T9ffdgf+G6/0XrieeczK7mUfBcE1X0ThI2buoqPUQ/TE4ae5v xBrMS9v8l2jkaHpboPOCv07zBgCn0u6ODTJWTEyDMD1F9h90kzTwFbW5j3FHReydla JY57vkMjl4e5Q== From: cel@kernel.org To: Neil Brown , Jeff Layton , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: , Rick Macklem , j.david.lists@gmail.com, Chuck Lever Subject: [PATCH v3 2/6] NFSD: Insulate nfsd4_encode_read() from page boundaries in the encode buffer Date: Thu, 26 Dec 2024 11:28:49 -0500 Message-ID: <20241226162853.8940-3-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241226162853.8940-1-cel@kernel.org> References: <20241226162853.8940-1-cel@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Chuck Lever Commit 28d5bc468efe ("NFSD: Optimize nfsd4_encode_readv()") replaced the use of write_bytes_to_xdr_buf() because it's expensive and the data items to be encoded are already properly aligned. However, the current code will corrupt the encoded data if the XDR data items that are reserved early and then poked into the XDR buffer later happen to fall on a page boundary in the XDR encoding buffer. __xdr_commit_encode can shift encoded data items in the encoding buffer so that pointers returned from xdr_reserve_space() no longer address the same part of the encoding stream. This isn't an issue for splice reads because the reserved encode buffer areas must fall in the XDR buffers header for the splice to work without error. For vectored reads, however, there is a possibility of send buffer corruption in rare cases. Fixes: 28d5bc468efe ("NFSD: Optimize nfsd4_encode_readv()") Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index efcb132c19d4..094806fe1a32 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4316,6 +4316,15 @@ static __be32 nfsd4_encode_splice_read( int status, space_left; __be32 nfserr; + /* + * Splice read doesn't work if encoding has already wandered + * into the XDR buf's page array. + */ + if (unlikely(xdr->buf->page_len)) { + WARN_ON_ONCE(1); + return nfserr_serverfault; + } + /* * Make sure there is room at the end of buf->head for * svcxdr_encode_opaque_pages() to create a tail buffer @@ -4398,25 +4407,23 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_compoundargs *argp = resp->rqstp->rq_argp; struct nfsd4_read *read = &u->read; struct xdr_stream *xdr = resp->xdr; - int starting_len = xdr->buf->len; bool splice_ok = argp->splice_ok; + unsigned int eof_offset; unsigned long maxcount; + __be32 wire_data[2]; struct file *file; - __be32 *p; if (nfserr) return nfserr; + + eof_offset = xdr_stream_pos(xdr); file = read->rd_nf->nf_file; - p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ - if (!p) { + /* Reserve space for the eof flag and byte count */ + if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT * 2))) { WARN_ON_ONCE(splice_ok); return nfserr_resource; } - if (resp->xdr->buf->page_len && splice_ok) { - WARN_ON_ONCE(1); - return nfserr_serverfault; - } xdr_commit_encode(xdr); maxcount = min_t(unsigned long, read->rd_length, @@ -4427,12 +4434,13 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, else nfserr = nfsd4_encode_readv(resp, read, file, maxcount); if (nfserr) { - xdr_truncate_encode(xdr, starting_len); + xdr_truncate_encode(xdr, eof_offset); return nfserr; } - p = xdr_encode_bool(p, read->rd_eof); - *p = cpu_to_be32(read->rd_length); + wire_data[0] = read->rd_eof ? xdr_one : xdr_zero; + wire_data[1] = cpu_to_be32(read->rd_length); + write_bytes_to_xdr_buf(xdr->buf, eof_offset, &wire_data, XDR_UNIT * 2); return nfs_ok; } @@ -5303,10 +5311,6 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, p = xdr_reserve_space(xdr, 4 + 8 + 4); if (!p) return nfserr_io; - if (resp->xdr->buf->page_len && splice_ok) { - WARN_ON_ONCE(splice_ok); - return nfserr_serverfault; - } maxcount = min_t(unsigned long, read->rd_length, (xdr->buf->buflen - xdr->buf->len)); From patchwork Thu Dec 26 16:28:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13921352 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 CB3C54C74 for ; Thu, 26 Dec 2024 16:28:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230539; cv=none; b=VmgaV7gtCW3Hl9KYIa62aPS1TRqD4rjn+Y/qUkHD5JntJrjQA+iatlbmtLKV+I7eE7JlL+9ABm6Qvwzm/B8oV6P1xa0zTQSxE/mBf7gmcTBndpobz+xglzfQ+9bnAkuDgOR2vVj47dnFbhOaxaKD3/7W/krQi/Up6PBBsag0PXI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230539; c=relaxed/simple; bh=JaWDDhfb+mmrwo7+SaQV+zwajMn+Ijykp/ajU/NijbI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rDGcYc+tPJqgvfzwqxRjNkczZHizD2dW9hNvXZx8CjTRiqTlLqyxwTkRVPDVF0gqPdFTue4KoZFVpT2RQisfIIg8Rg7DoSDGOolH3WrECCi4YUxqASUVFk8XewnC9nIFgND5URtI4+AWXYlLMcUEmKU6wchjyAY6GhC8+8GmLn0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VAd0nZzc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VAd0nZzc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A0949C4CED7; Thu, 26 Dec 2024 16:28:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735230539; bh=JaWDDhfb+mmrwo7+SaQV+zwajMn+Ijykp/ajU/NijbI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VAd0nZzcZpQx4I6R0vh24/mBgWDdvmdP7FilFQk5U+FKWOJfDnh8DiZuAhawvJ+0W yKnZ3Iecgnlp/pvSmZpXTfUtisobU25o31Iygl2ENFtlHX4/k5Hg0k669xjRIcwhle RnUnX6R52VyuLFpGc3azDDG0cAg+WDvdi65PnS7KJ3nxU6C599gE4UMm/ODxPY+6iU y8SNOP8tlYX+j8Ik3nO8BcFMxSUq3aEm8LuaBTFnqpDPZxGAwg42B/+sBOvlBWrOhv AurS3T9/SIZjvJSEYsjHKUejKYK+CKm8szqoY68mzB0hrToNbAEWnmMPVApT0r4eSj wLPX6QANIhIog== From: cel@kernel.org To: Neil Brown , Jeff Layton , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: , Rick Macklem , j.david.lists@gmail.com, Chuck Lever Subject: [PATCH v3 3/6] NFSD: Insulate nfsd4_encode_read_plus() from page boundaries in the encode buffer Date: Thu, 26 Dec 2024 11:28:50 -0500 Message-ID: <20241226162853.8940-4-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241226162853.8940-1-cel@kernel.org> References: <20241226162853.8940-1-cel@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Chuck Lever Commit eeadcb757945 ("NFSD: Simplify READ_PLUS") replaced the use of write_bytes_to_xdr_buf(), copying what was in nfsd4_encode_read() at the time. However, the current code will corrupt the encoded data if the XDR data items that are reserved early and then poked into the XDR buffer later happen to fall on a page boundary in the XDR encoding buffer. __xdr_commit_encode can shift encoded data items in the encoding buffer so that pointers returned from xdr_reserve_space() no longer address the same part of the encoding stream. Fixes: eeadcb757945 ("NFSD: Simplify READ_PLUS") Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 094806fe1a32..00e2f4fc4e19 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5336,16 +5336,17 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read = &u->read; struct file *file = read->rd_nf->nf_file; struct xdr_stream *xdr = resp->xdr; - int starting_len = xdr->buf->len; + unsigned int eof_offset; + __be32 wire_data[2]; u32 segments = 0; - __be32 *p; if (nfserr) return nfserr; - /* eof flag, segment count */ - p = xdr_reserve_space(xdr, 4 + 4); - if (!p) + eof_offset = xdr_stream_pos(xdr); + + /* Reserve space for the eof flag and segment count */ + if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT * 2))) return nfserr_io; xdr_commit_encode(xdr); @@ -5355,15 +5356,16 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, nfserr = nfsd4_encode_read_plus_data(resp, read); if (nfserr) { - xdr_truncate_encode(xdr, starting_len); + xdr_truncate_encode(xdr, eof_offset); return nfserr; } segments++; out: - p = xdr_encode_bool(p, read->rd_eof); - *p = cpu_to_be32(segments); + wire_data[0] = read->rd_eof ? xdr_one : xdr_zero; + wire_data[1] = cpu_to_be32(segments); + write_bytes_to_xdr_buf(xdr->buf, eof_offset, &wire_data, XDR_UNIT * 2); return nfserr; } From patchwork Thu Dec 26 16:28:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13921353 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 EBB0B4C74 for ; Thu, 26 Dec 2024 16:29:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230541; cv=none; b=VoKucvROItAO9wl4Bk5LmddzRXUfGqa3n9pV8oJEZPAF0vQ4DxktRS6Q+oDPykkilpFMn232WGPYZgAcCKPP4nTD1JqHvUwbZ10MvQGTQ3MOBfaaNW29bWWZf/Bib75vKdZV/IjIp73qSaop53c+PbBzOWV7qkT34Kn6Eh6+GYQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230541; c=relaxed/simple; bh=bOuMa9sMAGF/sqzqytsqwn7EWGVttZ3gpupeBr5Kh4g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=p4/yrUQKYZ1IQ9/lhsJpjzb1oObSajYZdpWGe4TYCt4NoA+oYfd/NCgY2K6QRPZnPzbGMLCSXsJOff4C5zZbj+hj2n0Iu8hMxUNJv+jn9iPdFxHiaddbstMoKL7eMYFQmKkNWsqxzKWf5H/5zpRHfeLk24JRUL6IeL7wnAwE82E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DhKcGNsN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DhKcGNsN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AE5C5C4CED4; Thu, 26 Dec 2024 16:28:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735230540; bh=bOuMa9sMAGF/sqzqytsqwn7EWGVttZ3gpupeBr5Kh4g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DhKcGNsN55BiKo8xQUv71p3O5aoyapepkK4Aq9dBbYQWLRRl7tJB3vx/HMepq9ON9 7i8VGNkx7BO6zZys/n+UecOc3t4LhldbpVJFzk25nFbJ/3WhBtvge+gjOMbgetzu8i jODEbaPrDi5ikU+pXlQDpZGE+nyYP4COBkn4MnsfO1/Vx/RZv/0rMPxIvu1qhszz5k r167RUcd9UuJHAg/a7KjGIigyM6ZydRR0YkGI3/J1YK5kZ47y6sFRQIMcWkf8nkGyG ffOEb+Mfe89sJilsMbW/C0+VKqor6iRMhpRXrqi5wAlU4K8BayYFO0XZ0TfZgvQGhn wzDuA0wiJD3CQ== From: cel@kernel.org To: Neil Brown , Jeff Layton , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: , Rick Macklem , j.david.lists@gmail.com, Chuck Lever Subject: [PATCH v3 4/6] NFSD: Insulate nfsd4_encode_read_plus_data() from page boundaries in the encode buffer Date: Thu, 26 Dec 2024 11:28:51 -0500 Message-ID: <20241226162853.8940-5-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241226162853.8940-1-cel@kernel.org> References: <20241226162853.8940-1-cel@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Chuck Lever Commit eeadcb757945 ("NFSD: Simplify READ_PLUS") replaced the use of write_bytes_to_xdr_buf(), copying what was in nfsd4_encode_read() at the time. However, the current code will corrupt the encoded data if the XDR data items that are reserved early and then poked into the XDR buffer later happen to fall on a page boundary in the XDR encoding buffer. __xdr_commit_encode can shift encoded data items in the encoding buffer so that pointers returned from xdr_reserve_space() no longer address the same part of the encoding stream. Fixes: eeadcb757945 ("NFSD: Simplify READ_PLUS") Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 00e2f4fc4e19..b770225d63dc 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5304,14 +5304,21 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, struct file *file = read->rd_nf->nf_file; struct xdr_stream *xdr = resp->xdr; bool splice_ok = argp->splice_ok; + unsigned int offset_offset; + __be32 nfserr, wire_count; unsigned long maxcount; - __be32 nfserr, *p; + __be64 wire_offset; - /* Content type, offset, byte count */ - p = xdr_reserve_space(xdr, 4 + 8 + 4); - if (!p) + if (xdr_stream_encode_u32(xdr, NFS4_CONTENT_DATA) != XDR_UNIT) return nfserr_io; + offset_offset = xdr_stream_pos(xdr); + + /* Reserve space for the byte offset and count */ + if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT * 3))) + return nfserr_io; + xdr_commit_encode(xdr); + maxcount = min_t(unsigned long, read->rd_length, (xdr->buf->buflen - xdr->buf->len)); @@ -5322,10 +5329,12 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, if (nfserr) return nfserr; - *p++ = cpu_to_be32(NFS4_CONTENT_DATA); - p = xdr_encode_hyper(p, read->rd_offset); - *p = cpu_to_be32(read->rd_length); - + wire_offset = cpu_to_be64(read->rd_offset); + write_bytes_to_xdr_buf(xdr->buf, offset_offset, &wire_offset, + XDR_UNIT * 2); + wire_count = cpu_to_be32(read->rd_length); + write_bytes_to_xdr_buf(xdr->buf, offset_offset + XDR_UNIT * 2, + &wire_count, XDR_UNIT); return nfs_ok; } From patchwork Thu Dec 26 16:28:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13921354 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 EE6194C74 for ; Thu, 26 Dec 2024 16:29:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230542; cv=none; b=p+1ygi2t+SmPRNqqzZqiJMZwzlTkn7aEE4Y2IL8d4QxXutdOun6IaygZXSNwKVvVVUEKpQ06lpaEydUdkEkZhQqPJ7RyEutzv6RxE3jBhaRLtFIb+ppu5AYK2O2J//P+GM+FOYYIau55s96fzIN5enRSGTt8+12wqCRAv/W2bV0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230542; c=relaxed/simple; bh=t0dHrzz6nCVz5GdSMqgBuHRQMV2JCKRfQ1sMFljOO0I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NT90xdOSzSn0jgY9qG4XoM0ydespl1uRAAXH4NHeDX+21d4e3QWyQwkf5opsXAqITwO7dxbPwK8A1T3L2COrXJZL2EP7zV7wC3jfz/GEhwfRp41X9wzsZHAHC21Teqst6oOsiGDT+VXNbATsTRzCl+8QtTTL93gZsRMdfGAJdDU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NXehzuBv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NXehzuBv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B916AC4CED2; Thu, 26 Dec 2024 16:29:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735230541; bh=t0dHrzz6nCVz5GdSMqgBuHRQMV2JCKRfQ1sMFljOO0I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NXehzuBvdXq+J75qVZ+hz+i1s8xeE2lXnHVW5/6uld7ffiV/N9b2BTQwyJmJmZnkq XrxdU9ZVVFvDSj9e8bqCgvMRKvIkKrzw1sFdvnseDNOfaHCXPh+6m6IDY15WkC7ZMo zzW0czbjgcdWYHA5TcBKV34Qx0MrYnuQ55JkXLiKtbDgPiA9n+0oOwaG6xyektcko4 N3xGWf6IUFImAON0084nK34KSs6u5aWMCmrxaZkChckgqw9uQT/YhbTGdZgV6w5Fm6 mNXyVMfWZuOEO9EreBMQcS4w5QIVtDVXTvJaQer5MJPSJUK+32ihN969AqMD8aoeiD niL0jp5SsFSVA== From: cel@kernel.org To: Neil Brown , Jeff Layton , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: , Rick Macklem , j.david.lists@gmail.com, Chuck Lever Subject: [PATCH v3 5/6] NFSD: Insulate nfsd4_encode_fattr4() from page boundaries in the encode buffer Date: Thu, 26 Dec 2024 11:28:52 -0500 Message-ID: <20241226162853.8940-6-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241226162853.8940-1-cel@kernel.org> References: <20241226162853.8940-1-cel@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Chuck Lever Commit ab04de60ae1c ("NFSD: Optimize nfsd4_encode_fattr()") replaced the use of write_bytes_to_xdr_buf() because it's expensive and the data items to be encoded are already properly aligned. However, there's no guarantee that the pointer returned from xdr_reserve_space() will still point to the correct reserved space in the encode buffer after one or more intervening calls to xdr_reserve_space(). It just happens to work with the current implementation of xdr_reserve_space(). This commit effectively reverts the optimization. Signed-off-by: Chuck Lever --- fs/nfsd/nfs4xdr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b770225d63dc..d4ee633b01e3 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3506,8 +3506,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct nfsd4_fattr_args args; struct svc_fh *tempfh = NULL; int starting_len = xdr->buf->len; - __be32 *attrlen_p, status; - int attrlen_offset; + unsigned int attrlen_offset; + __be32 attrlen, status; u32 attrmask[3]; int err; struct nfsd4_compoundres *resp = rqstp->rq_resp; @@ -3627,9 +3627,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, goto out; /* attr_vals */ - attrlen_offset = xdr->buf->len; - attrlen_p = xdr_reserve_space(xdr, XDR_UNIT); - if (!attrlen_p) + attrlen_offset = xdr_stream_pos(xdr); + if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT))) goto out_resource; bitmap_from_arr32(attr_bitmap, attrmask, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)); @@ -3639,7 +3638,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, if (status != nfs_ok) goto out; } - *attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT); + attrlen = cpu_to_be32(xdr_stream_pos(xdr) - attrlen_offset - XDR_UNIT); + write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, XDR_UNIT); status = nfs_ok; out: From patchwork Thu Dec 26 16:28:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13921355 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 EE8DC4C74 for ; Thu, 26 Dec 2024 16:29:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230543; cv=none; b=MlAdjAipEG6DXbLjoYxosTSYK1BCKmWsuPhaIaEGF8Yir79nyv0Hrf+6r/M2+Altq9Bm6oCQy+P0OH8g/G6Tt8h6XaBpsDHU4Urr1VhWwCGBdRt817RjxpQLYFbGT/c4ccOUDlfpcQqNHgsLXMbp4zABstE1jYDBxb5cYs0L9rA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735230543; c=relaxed/simple; bh=vAHOURc2QFDsQ+Vf8bG4s7SmgSxxIAqY+fbvIc+HAmo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MJEPhwS8ShRVSCvHJaB5xP5aGFbd0gfMlul3uAIt9fW8DWJnWFPRsfkD4E/j9iQB+/MtUWrT5rgNOydEicmnJcu1frVMCe3ZF9YJ6Wcz12ZvDPooplBUsjUKWF70Mckp/sW4ZXtaGoMrkpJuSJ8trjMWc83PNegojb0XPAckirA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JYhKL3wI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JYhKL3wI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C7CEAC4CED4; Thu, 26 Dec 2024 16:29:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735230542; bh=vAHOURc2QFDsQ+Vf8bG4s7SmgSxxIAqY+fbvIc+HAmo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JYhKL3wIn2xSMOJeIfHZfbQFT68SZEIl2Dw64AZ8VGTKwpdf/U2g2i8XDpUO+oLfS CtKnD8x7f7Cm7NhA8Xmhjk4bBoRHftGn6hbjgo90h5+W9IMfQPGx6KpOb3qr8+xxTM MoVJMb/15djnqimAUZ+2i6PZonFzFYddnH6VoYTzGZsgRTH5iDdxDuPq1bj7q7OCIV syks52XLH4JQE0emjYzj1FqQ9oG4PPTEbBuf0CqiBcG/ZSsugzy3tgbmmgzm5ib08+ 0tmg7suD4J7vpaU2FYwFfa3c7Zl2zEg2z0n+uECt3vOYI/RA0FQLFhE1oPWinAwemQ O6wMnaGLCugZA== From: cel@kernel.org To: Neil Brown , Jeff Layton , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: , Rick Macklem , j.david.lists@gmail.com, Chuck Lever Subject: [PATCH v3 6/6] SUNRPC: Document validity guarantees of the pointer returned by reserve_space Date: Thu, 26 Dec 2024 11:28:53 -0500 Message-ID: <20241226162853.8940-7-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241226162853.8940-1-cel@kernel.org> References: <20241226162853.8940-1-cel@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Chuck Lever A subtlety of this API is that if the @nbytes region traverses a page boundary, the next __xdr_commit_encode will shift the data item in the XDR encode buffer. This makes the returned pointer point to something else, leading to unexpected behavior. There are a few cases where the caller saves the returned pointer and then later uses it to insert a computed value into an earlier part of the stream. This can be safe only if either: - the data item is guaranteed to be in the XDR buffer's head, and thus is not ever going to be near a page boundary, or - the data item is no larger than 4 octets, since XDR alignment rules require all data items to start on 4-octet boundaries But that safety is only an artifact of the current implementation. It would be less brittle if these "safe" uses were eventually replaced. Signed-off-by: Chuck Lever --- net/sunrpc/xdr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 62e07c330a66..f198bb043e2f 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -1097,6 +1097,9 @@ static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, * Checks that we have enough buffer space to encode 'nbytes' more * bytes of data. If so, update the total xdr_buf length, and * adjust the length of the current kvec. + * + * The returned pointer is valid only until the next call to + * xdr_reserve_space() or xdr_commit_encode() on this stream. */ __be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) {