summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2012-12-04 18:25:10 -0500
committerWilly Tarreau <w@1wt.eu>2013-06-10 11:43:23 +0200
commitbe1a41d754084db22bb7599edd140dff61853ced (patch)
treefca1ce4b20ff8b8718cda2396a2cf03765496048 /fs
parentfc9e795a20735726400c834f3290806139f2c957 (diff)
nfsd4: fix oops on unusual readlike compound
commit d5f50b0c290431c65377c4afa1c764e2c3fe5305 upstream. If the argument and reply together exceed the maximum payload size, then a reply with a read-like operation can overlow the rq_pages array. Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Willy Tarreau <w@1wt.eu>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4xdr.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 6d2775748077..ab87b056b0c8 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2610,11 +2610,16 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
len = maxcount;
v = 0;
while (len > 0) {
- pn = resp->rqstp->rq_resused++;
+ pn = resp->rqstp->rq_resused;
+ if (!resp->rqstp->rq_respages[pn]) { /* ran out of pages */
+ maxcount -= len;
+ break;
+ }
resp->rqstp->rq_vec[v].iov_base =
page_address(resp->rqstp->rq_respages[pn]);
resp->rqstp->rq_vec[v].iov_len =
len < PAGE_SIZE ? len : PAGE_SIZE;
+ resp->rqstp->rq_resused++;
v++;
len -= PAGE_SIZE;
}
@@ -2662,6 +2667,8 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
return nfserr;
if (resp->xbuf->page_len)
return nfserr_resource;
+ if (!resp->rqstp->rq_respages[resp->rqstp->rq_resused])
+ return nfserr_resource;
page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
@@ -2711,6 +2718,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
return nfserr;
if (resp->xbuf->page_len)
return nfserr_resource;
+ if (!resp->rqstp->rq_respages[resp->rqstp->rq_resused])
+ return nfserr_resource;
RESERVE_SPACE(8); /* verifier */
savep = p;