⬢ DragonFlyBSD Kernel Audit
DF-3276 / fix.diff
← back to finding ↓ download raw
Fix DF-3276: span ports must not go through bridge_enqueue() -- span
interfaces never have if_bridge set (only member add sets it,
if_bridge.c:1300; addspan never does), so bridge_enqueue_handler()
passed bridge_handoff() a NULL softc and the first mirrored packet
panicked in bridge_handoff (bifp = sc->sc_ifp).  Mirror the frame
directly instead (also more correct: span must not rewrite the source
MAC), and add a defensive NULL guard in bridge_enqueue_handler() for
the member-deletion race (if_bridge is cleared at if_bridge.c:1071
before the netmsg_service_sync() that drains pending enqueue msgs).

--- a/sys/net/bridge/if_bridge.c
+++ b/sys/net/bridge/if_bridge.c
@@ -3276,7 +3276,12 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m)
 		if (mc == NULL) {
 			IFNET_STAT_INC(sc->sc_ifp, oerrors, 1);
 			continue;
 		}
-		bridge_enqueue(dst_if, mc);
+		/*
+		 * Span ports never have if_bridge set (only members do);
+		 * hand the copy off directly and keep the original
+		 * source MAC (no rewrite).
+		 */
+		bridge_handoff(sc, dst_if, mc, 0);
 	}
 
 	ifnet_deserialize_all(bifp);
@@ -4426,7 +4431,13 @@ bridge_enqueue_handler(netmsg_t msg)
 	dst_ifp = nmp->base.lmsg.u.ms_resultp;
 	mbuftrackid(m, 71);
 
-	bridge_handoff(dst_ifp->if_bridge, dst_ifp, m, 1);
+	/*
+	 * A member can be deleted (if_bridge cleared) between the
+	 * enqueue and this handler; drop instead of dereferencing NULL.
+	 */
+	if (dst_ifp->if_bridge == NULL)
+		m_freem(m);
+	else
+		bridge_handoff(dst_ifp->if_bridge, dst_ifp, m, 1);
 }