DragonFlyBSD Kernel Audit
DF-0008 / fix.diff
← back to finding ↓ download raw
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 *