aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs3xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs3xdr.c')
-rw-r--r--fs/nfsd/nfs3xdr.c51
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
481nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) 481nfs3svc_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