# DF-5767 — VERDICT

**Status: untested** (hardware-precondition finding — not reproducible on the
audit guest; code path proven by trace). Reproduced: no. Impact: none
demonstrated (device-trust class). Confidence in the defect: certain.

## Narrative

`sys/bus/u4b/controller/ohci.c:286` latches the number of root-hub ports
straight from device MMIO (`OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A))`,
mask `0xff` at ohcireg.h:97) with only a zero-retry guard
(ohci.c:283, the AMD756 "reports 0 ports" erratum workaround). The OHCI 1.0a
spec limits NDP to 15 and defines the operational register file as
0x00-0xFF with port registers at `0x50 + 4*n` (ohcireg.h:113); the driver
never clips, and re-latches the value on every resume
(ohci_resume ohci.c:461-476 → ohci_controller_init → ohci.c:282-287).

With `sc->sc_noport` in [16,255]:

* `ohci_root_intr()` (ohci.c:1610-1616) reads port-status registers
  1..noport on every RHSC interrupt — MMIO reads at 0x54..0x474, past the
  0x100-byte register file for any noport ≥ 44. The idata clamp at
  ohci.c:1607-1609 is vacuous (noport+1 ≤ 256 = 8*sizeof(sc_hub_idata),
  ohci.h:251).
* `ohci_roothub_exec()` bounds port indices only by sc_noport
  (ohci.c:2221-2225 CLEAR, 2306-2310 GET, 2324-2328 SET) and then
  OREAD4/OWRITE4 at `OHCI_RH_PORT_STATUS(index)` — OOB MMIO **reads and
  writes** (fixed UPS_* bit patterns, incl. UPS_RESET) up to offset 0x474.
* The hub descriptor reports `bNbrPorts = sc_noport` (ohci.c:2279), so the
  in-kernel uhub thread walks all bogus ports and performs those accesses
  itself during normal exploration — no crafted userspace request needed
  once the register lies.

Sibling family findings: DF-5268 (xhci CAPLENGTH/DBOFF/RTSOFF, Medium),
DF-5282 (ehci CAPLENGTH/N_PORTS, Medium), DF-5296 (uhci BAR size vs 0x14
register file, Low) — this is the OHCI instance of the same idiom.

## Why it is not reproduced on the guest

1. QEMU initializes OHCI NDP from the `num-ports` property and hard-errors
   above `OHCI_MAX_PORTS` = 15 (QEMU `hw/usb/hcd-ohci.c:1953-1955`).
2. QEMU models HcRhDescriptorA as fully read-only
   (`OHCI_RHA_RW_MASK = 0x00000000`, qemu hcd-ohci.c:189; write handler
   1791-1792 applies a zero mask), so a guest KLD cannot poison the register
   either.
3. The default audit-guest QEMU command line has no USB controller at all
   (`pciconf -l` on guest shows none), and NDP > 15 could not occur even
   with `-device usb-ohci` added.

Precondition class: malicious/buggy PCI hardware or emulation — identical to
DF-5296, which was likewise filed untested. A patched QEMU with
`num-ports > 15` (or a hardware OHCI whose NDP reads > 15) would exhibit the
OOB accesses immediately on the first roothub status change; on QEMU's
0x1000-byte OHCI MMIO region the reads return 0 (no fault), so even a patched
QEMU shows no crash — the class is cross-device MMIO corruption, visible only
with a minimal-BAR implementation.

## Fix validation

Not performable on this guest (bug cannot be manifested — see above);
`fix.diff` provided, `fix_status: not_testable`. The patch is a two-line clip
at the latch site plus optional clamp at the consumers; build-tested
mentally against the file (no other consumer of sc_noport permits > 15:
sc_devices[] is OHCI_MAX_DEVICES=128 — unrelated; hubd.bNbrPorts is uByte —
255 fits; DeviceRemovable[32] — l/8 ≤ 31 in-bounds, so no secondary overflow
exists to fix).

## Negative results worth recording (pass-2 classes hunted and killed)

* **Isoc ITD page arithmetic (ohci.c:1900-1965)**: the flush condition
  `(length & 0xF000)` allows ITDs spanning 3 pages (start page offset +
  accumulated length up to ~0x23FC). OHCI PSW encodes only {page(bp0),
  page(be)} (bit 12 page-select; confirmed in QEMU `ohci_service_iso_td`,
  qemu hcd-ohci.c:694-713), so middle-page frames are mis-mapped into
  page(be) — verified numerically (sim in pack: frames intended for the
  middle page DMA to be's page, up to ~3 KB past `be`). All such writes stay
  inside the transfer's own DMA allocation (page(be) is the buffer's last
  page; usbd_transfer_setup_sub validates Σfrlengths ≤ max_data_length via
  usb_generic.c:1166-1170, so `be` never leaves the map; isoc data buffers
  ≥ 8 KB are page-granular bus_dmamem allocations, so past-`be` is the
  allocation's own slack). Net: silent frame-data corruption (integrity),
  NOT kernel memory corruption. Upstream FreeBSD carries identical code
  (diffed 2026-10-11); not filed as a security finding.
* ITD field encodings correct: `OHCI_ITD_SET_FC(x)=((x)-1)<<24` 3-bit
  count-1 (ohci.h:152), `SET_SF` 16-bit (ohci.h:147).
* `ntd`/`nitd` allocation formulas (ohci.c:2404-2435) cover worst-case TD
  consumption (per frame: floor(len/4096)+1 TDs +1 ZLP ≤ 2*nframes +
  max_data/4096); panic safety nets at ohci.c:1297/1901.
* `ohci_non_isoc_done_sub` cbp/be arithmetic (ohci.c:824-838): underflow and
  overrun guarded by `temp > td->len → cc=STALL`.
* `ohci_isoc_done` plen walk (ohci.c:712-764): `nframes>8` clamp at 736,
  `len > *plen → 0` clamp at 748, walk bounded by the ITD chain built at
  enter time.
* isoc `nframes==0` NULL-deref in `ohci_device_isoc_enter` (td_last NULL,
  ohci.c:1968): unreachable — `usbd_transfer_submit` rejects nframes==0
  (usb_transfer.c:1748) and the stall_pipe special case completes via
  `usbd_pipe_start` without touching HCD methods (usb_transfer.c:2779-2785);
  `usbd_transfer_setup_sub` rejects ZERO_NFRAMES (usb_transfer.c:547).
* `ohci_device_done` double-invocation: guarded by prev==0 no-op in
  `_ohci_remove_qh` (ohci.c:691) + shared-stack did_close/did_transfer
  serialization; ED (qh_start) non-NULL whenever methods assigned (setup
  success is a precondition for pipe open).
* Done-list reaping: this driver does not walk hcca_done_head at all
  (completion detected by ED head/tail polling, ohci.c:1037-1038);
  intr_q TAILQ mutation during polling handled by `goto repeat`
  (ohci.c:1092-1095). HW-drain protocol = two DMA sets + 1125 us dma delay
  (ohci.c:2586).
* Roothub descriptor writes: `DeviceRemovable[32]` ≥ max index 31 — no
  overflow even at NDP=255 (ohci.c:2288-2293, usb.h:610).
* Port reset poll bounded (ohci.c:2340-2352); SET_ADDRESS bounded to
  OHCI_MAX_DEVICES (ohci.c:2190); SET_CONFIG ∈ {0,1} (ohci.c:2197).
* Toggle-carry latch (ohci.c:1050-1055) reads HC-maintained ED headp —
  trusted-by-design, matches upstream.
* Detach-veto family: lives in ohci_pci.c (DF-5562, already filed); this
  file's `ohci_detach` (ohci.c:429-445) is post-children teardown only.

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