Skip to content

Commit dbcb379

Browse files
committed
NFSD: Insulate nfsd4_encode_read_plus() from page boundaries in the encode buffer
JIRA: https://issues.redhat.com/browse/RHEL-108616 commit c9fc777 Author: Chuck Lever <chuck.lever@oracle.com> Date: Mon Dec 30 19:28:54 2024 -0500 NFSD: Insulate nfsd4_encode_read_plus() 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 cc6cc11 commit dbcb379

File tree

1 file changed

+10
-8
lines changed

1 file changed

+10
-8
lines changed

fs/nfsd/nfs4xdr.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5323,16 +5323,17 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
53235323
struct nfsd4_read *read = &u->read;
53245324
struct file *file = read->rd_nf->nf_file;
53255325
struct xdr_stream *xdr = resp->xdr;
5326-
int starting_len = xdr->buf->len;
5326+
unsigned int eof_offset;
5327+
__be32 wire_data[2];
53275328
u32 segments = 0;
5328-
__be32 *p;
53295329

53305330
if (nfserr)
53315331
return nfserr;
53325332

5333-
/* eof flag, segment count */
5334-
p = xdr_reserve_space(xdr, 4 + 4);
5335-
if (!p)
5333+
eof_offset = xdr->buf->len;
5334+
5335+
/* Reserve space for the eof flag and segment count */
5336+
if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT * 2)))
53365337
return nfserr_io;
53375338
xdr_commit_encode(xdr);
53385339

@@ -5342,15 +5343,16 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
53425343

53435344
nfserr = nfsd4_encode_read_plus_data(resp, read);
53445345
if (nfserr) {
5345-
xdr_truncate_encode(xdr, starting_len);
5346+
xdr_truncate_encode(xdr, eof_offset);
53465347
return nfserr;
53475348
}
53485349

53495350
segments++;
53505351

53515352
out:
5352-
p = xdr_encode_bool(p, read->rd_eof);
5353-
*p = cpu_to_be32(segments);
5353+
wire_data[0] = read->rd_eof ? xdr_one : xdr_zero;
5354+
wire_data[1] = cpu_to_be32(segments);
5355+
write_bytes_to_xdr_buf(xdr->buf, eof_offset, &wire_data, XDR_UNIT * 2);
53545356
return nfserr;
53555357
}
53565358

0 commit comments

Comments
 (0)