DF-2717 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | --- /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) |