# 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: