nfsd: let nfsd_symlink assume null-terminated data
authorJ. Bruce Fields <bfields@redhat.com>
Fri, 20 Jun 2014 15:52:21 +0000 (11:52 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Tue, 8 Jul 2014 21:14:23 +0000 (17:14 -0400)
Currently nfsd_symlink has a weird hack to serve callers who don't
null-terminate symlink data: it looks ahead at the next byte to see if
it's zero, and copies it to a new buffer to null-terminate if not.

That means callers don't have to null-terminate, but they *do* have to
ensure that the byte following the end of the data is theirs to read.

That's a bit subtle, and the NFSv4 code actually got this wrong.

So let's just throw out that code and let callers pass null-terminated
strings; we've already fixed them to do that.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs3proc.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfsproc.c
fs/nfsd/vfs.c
fs/nfsd/vfs.h

index 61ef42c7b0a6dd3ad441f8bad6efd622e88eb9b1..19ba233cf006e24dd971428271f8e9379713bbe5 100644 (file)
@@ -282,7 +282,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
        fh_copy(&resp->dirfh, &argp->ffh);
        fh_init(&resp->fh, NFS3_FHSIZE);
        nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
-                                                  argp->tname, argp->tlen,
+                                                  argp->tname,
                                                   &resp->fh, &argp->attrs);
        RETURN_STATUS(nfserr);
 }
index 2b3795a135e89efd6106752cee0cb3390c089a59..7aa83bf34fa980a8bbdda261881afca2a64aaf9b 100644 (file)
@@ -623,7 +623,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        case NF4LNK:
                status = nfsd_symlink(rqstp, &cstate->current_fh,
                                      create->cr_name, create->cr_namelen,
-                                     create->cr_linkname, create->cr_linklen,
+                                     create->cr_linkname,
                                      &resfh, &create->cr_iattr);
                break;
 
index aebe23c45cbee97f75da3171c1d3dd15763700c3..583ed03877e42caf5a8f23b677cdb64f763ada10 100644 (file)
@@ -409,7 +409,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
         */
        argp->tname[argp->tlen] = '\0';
        nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
-                                                argp->tname, argp->tlen,
+                                                argp->tname,
                                                 &newfh, &argp->attrs);
 
 
index 6ffaa70300ede7c7c960ed2b51975567f2d5d314..7518c65f9a5ae438ebcec546f5a98329c476ba97 100644 (file)
@@ -1504,7 +1504,7 @@ out_nfserr:
 __be32
 nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
                                char *fname, int flen,
-                               char *path,  int plen,
+                               char *path,
                                struct svc_fh *resfhp,
                                struct iattr *iap)
 {
@@ -1513,7 +1513,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
        int             host_err;
 
        err = nfserr_noent;
-       if (!flen || !plen)
+       if (!flen || path[0] == '\0')
                goto out;
        err = nfserr_exist;
        if (isdotent(fname, flen))
@@ -1534,18 +1534,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (IS_ERR(dnew))
                goto out_nfserr;
 
-       if (unlikely(path[plen] != 0)) {
-               char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
-               if (path_alloced == NULL)
-                       host_err = -ENOMEM;
-               else {
-                       strncpy(path_alloced, path, plen);
-                       path_alloced[plen] = 0;
-                       host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced);
-                       kfree(path_alloced);
-               }
-       } else
-               host_err = vfs_symlink(dentry->d_inode, dnew, path);
+       host_err = vfs_symlink(dentry->d_inode, dnew, path);
        err = nfserrno(host_err);
        if (!err)
                err = nfserrno(commit_metadata(fhp));
index b84aef50f55d5827c14ff98a9d331780d5391caa..20e4b6679e4629958490b3c2f51b3d827af28898 100644 (file)
@@ -85,7 +85,7 @@ __be32                nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
 __be32         nfsd_readlink(struct svc_rqst *, struct svc_fh *,
                                char *, int *);
 __be32         nfsd_symlink(struct svc_rqst *, struct svc_fh *,
-                               char *name, int len, char *path, int plen,
+                               char *name, int len, char *path,
                                struct svc_fh *res, struct iattr *);
 __be32         nfsd_link(struct svc_rqst *, struct svc_fh *,
                                char *, int, struct svc_fh *);