# DF-5268 VERDICT

**status: reproduced (impact: panic — write-capable OOB MMIO primitive
demonstrated; escalation bounded by requiring malicious hardware / PCIe
device access)**

## What was claimed

`sys/bus/u4b/controller/xhci.c:626-629` (`xhci_init()`) latches three
register base offsets (`CAPLENGTH`, `RTSOFF`, `DBOFF`) straight from
controller MMIO. The macros at `xhcireg.h:205-222` add these offsets to the
bus-space handle for **every** subsequent register access with no bounds
check against `sc->sc_io_size` (set once at `xhci_pci.c:206`, never read by
this file). A controller that returns oversized DBOFF/RTSOFF (both 32-bit
fields) turns each doorbell write into an OOB MMIO **write** up to 4 GB past
the mapped BAR, and each interrupter-register access into an OOB MMIO read.

Write-capable OOB sites reachable on the code path proven here:
- `xhci.c:1235` — `XWRITE4(sc, door, XHCI_DOORBELL(0), 0)` (every xHCI command)
- `xhci.c:2869` — `XWRITE4(sc, door, XHCI_DOORBELL(index), ...)` (every transfer start,
  `xhci_endpoint_doorbell`)
- `xhci.c:4313` — doorbell ring loop in `xhci_device_resume`
Read sites: `xhci.c:1653,1661` (USBSTS/IMAN on every interrupt), ERDP/ERSTSZ
writes (`xhci.c:1148-1149, 477, 513-521, 526-528`), PORTSC reads/writes in
`xhci_roothub_exec` (all `oper`/`runt` accesses).

## How it was verified (baseline)

Guest: DragonFly 6.5-DEVELOPMENT x86_64 (#0 snapshot), QEMU/KVM with
`-device qemu-xhci,id=xhci0,p2=8,p3=8` (1b36:000d, 16 KB BAR at
0xfebd0000, real offsets oper=0x40/runt=0x1000/door=0x2000).

1. Built `xhcipwn.ko` (pack source) which walks `devclass_find("xhci")` →
   `devclass_get_softc(dc, 0)` and stores `0xF0000000` into the latched
   `sc->sc_door_off` — the exact value `xhci_init()` would have stored had
   the controller's DBOFF register held it (the only simulated step; QEMU
   hardcodes sane offsets in its own model).
2. Loaded the module (dmesg confirms the real values first, then the poison).
3. Inserted a USB device via the QEMU monitor (`device_add usb-mouse,
   bus=xhci0.0,port=3`) → hub explore thread issues `ENABLE_SLOT` →
   `xhci_do_command()`.

Result: **instant kernel panic**

```
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0xfffff8017df7b000     [io_hdl + 0xF0000000 exactly]
fault code = supervisor write data, page not present
Stopped at xhci_do_command+0x216: movl $0,(%rdx)
```

The fault VA equals `sc_io_hdl + poisoned_door_off + XHCI_DOORBELL(0)` — the
driver's own write instruction on its own code path; a *write* fault at a
fully device-chosen address (subject to `& ~0x3` alignment). One run, one
panic; deterministic.

## Fix validation

Authored `fix.diff` (in-pack):
1. `xhci_init()`: validate `oper/runt/door` offsets against `sc_io_size`
   (ENXIO on violation — malicious controller never attaches), and
2. runtime guards before the two hottest doorbell writes
   (`xhci_do_command` at :1253+, `xhci_endpoint_doorbell` at :2892+).

Cycle: `vm.sh reset with-src` → applied fix.diff in guest `/usr/src` →
`make nativekernel KERNCONF=X86_64_GENERIC` + `make installkernel` →
rebooted (kernel #1 Thu Oct 1 21:45:59 UTC 2026) → re-ran the **identical**
PoC (same module, same poison, same monitor trigger):

- No trap. `dmesg | grep -c "Fatal trap"` → **0**.
- Enumeration degrades gracefully (`ugen0.2 <Unknown> (disconnected)`); the
  guarded command path returns `USB_ERR_IOERROR` before touching MMIO.
- Guest survived 4 further device_add/device_del cycles with the poison
  still loaded. Baseline vs patched behavior differs exactly as claimed.

## Escalation ceiling (honest bound)

The primitive is a *device-directed* OOB MMIO write (and read) at a
controller-chosen 32-bit offset past the BAR mapping. Where the address
lands unmapped ⇒ panic (proven here). Where it lands on adjacent mapped
MMIO (other devices' registers, APIC space, firmware flash mappings) ⇒
cross-device register corruption — potentially persistent platform
compromise (e.g., rewriting other devices' BARs/DMA engines). Local
unprivileged users are **not** in the threat model (ugen nodes are 0600
root:operator); the attacker is malicious hardware (Thunderbolt/USB4/
ExpressCard hotplug, compromised controller firmware, or a VM's emulated
controller), matching AV:P. uid=0-in-guest is not reachable from this
primitive alone on this platform without additional PCIe-sited gadgets.

Kin findings (same class, different code): DF-1106 / DF-2336 cover the XECP
*list walk* in `xhci_pci.c:398-413`; this finding covers the base register
offsets in `xhci.c:626-629` used by every runtime access — separate defect,
separate fix site.

## Kernel references

- `sys/bus/u4b/controller/xhci.c:626-629` (unmasked offset latch)
- `sys/bus/u4b/controller/xhcireg.h:205-222` (unchecked bus_space accessors)
- `sys/bus/u4b/controller/xhci_pci.c:204-213` (io_tag/hdl/size setup; size unused downstream)
- `sys/bus/u4b/controller/xhci.c:1235` (command doorbell write — panic site)
- `sys/bus/u4b/controller/xhci.c:1653,1661` (per-interrupt IMAN read)
- `sys/bus/u4b/controller/xhci.c:2855-2872` (endpoint doorbell write)

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