DragonFlyBSD Kernel Audit
DF-0884 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/smbfs/smbfs_io.c b/sys/vfs/smbfs/smbfs_io.c
--- a/sys/vfs/smbfs/smbfs_io.c
+++ b/sys/vfs/smbfs/smbfs_io.c
@@ -199,7 +199,18 @@
 		return EINVAL;
 	td = uiop->uio_td;
 	if (vp->v_type == VDIR) {
-		lks = LK_EXCLUSIVE;/*lockstatus(&vp->v_lock, td);*/
+		/*
+		 * vn_read() acquires the vnode SHARED, but smbfs_readvdir()
+		 * mutates per-vnode directory-iteration state (np->n_dirseq,
+		 * np->n_dirofs).  Two concurrent read(2) on the same directory
+		 * vnode would race smbfs_findnext() against smbfs_findclose()
+		 * and use-after-free the smbfs_fctx, so upgrade to exclusive
+		 * when we currently hold it shared (the normal read(2) path).
+		 * smbfs_readdir() already holds it exclusively, so detect the
+		 * current state rather than hardcoding LK_EXCLUSIVE (which left
+		 * the upgrade as dead code and the race open).
+		 */
+		lks = vn_islocked(vp);
 		if (lks == LK_SHARED)
 			vn_lock(vp, LK_UPGRADE | LK_RETRY);
 		error = smbfs_readvdir(vp, uiop, cred);