# DF-3276 — VERDICT

**REPRODUCED — panic (deterministic).**

## Environment

Guest: DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026,
X86_64_GENERIC, 6 CPUs, stock kernel, if_bridge compiled in.
`sys/net/bridge/if_bridge.c` in this tree is byte-identical to
DragonFlyBSD master (verified by diff against the upstream GitHub raw
copy), so the bug is a live upstream defect, not an artifact of this
audit tree.

## How it was reproduced (attempt 1 of 1 — first try panicked)

1. `ifconfig bridge0 create`, `ifconfig tap0|tap1|tap2 create + up`,
   `ifconfig bridge0 addm tap0 addm tap1 up` (run.sh).
2. PoC issues `SIOCSDRVSPEC/BRDGADDS` to make tap2 a span port
   (`sc->sc_span = 1`, tap2->if_bridge stays NULL by design).
3. In the captured run the kernel panicked *before any injected frame
   was needed*: the bridge interface's own IPv6 link-local DAD
   transmission went through `bridge_output()`, which calls
   `bridge_span()` for every output packet (if_bridge.c:2241, 2358).
   `bridge_span()` copied the frame and called
   `bridge_enqueue(tap2_span_ifp)` (if_bridge.c:3279).  The async
   netmsg handler `bridge_enqueue_handler()` then called
   `bridge_handoff(dst_ifp->if_bridge, ...)` with `if_bridge == NULL`
   (if_bridge.c:4430), and `bridge_handoff()` executed
   `bifp = sc->sc_ifp` (if_bridge.c:4440) on the NULL softc.

Panic (full text in panic.txt, from the serial console):

```
Fatal trap 12: page fault while in kernel mode
cpuid = 0; lapic id = 0
fault virtual address	= 0x3b8
instruction pointer	= 0x8:0xffffffff82622d11
current process	= Idle      (netisr0 context)
Stopped at bridge_handoff+0x11: movq 0x3b8(%rdi),%rax
```

`%rdi` = 0 (the NULL softc), `0x3b8` = offsetof(struct bridge_softc,
sc_ifp) — the disassembly pins the fault to `bifp = sc->sc_ifp`
exactly.  The guest hung at `db>` and `vm.sh status` reported `down`.

## Why span ports have if_bridge == NULL

- Only `bridge_ioctl_add()` assigns `ifs->if_bridge = sc`
  (if_bridge.c:1300).
- `bridge_ioctl_addspan()` never touches `if_bridge`; it only checks
  `ifs->if_bridge != NULL` to reject members (if_bridge.c:1807).
- `bridge_delete_span()` KASSERTs `bif->bif_ifp->if_bridge == NULL`
  ("not a span interface", if_bridge.c:1152) — the kernel itself
  documents the invariant that makes the enqueue path crash.

## Impact

- Configuring any span (mirror) port requires root (`BRDGADDS` is
  `BC_F_SUSER`-gated), but once configured the panic is triggered by
  ANY frame: forwarded traffic, adjacent-host frames, or the bridge's
  own output (IPv6 DAD/NDP, ARP).  The span feature is unusable — it
  panics the box on the first packet, deterministically.
- Secondary vector (same sink): a member deleted between
  `bridge_enqueue()` and the handler runs reads `if_bridge == NULL`
  too (cleared at if_bridge.c:1071 before the sync that drains
  pending enqueue msgs) — a race variant of DF-0271 with a different,
  unchecked sink.

## Exploit chain

Not applicable (NULL-page read at fixed offset → panic).  On this
guest there is no way to map page 0, so this is a pure DoS/panic.

## Fix validation

fix.diff applied to the guest's /usr/src copy; kernel rebuilt
(`make nativekernel`), rebooted; the identical PoC then ran to
completion with no panic and the mirrored frames appeared on the span
tap (see run_fixed.log).  Baseline vs patched behavior recorded in
this pack (build.log / run.log / panic.txt vs run_fixed.log).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
