⬢ DragonFlyBSD Kernel Audit
DF-2717 / fix.diff
← back to finding ↓ download raw
--- /home/maxx/dfbsd/dfbsd/sys/kern/vfs_nlookup.c	2026-06-29 12:51:19.000000000 +0000
+++ guest-vfs_nlookup.c	2026-10-20 08:46:37.108583771 +0000
@@ -59,6 +59,8 @@
 #include <sys/mount.h>
 #include <sys/filedesc.h>
 #include <sys/proc.h>
+#include <sys/spinlock.h>
+#include <sys/spinlock2.h>
 #include <sys/namei.h>
 #include <sys/nlookup.h>
 #include <sys/malloc.h>
@@ -144,6 +146,7 @@
 
     if (error == 0) {
 	if (p && p->p_fd) {
+	    spin_lock(&p->p_fd->fd_spin);
 	    if (nd->nl_path[0] == '/') {
 		    if ((flags & NLC_NLNCH_NOINIT) == 0) {
 			    nd->nl_basench = &p->p_fd->fd_nrdir;
@@ -165,6 +168,7 @@
 		    nd->nl_cred = td->td_ucred;
 		    nd->nl_flags |= NLC_BORROWCRED;
 	    }
+	    spin_unlock(&p->p_fd->fd_spin);
 	} else {
 	    if ((flags & NLC_NLNCH_NOINIT) == 0) {
 		    nd->nl_basench = &rootnch;
@@ -239,7 +243,18 @@
 		nd->nl_basench = &fp->f_nchandle;
 		*fpp = fp;
 	}
-	cache_copy(nd->nl_basench, &nd->nl_nch);
+	{
+		struct filedesc *fdp = curproc->p_fd;
+
+		if (nd->nl_basench == &fdp->fd_ncdir ||
+		    nd->nl_basench == &fdp->fd_nrdir) {
+			spin_lock(&fdp->fd_spin);
+			cache_copy(nd->nl_basench, &nd->nl_nch);
+			spin_unlock(&fdp->fd_spin);
+		} else {
+			cache_copy(nd->nl_basench, &nd->nl_nch);
+		}
+	}
 done:
 	if (error)
 		nlookup_done(nd);
@@ -757,6 +772,21 @@
 		} else {
 			nctmp.ncp = nctmp.ncp->nc_parent;
 		}
+		/*
+		 * The current directory's namecache topology can become
+		 * disconnected (directory removed out from under us while
+		 * fd_ncdir still holds a reference).  nc_parent is then
+		 * NULL; recover using the process root, same as the
+		 * jail-break case above, instead of dereferencing NULL.
+		 */
+		if (nctmp.ncp == NULL) {
+			kprintf("vfs_nlookup: '..' traverse disconnected: "
+				"pid %d (%s)\n",
+				curthread->td_proc ?
+				curthread->td_proc->p_pid : 0,
+				curthread->td_comm);
+			nctmp = nd->nl_rootnch;
+		}
 		if (last_element) {
 		    cache_get_maybe_shared(&nctmp, &nch,
 					   wantsexcllock(nd, 1));
@@ -1377,7 +1407,20 @@
 		nd->nl_flags &= ~NLC_NCPISLOCKED;
 	}
 	cache_drop(&nd->nl_nch);
-	cache_copy(nd->nl_basench, &nd->nl_nch);
+	{
+		struct filedesc *fdp;
+
+		fdp = nd->nl_td->td_proc ? nd->nl_td->td_proc->p_fd : NULL;
+		if (fdp &&
+		    (nd->nl_basench == &fdp->fd_ncdir ||
+		     nd->nl_basench == &fdp->fd_nrdir)) {
+			spin_lock(&fdp->fd_spin);
+			cache_copy(nd->nl_basench, &nd->nl_nch);
+			spin_unlock(&fdp->fd_spin);
+		} else {
+			cache_copy(nd->nl_basench, &nd->nl_nch);
+		}
+	}
 
 	nd->nl_elmno = 0;
 	nd->nl_flags |= saveflag;
--- /home/maxx/dfbsd/dfbsd/sys/kern/vfs_syscalls.c	2026-06-29 12:51:19.000000000 +0000
+++ guest-vfs_syscalls.c	2026-10-20 08:46:37.388580174 +0000
@@ -2028,6 +2028,9 @@
 	struct proc *p = td->td_proc;
 	struct filedesc *fdp = p->p_fd;
 	struct vnode *vp;
+	struct vnode *ovp;
+	struct nchandle onch;
+	int setjail;
 	int error;
 
 	/*
@@ -2059,15 +2062,21 @@
 	vn_unlock(vp);			/* leave reference intact */
 	if (error == 0) {
 		lwkt_gettoken(&p->p_token);
-		vrele(fdp->fd_rdir);
+		ovp = fdp->fd_rdir;
+		setjail = (fdp->fd_jdir == NULL);
+		if (setjail)
+			vref(vp);
+		spin_lock(&fdp->fd_spin);
 		fdp->fd_rdir = vp;	/* reference inherited by fd_rdir */
-		cache_drop(&fdp->fd_nrdir);
+		onch = fdp->fd_nrdir;
 		cache_copy(nch, &fdp->fd_nrdir);
-		if (fdp->fd_jdir == NULL) {
-			fdp->fd_jdir = vp;
-			vref(fdp->fd_jdir);
+		if (setjail) {
+			fdp->fd_jdir = vp;	/* reference taken above */
 			cache_copy(nch, &fdp->fd_njdir);
 		}
+		spin_unlock(&fdp->fd_spin);
+		vrele(ovp);
+		cache_drop(&onch);
 		if ((p->p_flags & P_DIDCHROOT) == 0) {
 			p->p_flags |= P_DIDCHROOT;
 			if (p->p_depth <= 65535 - 32)