--- a/sys/netgraph/netgraph/ng_base.c +++ b/sys/netgraph/netgraph/ng_base.c @@ -1674,11 +1674,33 @@ * Send a data packet to a node. If the recipient has no * 'receive data' method, then silently discard the packet. */ +/* + * Maximum depth of nested synchronous ng_send_data() forwarding. + * + * v1 netgraph forwards data synchronously (the peer's rcvdata is + * called directly, in the caller's thread), with no cycle detection. + * A cyclic graph built from forwarding nodes (e.g. two ng_tee nodes + * cross-wired left<->left / right<->right, injected via left2right) + * therefore recurses without bound and kills the machine. Bound the + * nesting so cycles unwind with ELOOP and the packet is dropped + * instead. (DF-3554, v1 twin of ng7's DF-3540 core bound.) + */ +#define NG_SEND_DEPTH_MAX 16 + +static volatile u_int ng_send_depth; + int ng_send_data(hook_p hook, struct mbuf *m, meta_p meta) { int (*rcvdata)(hook_p, struct mbuf *, meta_p); int error; + + /* Cycle guard: bound nested synchronous forwarding. */ + if (atomic_fetchadd_int(&ng_send_depth, 1) >= NG_SEND_DEPTH_MAX) { + atomic_subtract_int(&ng_send_depth, 1); + NG_FREE_DATA(m, meta); + return (ELOOP); + } CHECK_DATA_MBUF(m); if (hook && (hook->flags & HK_INVALID) == 0) { @@ -1694,5 +1716,6 @@ error = ENOTCONN; NG_FREE_DATA(m, meta); } + atomic_subtract_int(&ng_send_depth, 1); return (error); }