nfsd4: fix oops on unusual readlike compound
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. Cc: stable@kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
@@ -2925,11 +2925,16 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
|
|||||||
len = maxcount;
|
len = maxcount;
|
||||||
v = 0;
|
v = 0;
|
||||||
while (len > 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 =
|
resp->rqstp->rq_vec[v].iov_base =
|
||||||
page_address(resp->rqstp->rq_respages[pn]);
|
page_address(resp->rqstp->rq_respages[pn]);
|
||||||
resp->rqstp->rq_vec[v].iov_len =
|
resp->rqstp->rq_vec[v].iov_len =
|
||||||
len < PAGE_SIZE ? len : PAGE_SIZE;
|
len < PAGE_SIZE ? len : PAGE_SIZE;
|
||||||
|
resp->rqstp->rq_resused++;
|
||||||
v++;
|
v++;
|
||||||
len -= PAGE_SIZE;
|
len -= PAGE_SIZE;
|
||||||
}
|
}
|
||||||
@@ -2975,6 +2980,8 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
|
|||||||
return nfserr;
|
return nfserr;
|
||||||
if (resp->xbuf->page_len)
|
if (resp->xbuf->page_len)
|
||||||
return nfserr_resource;
|
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++]);
|
page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
|
||||||
|
|
||||||
@@ -3024,6 +3031,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
|
|||||||
return nfserr;
|
return nfserr;
|
||||||
if (resp->xbuf->page_len)
|
if (resp->xbuf->page_len)
|
||||||
return nfserr_resource;
|
return nfserr_resource;
|
||||||
|
if (!resp->rqstp->rq_respages[resp->rqstp->rq_resused])
|
||||||
|
return nfserr_resource;
|
||||||
|
|
||||||
RESERVE_SPACE(NFS4_VERIFIER_SIZE);
|
RESERVE_SPACE(NFS4_VERIFIER_SIZE);
|
||||||
savep = p;
|
savep = p;
|
||||||
|
Reference in New Issue
Block a user