diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2023-03-17 22:09:20 +0100 |
---|---|---|
committer | Chuck Lever <chuck.lever@oracle.com> | 2023-04-26 15:05:01 +0200 |
commit | 0f5162480bd25bd97b91c9153db7afbd89698804 (patch) | |
tree | a273f9e1648e80256d5e4b9321f624d0a9424cd4 /fs/nfsd | |
parent | sunrpc: simplify two-level sysctl registration for svcrdma_parm_table (diff) | |
download | linux-0f5162480bd25bd97b91c9153db7afbd89698804.tar.xz linux-0f5162480bd25bd97b91c9153db7afbd89698804.zip |
NFSD: Watch for rq_pages bounds checking errors in nfsd_splice_actor()
There have been several bugs over the years where the NFSD splice
actor has attempted to write outside the rq_pages array.
This is a "should never happen" condition, but if for some reason
the pipe splice actor should attempt to walk past the end of
rq_pages, it needs to terminate the READ operation to prevent
corruption of the pointer addresses in the fields just beyond the
array.
A server crash is thus prevented. Since the code is not behaving,
the READ operation returns -EIO to the client. None of the READ
payload data can be trusted if the splice actor isn't operating as
expected.
Suggested-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/vfs.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 5783209f17fc..10aa68ca82ef 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -930,6 +930,9 @@ nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, int may_flags, * Grab and keep cached pages associated with a file in the svc_rqst * so that they can be passed to the network sendmsg/sendpage routines * directly. They will be released after the sending has completed. + * + * Return values: Number of bytes consumed, or -EIO if there are no + * remaining pages in rqstp->rq_pages. */ static int nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, @@ -948,7 +951,8 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, */ if (page == *(rqstp->rq_next_page - 1)) continue; - svc_rqst_replace_page(rqstp, page); + if (unlikely(!svc_rqst_replace_page(rqstp, page))) + return -EIO; } if (rqstp->rq_res.page_len == 0) // first call rqstp->rq_res.page_base = offset % PAGE_SIZE; |