Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSd: Fix filehandle leak in exp_pseudoroot() and nfsd4_path()

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>

authored by

Trond Myklebust and committed by
J. Bruce Fields
2671a4bf bc6c53d5

+12 -5
+2
fs/nfsd/export.c
··· 1341 1341 if (rv) 1342 1342 goto out; 1343 1343 rv = check_nfsd_access(exp, rqstp); 1344 + if (rv) 1345 + fh_put(fhp); 1344 1346 out: 1345 1347 exp_put(exp); 1346 1348 return rv;
+10 -5
fs/nfsd/nfs4xdr.c
··· 1599 1599 static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) 1600 1600 { 1601 1601 struct svc_fh tmp_fh; 1602 - char *path, *rootpath; 1602 + char *path = NULL, *rootpath; 1603 + size_t rootlen; 1603 1604 1604 1605 fh_init(&tmp_fh, NFS4_FHSIZE); 1605 1606 *stat = exp_pseudoroot(rqstp, &tmp_fh); ··· 1610 1609 1611 1610 path = exp->ex_pathname; 1612 1611 1613 - if (strncmp(path, rootpath, strlen(rootpath))) { 1612 + rootlen = strlen(rootpath); 1613 + if (strncmp(path, rootpath, rootlen)) { 1614 1614 dprintk("nfsd: fs_locations failed;" 1615 1615 "%s is not contained in %s\n", path, rootpath); 1616 1616 *stat = nfserr_notsupp; 1617 - return NULL; 1617 + path = NULL; 1618 + goto out; 1618 1619 } 1619 - 1620 - return path + strlen(rootpath); 1620 + path += rootlen; 1621 + out: 1622 + fh_put(&tmp_fh); 1623 + return path; 1621 1624 } 1622 1625 1623 1626 /*