⬢ DragonFlyBSD Kernel Audit
DF-3277 / fix.diff
← back to finding ↓ download raw
Fix DF-3277: bridge_delete_span() unlinked the span bif from
&sc->sc_iflists[mycpuid] although span bifs are linked on
sc->sc_spanlist (bridge_ioctl_addspan, if_bridge.c:1832).  Removing
the last span entry executed head->tqh_last = elm->tqe_prev against
the per-cpu MEMBER list head, leaving sc_iflists[0].tqh_last pointing
at &sc->sc_spanlist.tqh_first.  The next TAILQ_INSERT_TAIL on the
member list (the LINK2 bonding round-robin in bridge_select_unicast,
if_bridge.c:2140) then wrote the member bif into sc_spanlist.tqh_first,
cross-linking the lists and leading to KASSERT panic / UAF / double
free on teardown (reproduced: "panic: bridge_delete_span: not a span
interface" after deleting a span port that was a live member).

--- a/sys/net/bridge/if_bridge.c
+++ b/sys/net/bridge/if_bridge.c
@@ -1152,7 +1152,8 @@ bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif)
 	KASSERT(bif->bif_ifp->if_bridge == NULL,
 	    ("%s: not a span interface", __func__));
 
-	TAILQ_REMOVE(&sc->sc_iflists[mycpuid], bif, bif_next);
+	/* Span bifs live on sc_spanlist, not on the per-cpu member lists */
+	TAILQ_REMOVE(&sc->sc_spanlist, bif, bif_next);
 	kfree(bif, M_DEVBUF);
 }