Skip to content

Commit 26ea816

Browse files
committed
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 <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent c9fc777 commit 26ea816

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
@@ -5305,13 +5305,20 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
53055305
struct file *file = read->rd_nf->nf_file;
53065306
struct xdr_stream *xdr = resp->xdr;
53075307
bool splice_ok = argp->splice_ok;
5308+
unsigned int offset_offset;
5309+
__be32 nfserr, wire_count;
53085310
unsigned long maxcount;
5309-
__be32 nfserr, *p;
5311+
__be64 wire_offset;
53105312

5311-
/* Content type, offset, byte count */
5312-
p = xdr_reserve_space(xdr, 4 + 8 + 4);
5313-
if (!p)
5313+
if (xdr_stream_encode_u32(xdr, NFS4_CONTENT_DATA) != XDR_UNIT)
5314+
return nfserr_io;
5315+
5316+
offset_offset = xdr->buf->len;
5317+
5318+
/* Reserve space for the byte offset and count */
5319+
if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT * 3)))
53145320
return nfserr_io;
5321+
xdr_commit_encode(xdr);
53155322

53165323
maxcount = min_t(unsigned long, read->rd_length,
53175324
(xdr->buf->buflen - xdr->buf->len));
@@ -5323,10 +5330,12 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
53235330
if (nfserr)
53245331
return nfserr;
53255332

5326-
*p++ = cpu_to_be32(NFS4_CONTENT_DATA);
5327-
p = xdr_encode_hyper(p, read->rd_offset);
5328-
*p = cpu_to_be32(read->rd_length);
5329-
5333+
wire_offset = cpu_to_be64(read->rd_offset);
5334+
write_bytes_to_xdr_buf(xdr->buf, offset_offset, &wire_offset,
5335+
XDR_UNIT * 2);
5336+
wire_count = cpu_to_be32(read->rd_length);
5337+
write_bytes_to_xdr_buf(xdr->buf, offset_offset + XDR_UNIT * 2,
5338+
&wire_count, XDR_UNIT);
53305339
return nfs_ok;
53315340
}
53325341

0 commit comments

Comments
 (0)