| From bfc279c7da21122df078282497fa1a632508017d Mon Sep 17 00:00:00 2001 |
| From: "J. Bruce Fields" <bfields@redhat.com> |
| Date: Tue, 4 Dec 2012 18:25:10 -0500 |
| Subject: [PATCH] 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| fs/nfsd/nfs4xdr.c | 11 ++++++++++- |
| 1 file changed, 10 insertions(+), 1 deletion(-) |
| |
| diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c |
| index 28d586a5e77e..3800e7680037 100644 |
| --- a/fs/nfsd/nfs4xdr.c |
| +++ b/fs/nfsd/nfs4xdr.c |
| @@ -2607,11 +2607,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; |
| } |
| @@ -2659,6 +2664,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++]); |
| |
| @@ -2708,6 +2715,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; |
| -- |
| 1.8.5.2 |
| |