nfsd: let nfsd_symlink assume null-terminated data

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>
This commit is contained in:
J. Bruce Fields 2014-06-20 11:52:21 -04:00
parent 0aeae33f5d
commit 52ee04330f
5 changed files with 7 additions and 18 deletions

View File

@ -282,7 +282,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
fh_copy(&resp->dirfh, &argp->ffh); fh_copy(&resp->dirfh, &argp->ffh);
fh_init(&resp->fh, NFS3_FHSIZE); fh_init(&resp->fh, NFS3_FHSIZE);
nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
argp->tname, argp->tlen, argp->tname,
&resp->fh, &argp->attrs); &resp->fh, &argp->attrs);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }

View File

@ -623,7 +623,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
case NF4LNK: case NF4LNK:
status = nfsd_symlink(rqstp, &cstate->current_fh, status = nfsd_symlink(rqstp, &cstate->current_fh,
create->cr_name, create->cr_namelen, create->cr_name, create->cr_namelen,
create->cr_linkname, create->cr_linklen, create->cr_linkname,
&resfh, &create->cr_iattr); &resfh, &create->cr_iattr);
break; break;

View File

@ -409,7 +409,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
*/ */
argp->tname[argp->tlen] = '\0'; argp->tname[argp->tlen] = '\0';
nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
argp->tname, argp->tlen, argp->tname,
&newfh, &argp->attrs); &newfh, &argp->attrs);

View File

@ -1504,7 +1504,7 @@ out_nfserr:
__be32 __be32
nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
char *fname, int flen, char *fname, int flen,
char *path, int plen, char *path,
struct svc_fh *resfhp, struct svc_fh *resfhp,
struct iattr *iap) struct iattr *iap)
{ {
@ -1513,7 +1513,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
int host_err; int host_err;
err = nfserr_noent; err = nfserr_noent;
if (!flen || !plen) if (!flen || path[0] == '\0')
goto out; goto out;
err = nfserr_exist; err = nfserr_exist;
if (isdotent(fname, flen)) if (isdotent(fname, flen))
@ -1534,18 +1534,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (IS_ERR(dnew)) if (IS_ERR(dnew))
goto out_nfserr; goto out_nfserr;
if (unlikely(path[plen] != 0)) { host_err = vfs_symlink(dentry->d_inode, dnew, path);
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);
err = nfserrno(host_err); err = nfserrno(host_err);
if (!err) if (!err)
err = nfserrno(commit_metadata(fhp)); err = nfserrno(commit_metadata(fhp));

View 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 *, __be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
char *, int *); char *, int *);
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *, __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 *); struct svc_fh *res, struct iattr *);
__be32 nfsd_link(struct svc_rqst *, struct svc_fh *, __be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
char *, int, struct svc_fh *); char *, int, struct svc_fh *);