# DF-5268 — xHCI driver latches unmasked device-controlled register offsets (CAPLENGTH/RTSOFF/DBOFF) → unbounded OOB MMIO read/write

## Build

See `build.sh` — builds `xhcipwn.ko` in the guest (DragonFly 6.5-DEVELOPMENT,
cc 8.3). Needs `/usr/src` + kernel obj tree (`vm.sh reset with-src`, then
`make nativekernel KERNCONF=X86_64_GENERIC` once for headers).

## Run

See `run.sh`. Boot the guest with `QEMU_EXTRA="-device qemu-xhci,id=xhci0,p2=8,p3=8"`,
`kldload ./xhcipwn.ko`, then insert any USB device via the QEMU monitor
(`device_add usb-mouse,id=m1,bus=xhci0.0,port=3`).

## Expected

* **Vulnerable kernel (unmodified snapshot):** instant kernel panic —
  `Fatal trap 12: page fault while in kernel mode`, fault VA
  `0xfffff8017df7b000` = `io_hdl(0xfffff8008df7b000) + 0xF0000000`,
  `supervisor write data, page not present`,
  `Stopped at xhci_do_command+0x216: movl $0,(%rdx)` (the doorbell write at
  `sys/bus/u4b/controller/xhci.c:1235`).
* **Fixed kernel (+fix.diff):** no panic, no fault; device enumeration fails
  gracefully (`ugen0.2 <Unknown> (disconnected)`), guest stays up across
  repeated plug/unplug cycles.

## Why this is the real thing (not a synthetic bug)

`xhci_init()` (sys/bus/u4b/controller/xhci.c:626-629) copies three register
base offsets **verbatim from device MMIO** into the softc:

```c
sc->sc_oper_off = XREAD1(sc, capa, XHCI_CAPLENGTH);        /* 8 bits   */
sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0x1F;   /* 32 bits  */
sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF)  & ~0x3;    /* 32 bits  */
```

`sc->sc_io_size` — the mapped BAR size, recorded at
`sys/bus/u4b/controller/xhci_pci.c:206` — is **never consulted anywhere in
xhci.c**. Every `XREAD*/XWRITE*` macro (xhcireg.h:205-222) is a raw
`bus_space_*` on `sc_io_hdl + offset` (a direct `*(volatile uint32_t *)`
dereference on x86). With DBOFF up to `0xFFFFFFFC`, RTSOFF up to
`0xFFFFFFE0`, the driver will read/write gigabytes past the 16 KB mapping.

The PoC module performs exactly one thing: it stores into the *latched*
`sc->sc_door_off` the value `0xF0000000` — bit-for-bit what `xhci_init()`
would itself have stored had the controller returned that DBOFF (the only
step simulated, because QEMU's own xhci hardcodes sane offsets). Everything
afterwards — the doorbell write, the page fault — is the driver's unmodified
code on the real code path reached from ordinary USB device insertion
(`ENABLE_SLOT` command → `xhci_do_command()` → `XWRITE4(sc, door,
XHCI_DOORBELL(0), 0)` at xhci.c:1235).

Threat model: malicious/compromised xHCI controller (Thunderbolt/USB4/PCIe
hotplug, emulated device in VM, firmware-implanted controller). Sibling of
DF-1106 / DF-2336 (the extended-capability *list walk* in `xhci_pci.c`);
this finding is the *base-offset* variant in `xhci.c` — every register
access in the driver, not just the attach-time XECP walk.

## Artifacts

* `poison.c`, `Makefile` — PoC kernel module source
* `build.sh` / `run.sh` — exact commands
* `run.log` — full baseline (panic) + fixed (survives) transcript
* `panic.txt` — kernel panic signature captured from serial console
* `env.txt` — guest uname, compiler, controller, register values
* `fix.diff` — validated fix (init-time bounds validation + runtime
  doorbell guards)
* `fix_build_guest.log` — kernel build/install tail with fix applied
