⬢ DragonFlyBSD Kernel Audit
DF-3557 / fix.diff
← back to finding ↓ download raw
--- a/sys/netgraph7/UI/ng_UI.c
+++ b/sys/netgraph7/UI/ng_UI.c
@@ -134,25 +134,39 @@
 /*
  * Receive a control message
  */
+/*
+ * Bound nested synchronous FLOW relaying.  A closed hook cycle (e.g. two
+ * UI nodes wired into a downstream/upstream ring) otherwise relays the
+ * item synchronously forever (ng_snd_item() applies forwarded items
+ * inline), overflowing the LWKT token array.  Pure cycles stay nested
+ * for the whole relay, so a nesting counter trips deterministically.
+ */
+#define NG_UI_FLOW_HOPS_MAX	8
+
+static volatile u_int	ng_UI_flow_hops;
+
 static int
 ng_UI_rcvmsg(node_p node, item_p item, hook_p lasthook)
 {
 	int	error;
 	const priv_p priv = NG_NODE_PRIVATE(node);
 	struct ng_mesg *msg;
+	hook_p	dest;
 
 	msg = NGI_MSG(item); /* only peeking */
 	if ((msg->header.typecookie == NGM_FLOW_COOKIE) && lasthook)  {
-		if (lasthook == priv->downlink) {
-			if (priv->uplink) {
-				NG_FWD_ITEM_HOOK(error, item, priv->uplink);
-				return (error);
-			}
-		} else {
-			if (priv->downlink) {
-				NG_FWD_ITEM_HOOK(error, item, priv->downlink);
-				return (error);
+		dest = (lasthook == priv->downlink) ? priv->uplink :
+		    priv->downlink;
+		if (dest != NULL) {
+			if (atomic_fetchadd_int(&ng_UI_flow_hops, 1) >=
+			    NG_UI_FLOW_HOPS_MAX) {
+				atomic_subtract_int(&ng_UI_flow_hops, 1);
+				NG_FREE_ITEM(item);
+				return (ELOOP);
 			}
+			NG_FWD_ITEM_HOOK(error, item, dest);
+			atomic_subtract_int(&ng_UI_flow_hops, 1);
+			return (error);
 		}
 	}