⬢ DragonFlyBSD Kernel Audit
DF-3331 / fix.diff
← back to finding ↓ download raw
--- /home/maxx/dfbsd/dfbsd/sys/netinet6/nd6.c	2026-06-29 12:51:19.000000000 +0000
+++ nd6.c	2026-09-10 23:43:38.749415625 +0000
@@ -497,6 +497,16 @@
 		case ND6_LLINFO_WAITDELETE:
 			next = nd6_free(rt);
 			break;
+		case ND6_LLINFO_NOSTATE:
+			/*
+			 * DF-3331: created by route cloning (RTM_RESOLVE)
+			 * but never moved to INCOMPLETE because the output
+			 * path does not do neighbor resolution (e.g. gif).
+			 * Its creation grace (nd6_delay) has expired, and
+			 * nothing else will ever free it -- reap it here.
+			 */
+			next = nd6_free(rt);
+			break;
 		case ND6_LLINFO_INCOMPLETE:
 			if (ln->ln_asked++ >= nd6_mmaxtries) {
 				struct mbuf *m = ln->ln_hold;
@@ -1314,9 +1324,15 @@
 		        /*
 			 * When req == RTM_RESOLVE, rt is created and
 			 * initialized in rtrequest(), so rt_expire is 0.
+			 *
+			 * DF-3331: give the entry a grace period.  On
+			 * ND-resolving links nd6_resolve() moves it to
+			 * INCOMPLETE synchronously in the same output call;
+			 * on other links (e.g. gif) nothing ever does, and
+			 * nd6_timer() now reaps it when the grace expires.
 			 */
 			ln->ln_state = ND6_LLINFO_NOSTATE;
-			ln->ln_expire = time_uptime;
+			ln->ln_expire = time_uptime + nd6_delay;
 		}
 		rt->rt_flags |= RTF_LLINFO;
 		ln->ln_next = llinfo_nd6.ln_next;
@@ -1709,11 +1725,15 @@
 
 	rt = nd6_lookup(from, 0, ifp);
 	if (!rt) {
-#if 0
-		/* nothing must be done if there's no lladdr */
+		/*
+		 * DF-3331: do not create a neighbor cache entry when the
+		 * ND message carries no link-layer address option
+		 * (RFC 4861 7.2.3: nothing to record).  Entries created
+		 * here are ND6_LLINFO_NOSTATE, and see the timer change
+		 * below for why that mattered.
+		 */
 		if (!lladdr || !lladdrlen)
 			return NULL;
-#endif
 
 		rt = nd6_lookup(from, 1, ifp);
 		is_newentry = 1;