⬢ DragonFlyBSD Kernel Audit
DF-3554 / fix.diff
← back to finding ↓ download raw
--- 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);
 }