DragonFlyBSD Kernel Audit
DF-2993 / fix_all_three.diff
← back to finding ↓ download raw
--- nfs_orig.c	2026-09-04 20:56:50.067542992 +0000
+++ nfs_new.c	2026-09-04 20:56:50.083542794 +0000
@@ -586,6 +586,15 @@
 				error = cache_vget(&nd.nl_nch, nd.nl_cred,
 							LK_EXCLUSIVE, &vp);
 				KKASSERT(error == 0);
+			} else {
+				/*
+				 * DF-2994: the index lookup failed, so we
+				 * continue with the original vp — which was
+				 * unlocked above.  Restore its lock so the
+				 * vput() paths below cannot release an
+				 * unheld lock (guaranteed panic).
+				 */
+				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 			}
 			error = 0;
 		}
@@ -1307,11 +1316,19 @@
 nfsmout:
 		m_freem(info.mrep);
 		info.mrep = NULL;
-		error = EIO;
-		nfsm_writereply(&info, nfsd, slp, error, 2 * NFSX_UNSIGNED);
-		if (info.v3) {
-		    nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
-				     aftat_ret, &va);
+		/*
+		 * DF-2995: when we got here through NEGREPLYOUT()'s -2 path
+		 * nfsm_reply() already built a reply into info.mreq — do
+		 * not build (and leak) a second one.
+		 */
+		if (info.mreq == NULL) {
+			error = EIO;
+			nfsm_writereply(&info, nfsd, slp, error,
+					2 * NFSX_UNSIGNED);
+			if (info.v3) {
+			    nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
+					     aftat_ret, &va);
+			}
 		}
 		nfsd->nd_mreq = info.mreq;
 		nfsd->nd_mrep = NULL;
@@ -3009,6 +3026,14 @@
 		if (!error && toff && verf && verf != at.va_filerev)
 			error = NFSERR_BAD_COOKIE;
 #endif
+		/*
+		 * DF-2993: a count of 0 from the wire makes siz/fullsiz 0
+		 * which turns the degenerate-case retry loop below into an
+		 * infinite loop (no eof reply is possible because that path
+		 * requires uio_resid > 0).
+		 */
+		if (siz <= 0)
+			error = NFSERR_TOOSMALL;
 	}
 	if (!error)
 		error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0);
@@ -3305,6 +3330,12 @@
 	if (!error && toff && verf && verf != at.va_filerev)
 		error = NFSERR_BAD_COOKIE;
 #endif
+	/*
+	 * DF-2993: a dircount of 0 from the wire makes siz/fullsiz 0 which
+	 * turns the degenerate-case retry loop below into an infinite loop.
+	 */
+	if (siz <= 0)
+		error = NFSERR_TOOSMALL;
 	if (!error) {
 		error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0);
 	}