diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -2255,10 +2255,17 @@ if ((error = VFS_ROOT(mp, &rvp))) return (error); - if ((error = VFS_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid))) + /* + * DF-0008: keep rvp referenced+locked across VFS_VPTOFH and the + * indexfile/name-length lookup below; vput exactly once on every + * path (success and error). Previously VFS_VPTOFH's error return + * leaked a usecount, and vn_get_namelen()->VOP_PATHCONF(rvp) ran + * after vput() on an unlocked/reclaimable vnode. + */ + if ((error = VFS_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid))) { + vput(rvp); return (error); - - vput(rvp); + } /* * If an indexfile was specified, pull it in. @@ -2266,9 +2273,9 @@ if (argp->ex_indexfile != NULL) { int namelen; - error = vn_get_namelen(rvp, &namelen); + error = vn_get_namelen(rvp, &namelen); /* rvp still locked */ if (error) - return (error); + goto out; nfs_pub.np_index = kmalloc(namelen, M_TEMP, M_WAITOK); error = copyinstr(argp->ex_indexfile, nfs_pub.np_index, namelen, NULL); @@ -2285,13 +2292,18 @@ } if (error) { kfree(nfs_pub.np_index, M_TEMP); - return (error); + goto out; } } + vput(rvp); nfs_pub.np_mount = mp; nfs_pub.np_valid = 1; return (0); + +out: + vput(rvp); + return (error); } struct netcred *