# DF-3277 — bridge_delete_span() unlinks span bif from the WRONG list → member/span list cross-linkage → KASSERT panic / UAF / double-free

## What

`bridge_delete_span()` executes

```c
TAILQ_REMOVE(&sc->sc_iflists[mycpuid], bif, bif_next);   /* if_bridge.c:1155 */
```

but span bifs are linked on `sc->sc_spanlist`
(`TAILQ_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next)`,
if_bridge.c:1832).  When the removed span bif is the **last element**
of the span list (`tqe_next == NULL`), `TAILQ_REMOVE` executes
`head->tqh_last = elm->tqe_prev` against the per-cpu **member list**
head, so `sc_iflists[0].tqh_last` is clobbered to point 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:2135-2143) —
then executes `*(sc_iflists[0].tqh_last) = alt_bif`, i.e. it writes a
**member bif pointer into `sc_spanlist.tqh_first`**, cross-linking the
two lists.  After that, span-list operations treat live member bifs as
span ports: `bridge_delete_span()`'s KASSERT fires (INVARIANTS), or on
stock kernels the member bif is unlinked from the member list and
freed while still a member → use-after-free / double-free at teardown
(`bridge_del_bif_handler` KKASSERTs `bif != NULL`, or kfree hits freed
memory).

## Reproduce (guest, as root)

```
cd /root/poc/df-3277
cc -O -o bond_corrupt bond_corrupt.c
./bond_corrupt
```

The PoC (pinned to cpu0, all frames ETHERTYPE_ARP so the netisr hash
keeps processing on cpu0):

1. bridge0 with tap0/tap1 sharing one MAC (bonding set, STP on,
   fwddelay 1s), tap2 normal member; bridge `link2` + up; tap fds
   opened before bridge-up so STP ports reach FORWARDING.
2. `spanport tap3` + `-spanport tap3` → corrupts
   `sc_iflists[0].tqh_last`.
3. Learn `02:00:00:00:00:55` on tap0, then unicast to it from tap2 →
   bonding round-robin `TAILQ_INSERT_TAIL` through the stale
   `tqh_last` → `sc_spanlist.tqh_first = <tap1's member bif>`.
4. Probe: `BRDGDELS("tap1")` — finds the MEMBER on the span list.

## Expected

```
[+] list order before bonding traffic:    [member order: tap2 tap1 tap0]
[+] after bcast learn frame:    [rtable: 02:00:00:00:00:55->tap0]
[+] list order after bonding traffic:    [member order: tap2 tap0 tap1]
panic: bridge_delete_span: not a span interface
bridge_delete_span() at bridge_delete_span+0x87
bridge_ioctl_delspan() at bridge_ioctl_delspan+0x58
```

The member-order flip (tap1 moved to tail) is the INSERT_TAIL firing;
the probe panic proves tap1 — a member with `if_bridge == sc` — was
linked on `sc_spanlist`.
