Skip to content

Commit 6f8b025

Browse files
committed
NFSD: Insulate nfsd4_encode_read_plus_data() from page boundaries in the encode buffer
JIRA: https://issues.redhat.com/browse/RHEL-108616 commit 26ea816 Author: Chuck Lever <chuck.lever@oracle.com> Date: Mon Dec 30 19:28:55 2024 -0500 NFSD: Insulate nfsd4_encode_read_plus_data() from page boundaries in the encode buffer Commit eeadcb7 ("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: eeadcb7 ("NFSD: Simplify READ_PLUS") Reviewed-by: NeilBrown <neilb@suse.de> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
1 parent dbcb379 commit 6f8b025

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

fs/nfsd/nfs4xdr.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5291,13 +5291,20 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
52915291
struct file *file = read->rd_nf->nf_file;
52925292
struct xdr_stream *xdr = resp->xdr;
52935293
bool splice_ok = argp->splice_ok;
5294+
unsigned int offset_offset;
5295+
__be32 nfserr, wire_count;
52945296
unsigned long maxcount;
5295-
__be32 nfserr, *p;
5297+
__be64 wire_offset;
52965298

5297-
/* Content type, offset, byte count */
5298-
p = xdr_reserve_space(xdr, 4 + 8 + 4);
5299-
if (!p)
5299+
if (xdr_stream_encode_u32(xdr, NFS4_CONTENT_DATA) != XDR_UNIT)
5300+
return nfserr_io;
5301+
5302+
offset_offset = xdr->buf->len;
5303+
5304+
/* Reserve space for the byte offset and count */
5305+
if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT * 3)))
53005306
return nfserr_io;
5307+
xdr_commit_encode(xdr);
53015308

53025309
maxcount = min_t(unsigned long, read->rd_length,
53035310
(xdr->buf->buflen - xdr->buf->len));
@@ -5309,10 +5316,12 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
53095316
if (nfserr)
53105317
return nfserr;
53115318

5312-
*p++ = cpu_to_be32(NFS4_CONTENT_DATA);
5313-
p = xdr_encode_hyper(p, read->rd_offset);
5314-
*p = cpu_to_be32(read->rd_length);
5315-
5319+
wire_offset = cpu_to_be64(read->rd_offset);
5320+
write_bytes_to_xdr_buf(xdr->buf, offset_offset, &wire_offset,
5321+
XDR_UNIT * 2);
5322+
wire_count = cpu_to_be32(read->rd_length);
5323+
write_bytes_to_xdr_buf(xdr->buf, offset_offset + XDR_UNIT * 2,
5324+
&wire_count, XDR_UNIT);
53165325
return nfs_ok;
53175326
}
53185327

0 commit comments

Comments
 (0)