diff options
Diffstat (limited to 'fs/nfsd/nfs3xdr.c')
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 00575d776d91..7162ab7bc093 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -358,6 +358,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
358 | { | 358 | { |
359 | unsigned int len, v, hdr, dlen; | 359 | unsigned int len, v, hdr, dlen; |
360 | u32 max_blocksize = svc_max_payload(rqstp); | 360 | u32 max_blocksize = svc_max_payload(rqstp); |
361 | struct kvec *head = rqstp->rq_arg.head; | ||
361 | 362 | ||
362 | p = decode_fh(p, &args->fh); | 363 | p = decode_fh(p, &args->fh); |
363 | if (!p) | 364 | if (!p) |
@@ -367,6 +368,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
367 | args->count = ntohl(*p++); | 368 | args->count = ntohl(*p++); |
368 | args->stable = ntohl(*p++); | 369 | args->stable = ntohl(*p++); |
369 | len = args->len = ntohl(*p++); | 370 | len = args->len = ntohl(*p++); |
371 | if ((void *)p > head->iov_base + head->iov_len) | ||
372 | return 0; | ||
370 | /* | 373 | /* |
371 | * The count must equal the amount of data passed. | 374 | * The count must equal the amount of data passed. |
372 | */ | 375 | */ |
@@ -377,9 +380,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
377 | * Check to make sure that we got the right number of | 380 | * Check to make sure that we got the right number of |
378 | * bytes. | 381 | * bytes. |
379 | */ | 382 | */ |
380 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; | 383 | hdr = (void*)p - head->iov_base; |
381 | dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len | 384 | dlen = head->iov_len + rqstp->rq_arg.page_len - hdr; |
382 | - hdr; | ||
383 | /* | 385 | /* |
384 | * Round the length of the data which was specified up to | 386 | * Round the length of the data which was specified up to |
385 | * the next multiple of XDR units and then compare that | 387 | * the next multiple of XDR units and then compare that |
@@ -396,7 +398,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
396 | len = args->len = max_blocksize; | 398 | len = args->len = max_blocksize; |
397 | } | 399 | } |
398 | rqstp->rq_vec[0].iov_base = (void*)p; | 400 | rqstp->rq_vec[0].iov_base = (void*)p; |
399 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; | 401 | rqstp->rq_vec[0].iov_len = head->iov_len - hdr; |
400 | v = 0; | 402 | v = 0; |
401 | while (len > rqstp->rq_vec[v].iov_len) { | 403 | while (len > rqstp->rq_vec[v].iov_len) { |
402 | len -= rqstp->rq_vec[v].iov_len; | 404 | len -= rqstp->rq_vec[v].iov_len; |
@@ -471,6 +473,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, | |||
471 | /* first copy and check from the first page */ | 473 | /* first copy and check from the first page */ |
472 | old = (char*)p; | 474 | old = (char*)p; |
473 | vec = &rqstp->rq_arg.head[0]; | 475 | vec = &rqstp->rq_arg.head[0]; |
476 | if ((void *)old > vec->iov_base + vec->iov_len) | ||
477 | return 0; | ||
474 | avail = vec->iov_len - (old - (char*)vec->iov_base); | 478 | avail = vec->iov_len - (old - (char*)vec->iov_base); |
475 | while (len && avail && *old) { | 479 | while (len && avail && *old) { |
476 | *new++ = *old++; | 480 | *new++ = *old++; |