# DF-5509 — VERDICT

**Status: reproduced (impact: dos). Confidence: certain.**
Fix authored after verification and **validated on the guest** (same trigger:
unpatched 311,162 interrupts through the armed window; patched: 0 during the
window, USB fully functional).

## Root cause

`ehci_pci_attach()` arms the interrupt handler at
`sys/bus/u4b/controller/ehci_pci.c:390-391` — **before**
`ehci_pci_take_controller()` (:398, whose LEGSUP BIOS-handoff wait
:517-546 parks the attach for up to 5 s) and before `ehci_init()` (:451)
latches the geometry. newbus allocates the softc with
`M_INTWAIT | M_ZERO` (sys/kern/subr_bus.c:1953-1954), so through the whole
window `sc_offs == 0` (set only at ehci.c:308) and `sc_eintrs == 0`
(set only at ehci.c:353). The armed `ehci_interrupt()` (ehci.c:1490) then:

1. reads "USBSTS" at `io_hdl + sc_offs(0) + EHCI_USBSTS(0x04)` — i.e. the
   **HCSPARAMS capability register** (measured: 6, N_PORTS — never the real
   status register);
2. computes `status & sc->sc_eintrs == 0` and exits via `goto done`
   (ehci.c:1509-1511) **without writing USBSTS to acknowledge**.

With `(USBINTR & USBSTS) != 0` at handler-arm time — exactly what a BIOS
mid-handoff (or a malicious controller) leaves behind — the level-triggered
INTx re-fires for every instant of the window. The **first** code that
touches USBINTR/USBSTS after arming is `ehci_hcreset()` (ehci.c:215,
EOWRITE4 USBCMD=0 + HCRESET) reached only via `ehci_init()` at ehci.c:335 —
*after* the up-to-5 s handoff park. This ordering defect is distinct from
the file's known findings (DF-1092/DF-2335: the walk itself can be
unbounded) and from DF-5282 (ehci.c latching unvalidated geometry): the
handler is mute here **regardless of geometry correctness**, because it is
armed before the softc fields it depends on exist.

## Verification methodology

QEMU 7.2.22 i440fx, DragonFly 6.5-DEVELOPMENT, `-device usb-ehci,id=ehci0`
cold-boot (ehci0@pci0:0:3:0, 8086:24cd, BAR 0xfebd1000/0x1000, IRQ 10,
6 ports). QEMU's usb-ehci implements the LEGSUP extended capability at
EECP=0x68 with **writable BIOS_SEM/OS_SEM**, so the entire BIOS-handoff
dance is exercisable from the guest (root `pciconf -w`). The device-side
preconditions (USBINTR=0x3F enabled, USBCMD.RS=1, BIOS_SEM=1 — the
"BIOS residue") were set by a root KLD (`ehciarm.ko`, DF-5282's poison
methodology) and a QEMU-monitor `device_add usb-kbd` fired a **real**
port-change event at a chosen instant. 100% stock driver code in every
measured run; softc re-zeroing on each kldload verified from
subr_bus.c:1943-1954.

## Observed results

1. **Dry run** — BIOS_SEM=1, clean controller state: serial console shows
   `usbus0: waiting for BIOS to give up control` → `timed out waiting for
   BIOS` (~5 s park inside ehci_pci_take_controller), attach then completes
   normally. The park is deterministic and opens exactly between
   bus_setup_intr (:391) and ehci_init (:451).
2. **End-to-end bounded storm (stock driver)** — armed residue + park +
   one real port event mid-park: ehci0 interrupt counter 393,106 →
   **704,268 = 311,162 interrupts** through a single attach; attach
   nonetheless completes (ehci_hcreset clears the state at ehci.c:335) and
   the keyboard enumerates. On this 6-vCPU guest the storm is bounded; the
   attaching CPU is saturated for the whole park.
3. **Control** — identical park, no pending event: Δ = **55** interrupts.
   A single port event in the armed pre-init window is a **5,657×**
   interrupt amplification on stock driver code.
4. **Permanent variant** — pre-init handler state injected on the live,
   otherwise-healthy driver (`sc_eintrs = 0` — the exact M_ZERO value;
   `sc_offs` left CORRECT at 0x20): one real port event → sustained
   **~33,000 interrupts/s**, ~900 K interrupts over 14 s, load average 3.6
   and climbing, **no self-heal** (nothing will ever acknowledge; no
   hcreset is coming). Restoring `sc_eintrs=0x37` stops the storm dead
   within one delivery (1,603,736 → 1,605,667 ≈ tail only, load 0.00).
   This is the boot-window outcome on machines where the storming IRQ
   thread starves the attaching thread (e.g. 1-vCPU): `ehci_hcreset` is
   never reached → permanent boot-time machine live-lock.

## Why this is the driver's defect (attribution)

A controller that can assert INTx forever can DoS the machine regardless of
any driver — that generic case is out of scope (same attribution DF-5282
made). The **driver-controllable** defect here is the ordering: the handler
is registered while it provably cannot acknowledge anything (sc_offs=0 →
reads the wrong register; sc_eintrs=0 → masks every bit), and the window
deliberately includes a 5-second sleep. A 2-instruction quiesce before
`bus_setup_intr` (the validated fix) removes the entire window.

## QEMU device-model notes (repro fidelity)

- QEMU's `ehci_opreg_write` for USBINTR does **not** re-evaluate the INTx
  line, but `ehci_port_attach` raises PCD **and** re-evaluates immediately
  (hw/usb/hcd-ehci.c v7.2: ehci_raise_irq/ehci_update_irq) — so arming
  before the port event reproduces the handoff-residue semantics exactly.
- Real EHCI silicon latches USBSTS.PCD on connect changes regardless of
  run state; QEMU only does so via paths that need the frame timer, hence
  the arm also sets USBCMD.RS (the state a BIOS actively servicing ports
  is in at handoff).
- Amusing side-observation: after the runs, QEMU's LEGSUP dword had
  NEXT=0x10; the walk then reads the BAR0 dword (0xfebd1000 → NEXT=0x10)
  at config 0x10 forever — an accidental re-confirmation of the KNOWN
  DF-1092/DF-2335 unbounded-chain class (not re-reported).

## Fix (fix.diff — validated)

In `ehci_pci_attach()`, immediately after the MMIO resource is mapped and
**before** `bus_setup_intr()`: read CAPLENGTH (low byte of capability
register 0 — an absolute offset, valid pre-init), then write
`USBINTR = 0` and `USBSTS = 0xFFFFFFFF` (acknowledge-all). A pending
interrupt can then never be level-asserted at handler-arm time; interrupts
are re-enabled later by `ehci_init_sub()` (ehci.c:264) once `sc_offs` and
`sc_eintrs` are valid.

Validation (see fix_build_guest.log, fix_validation_3pt.log):

- Patch applied to guest /usr/src, `make quickkernel` (ehci_pci.c
  recompiled, log:5530) + `make installkernel`, rebooted.
- **Pass-branch**: real QEMU EHCI boots and enumerates normally
  (roothub + 6 keyboards; 72 boot interrupts — normal).
- **Same trigger as the baseline storm**: T1 park-start 322,795 →
  T2 mid-park **322,795 (Δ=0)** → T3 post-attach 322,900 (Δ=105 total)
  with the port event fired *inside* the park — vs 311,162 unpatched.
  Storm eliminated; USB functional.

## Threat model / severity

Malicious or compromised EHCI silicon/emulator, or BIOS/SMM residue at
ownership handoff; kldload-time re-attach is root-gated, boot-time attach
needs no privilege at all beyond the device's own state. Not reachable by
an unprivileged local user through this file. Consequence: bounded ~5 s
full-machine IRQ storm (measured 311 K interrupts) or permanent boot
live-lock when the attaching CPU is starved (demonstrated variant).
Severity **Low** — calibrated with the file's known findings DF-1092 /
DF-2335 (same hardware-preconditioned DoS class, same file, Low each).

## 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.
