⬢ DragonFlyBSD Kernel Audit
DF-3134 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/dirfs/dirfs_subr.c b/sys/vfs/dirfs/dirfs_subr.c
index 0fda4856..4f85fea5 100644
--- a/sys/vfs/dirfs/dirfs_subr.c
+++ b/sys/vfs/dirfs/dirfs_subr.c
@@ -463,6 +463,14 @@ dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur,
 	if (cur == NULL)
 		return NULL;
 
+	/*
+	 * Serialize the fd walk + node ref against
+	 * dirfs_node_setpassive()'s check-then-close of dn_fd.  The token
+	 * is released by dirfs_dropfd() once the caller is done using the
+	 * descriptor.
+	 */
+	lwkt_gettoken(&dmp->dm_token);
+
 	buf = kmalloc(MAXPATHLEN + 1, M_DIRFS_MISC, M_WAITOK | M_ZERO);
 	count = 0;
 
@@ -489,6 +497,7 @@ dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur,
 	} else {
 		dbg(9, "failed too long\n");
 		kfree(buf, M_DIRFS_MISC);
+		lwkt_reltoken(&dmp->dm_token);
 		*pathfreep = NULL;
 		*pathto = NULL;
 		dnp1 = NULL;
@@ -501,8 +510,11 @@ dirfs_dropfd(dirfs_mount_t dmp, dirfs_node_t dnp1, char *pathfree)
 {
 	if (pathfree)
 		kfree(pathfree, M_DIRFS_MISC);
-	if (dnp1)
+	if (dnp1) {
 		dirfs_node_drop(dmp, dnp1);
+		/* pairs with lwkt_gettoken() in dirfs_findfd() */
+		lwkt_reltoken(&dmp->dm_token);
+	}
 }
 
 int
@@ -844,7 +856,13 @@ dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state)
 		 *
 		 * The descriptor for the root node is NEVER closed by
 		 * this function.
+		 *
+		 * The token pairs with the one held across
+		 * dirfs_findfd()..dirfs_dropfd() so an in-flight consumer
+		 * can never lose its dn_fd (or have the fd number recycled
+		 * underneath it) while it is being used.
 		 */
+		lwkt_gettoken(&dmp->dm_token);
 		vp = dnp->dn_vnode;
 		if (dirfs_node_refcnt(dnp) == 2 && vp &&
 		    dnp->dn_fd != DIRFS_NOFD &&
@@ -864,6 +882,7 @@ dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state)
 				dnp->dn_fd = DIRFS_NOFD;
 			}
 		}
+		lwkt_reltoken(&dmp->dm_token);
 		dirfs_node_drop(dmp, dnp);
 	}
 }