diff options
Diffstat (limited to 'fs/nfsd/nfs3xdr.c')
| -rw-r--r-- | fs/nfsd/nfs3xdr.c | 51 |
1 files changed, 12 insertions, 39 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index e19fc5d8bcb5..3192b544a441 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
| @@ -481,51 +481,24 @@ int | |||
| 481 | nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) | 481 | nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) |
| 482 | { | 482 | { |
| 483 | struct nfsd3_symlinkargs *args = rqstp->rq_argp; | 483 | struct nfsd3_symlinkargs *args = rqstp->rq_argp; |
| 484 | unsigned int len, avail; | 484 | char *base = (char *)p; |
| 485 | char *old, *new; | 485 | size_t dlen; |
| 486 | struct kvec *vec; | ||
| 487 | 486 | ||
| 488 | if (!(p = decode_fh(p, &args->ffh)) || | 487 | if (!(p = decode_fh(p, &args->ffh)) || |
| 489 | !(p = decode_filename(p, &args->fname, &args->flen)) | 488 | !(p = decode_filename(p, &args->fname, &args->flen))) |
| 490 | ) | ||
| 491 | return 0; | 489 | return 0; |
| 492 | p = decode_sattr3(p, &args->attrs); | 490 | p = decode_sattr3(p, &args->attrs); |
| 493 | 491 | ||
| 494 | /* now decode the pathname, which might be larger than the first page. | 492 | args->tlen = ntohl(*p++); |
| 495 | * As we have to check for nul's anyway, we copy it into a new page | ||
| 496 | * This page appears in the rq_res.pages list, but as pages_len is always | ||
| 497 | * 0, it won't get in the way | ||
| 498 | */ | ||
| 499 | len = ntohl(*p++); | ||
| 500 | if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE) | ||
| 501 | return 0; | ||
| 502 | args->tname = new = page_address(*(rqstp->rq_next_page++)); | ||
| 503 | args->tlen = len; | ||
| 504 | /* first copy and check from the first page */ | ||
| 505 | old = (char*)p; | ||
| 506 | vec = &rqstp->rq_arg.head[0]; | ||
| 507 | if ((void *)old > vec->iov_base + vec->iov_len) | ||
| 508 | return 0; | ||
| 509 | avail = vec->iov_len - (old - (char*)vec->iov_base); | ||
| 510 | while (len && avail && *old) { | ||
| 511 | *new++ = *old++; | ||
| 512 | len--; | ||
| 513 | avail--; | ||
| 514 | } | ||
| 515 | /* now copy next page if there is one */ | ||
| 516 | if (len && !avail && rqstp->rq_arg.page_len) { | ||
| 517 | avail = min_t(unsigned int, rqstp->rq_arg.page_len, PAGE_SIZE); | ||
| 518 | old = page_address(rqstp->rq_arg.pages[0]); | ||
| 519 | } | ||
| 520 | while (len && avail && *old) { | ||
| 521 | *new++ = *old++; | ||
| 522 | len--; | ||
| 523 | avail--; | ||
| 524 | } | ||
| 525 | *new = '\0'; | ||
| 526 | if (len) | ||
| 527 | return 0; | ||
| 528 | 493 | ||
| 494 | args->first.iov_base = p; | ||
| 495 | args->first.iov_len = rqstp->rq_arg.head[0].iov_len; | ||
| 496 | args->first.iov_len -= (char *)p - base; | ||
| 497 | |||
| 498 | dlen = args->first.iov_len + rqstp->rq_arg.page_len + | ||
| 499 | rqstp->rq_arg.tail[0].iov_len; | ||
| 500 | if (dlen < XDR_QUADLEN(args->tlen) << 2) | ||
| 501 | return 0; | ||
| 529 | return 1; | 502 | return 1; |
| 530 | } | 503 | } |
| 531 | 504 | ||
