⬢ DragonFlyBSD Kernel Audit
DF-3559 / fix.diff
← back to finding ↓ download raw
# DF-3559 fix validation -- framework subset of the DF-3540 fix
# (el_hops hop-bound in ng_snd_item). The ng_bpf.c node-local hunk of
# the original diff is intentionally omitted: ng_hub needs NO node-local
# guard -- the panic is pure topology, so only the framework bound is
# required to stop it.
--- 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: