DragonFlyBSD Kernel Audit
DF-3061 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/nfs/nfs_subs.c	2026-09-05 19:46:34.336135611 +0000
+++ b/sys/vfs/nfs/nfs_subs.c	2026-09-05 19:46:38.808078445 +0000
@@ -1001,9 +1001,22 @@
 	 * Check retry case
 	 */
 	if (nd->nl_flags & NLC_HASBUF) {
+		/*
+		 * Retry case (nfsrv_rename "goto again"): the caller is
+		 * re-using an nlookupdata that may still hold live state
+		 * from the previous iteration -- an exclusively locked and
+		 * held nl_nch, held root/jail nchandle refs, a crhold'd
+		 * nl_cred and possibly nl_dvp/nl_open_vp.
+		 *
+		 * Rescue the path buffer, then tear the remaining state
+		 * down properly.  nlookup_init_raw() below unconditionally
+		 * bzero()s nd; without this release every retry leaks the
+		 * ncp lock, cache refs and the credential reference.
+		 */
 		namebuf = nd->nl_path;
 		nd->nl_flags &= ~NLC_HASBUF;
 		nd->nl_path = NULL;
+		nlookup_done(nd);	/* NLC_HASBUF clear: buffer kept */
 		isretry = 1;
 	} else {
 		namebuf = objcache_get(namei_oc, M_WAITOK);
--- a/sys/vfs/nfs/nfs_serv.c	2026-09-05 19:46:34.336135611 +0000
+++ b/sys/vfs/nfs/nfs_serv.c	2026-09-05 19:46:45.843988501 +0000
@@ -2257,10 +2257,20 @@
             (tond.nl_nch.ncp->nc_flag & (NCF_DESTROYED | NCF_UNRESOLVED))) {
 		cache_put(&fnchd);
 		cache_put(&tnchd);
+		/*
+		 * The handles/dirs above are now released; reset the
+		 * cleanup status and pointers so a failure in the second
+		 * nfs_namei() pass cannot double-put/double-vrele them
+		 * from the nfsmout cleanup path.
+		 */
+		fnchd_status = 0;
+		tnchd_status = 0;
 		if (tdirp)
 			vrele(tdirp);
 		if (fdirp)
 			vrele(fdirp);
+		tdirp = NULL;
+		fdirp = NULL;
 		kprintf("nfs - retry rename %s to %s\n",
 			fromnd.nl_path, tond.nl_path);
 		goto again;