NFSd: Fix filehandle leak in exp_pseudoroot() and nfsd4_path()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 2 Sep 2009 20:48:32 +0000 (16:48 -0400)
committerJ. Bruce Fields <bfields@citi.umich.edu>
Thu, 3 Sep 2009 20:57:57 +0000 (16:57 -0400)
nfsd4_path() allocates a temporary filehandle and then fails to free it
before the function exits, leaking reference counts to the dentry and
export that it refers to.

Also, nfsd4_lookupp() puts the result of exp_pseudoroot() in a temporary
filehandle which it releases on success of exp_pseudoroot() but not on
failure; fix exp_pseudoroot to ensure that on failure it releases the
filehandle before returning.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/nfsd/export.c
fs/nfsd/nfs4xdr.c

index d946264..984a5eb 100644 (file)
@@ -1341,6 +1341,8 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
        if (rv)
                goto out;
        rv = check_nfsd_access(exp, rqstp);
+       if (rv)
+               fh_put(fhp);
 out:
        exp_put(exp);
        return rv;
index 00ed16a..0fbd50c 100644 (file)
@@ -1599,7 +1599,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
 static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat)
 {
        struct svc_fh tmp_fh;
-       char *path, *rootpath;
+       char *path = NULL, *rootpath;
+       size_t rootlen;
 
        fh_init(&tmp_fh, NFS4_FHSIZE);
        *stat = exp_pseudoroot(rqstp, &tmp_fh);
@@ -1609,14 +1610,18 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
 
        path = exp->ex_pathname;
 
-       if (strncmp(path, rootpath, strlen(rootpath))) {
+       rootlen = strlen(rootpath);
+       if (strncmp(path, rootpath, rootlen)) {
                dprintk("nfsd: fs_locations failed;"
                        "%s is not contained in %s\n", path, rootpath);
                *stat = nfserr_notsupp;
-               return NULL;
+               path = NULL;
+               goto out;
        }
-
-       return path + strlen(rootpath);
+       path += rootlen;
+out:
+       fh_put(&tmp_fh);
+       return path;
 }
 
 /*