⬢ DragonFlyBSD Kernel Audit
DF-3540 / fix.diff
← back to finding ↓ download raw
--- a/sys/netgraph7/bpf/ng_bpf.c	2026-09-14 18:15:36.484957045 +0000
+++ b/sys/netgraph7/bpf/ng_bpf.c	2026-09-14 18:15:42.832877239 +0000
@@ -556,6 +556,20 @@
 #endif
 	int size;
 
+	/*
+	 * Disallow programs that would forward packets back out the same
+	 * hook they arrived on (ifMatch/ifNotMatch == thisHook).  Such a
+	 * "self-bounce", combined with any peer that re-sends (e.g. a
+	 * second ng_bpf configured the same way), forms a forwarding
+	 * cycle; netgraph7 forwards items synchronously and would recurse
+	 * until the kernel stack / token array is exhausted. (DF-3540)
+	 * The default program (empty thisHook) is unaffected.
+	 */
+	if (hp0->thisHook[0] != '\0' &&
+	    (strcmp(hp0->ifMatch, hp0->thisHook) == 0 ||
+	     strcmp(hp0->ifNotMatch, hp0->thisHook) == 0))
+		return (EINVAL);
+
 	/* Check program for validity */
 	if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len))
 		return (EINVAL);
--- a/sys/netgraph7/netgraph.h	2026-09-14 18:15:36.488956995 +0000
+++ b/sys/netgraph7/netgraph.h	2026-09-14 18:15:42.832877239 +0000
@@ -624,6 +624,7 @@
 	 */
 	struct ng_apply_info	*apply;
 	u_int	refs;
+	u_int	el_hops;	/* synchronous forwards so far (cycle guard) */
 #ifdef	NETGRAPH_DEBUG /*----------------------------------------------*/
 	char *lastfile;
 	int  lastline;
--- a/sys/netgraph7/netgraph/ng_base.c	2026-09-14 18:15:36.484957045 +0000
+++ b/sys/netgraph7/netgraph/ng_base.c	2026-09-14 18:15:51.768764894 +0000
@@ -1832,6 +1832,14 @@
 * are distributed based on the ingress node, to keep item ordering.
 \***************************************************************/
 
+/*
+ * Maximum number of synchronous forwards (hops) per item.  Bounds the
+ * ng_snd_item -> ng_apply_item recursion for cyclic graphs so it can
+ * never exhaust the kernel stack or the per-thread token array
+ * (LWKT_MAXTOKENS).  (DF-3540)
+ */
+#define	NG_HOPS_MAX	16
+
 static __inline void	ng_acquire_read(node_p node);
 static __inline void	ng_acquire_write(node_p node);
 static __inline void	ng_leave_readwrite(node_p node);
@@ -1957,7 +1965,15 @@
 
 	/*
 	 * The item wasn't queued.  Process it synchronously.
+	 *
+	 * Bound the number of synchronous forwards: each hop is a stack
+	 * frame chain and a token reference; without a bound a cyclic
+	 * graph recurses until the stack or td_toks[] overflows.
 	 */
+	if (item->el_hops++ >= NG_HOPS_MAX) {
+		ng_unref_item(item, ELOOP);
+		return (ELOOP);
+	}
 	error = ng_apply_item(item);
 
 done: