{
  "finding_id": "DF-5546",
  "status": "reproduced",
  "reproduced": true,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "xhci_pci_attach() allocates classic-MSI vectors unconditionally via pci_alloc_1intr() (xhci_pci.c:234, pci.c:4365) but in forced-polling mode (hw.usb.xhci.use_polling=1) never creates the IRQ resource (:253-268), and xhci_pci_detach() releases MSI only under if (sc->sc_irq_res) (:366-371) -- with no IRQ resource the release is skipped and the MSI message allocation, its rid resource-list entries and sc_irq_rid state leak on every polling-mode attach/detach cycle. Proven live: guest booted with -device nec-usb-xhci,msi=on,msix=off (classic-MSI xHCI; qemu-xhci is MSI-X-only and does not exercise the path -- documented in run.hw-precondition.log) plus the boot tunable; polling attach state sc_irq_rid=1/sc_irq_res=0; after a fully clean device_detach(xhci0) (usbus detached normally, no veto involved) the harnesss pci_release_msi(xhci0) probe returned 0 -- i.e. the driver left vectors allocated (the harness then released them to keep the guest usable). On the kernel rebuilt with fix.diff (unconditional pci_release_msi(self) in detach, a no-op when nothing is allocated) the identical run returns ENODEV(19) clean: nothing left to release. Impact ceiling: privileged-context kernel resource leak (finite MSI vector pool + per-device resource-list entries) degrading future device interrupt setup across kldload/kldunload or hot-plug cycles -- a slow local DoS, not an info leak or memory corruption. Root boot tunable + privileged unload required => Low severity; mechanics certain and reproduced end-to-end.",
  "exploit_chain": "privileged: loader.conf hw.usb.xhci.use_polling=1 (root) -> xhci_pci_attach on MSI-capable controller: pci_alloc_1intr allocates MSI (rid=1), polling mode skips bus_alloc_resource_any -> later kldunload/PCI hot-unplug -> xhci_pci_detach: sc_irq_res==NULL so the pci_release_msi block is skipped -> leaked msi_alloc vectors + rid entries accumulate per cycle -> MSI pool exhaustion degrades future pci_alloc_msi (devices fall back to INTx or lose interrupts). No unprivileged route.",
  "evidence": "run.log (baseline: pre-detach sc_irq_rid=1 sc_irq_res=0 sc_intr_hdl=0 -> detach returned 0 -> pci_release_msi(xhci0) probe returned 0 (LEAK: driver left MSI vectors allocated)); run.fix.log (fixed kernel, same pre-state -> probe returned 19 (clean: nothing left to release)); run.hw-precondition.log (qemu-xhci MSI-X-only null result that led to the NEC classic-MSI controller); msileak.c/Makefile/build.sh/run.sh (harness); build.log; fix_build.log (shared rebuild with DF-5545, xhci_pci.c recompiled, installkernel completed); fix.diff",
  "kernel_refs": [
    "sys/bus/u4b/controller/xhci_pci.c:234",
    "sys/bus/u4b/controller/xhci_pci.c:253",
    "sys/bus/u4b/controller/xhci_pci.c:266",
    "sys/bus/u4b/controller/xhci_pci.c:320",
    "sys/bus/u4b/controller/xhci_pci.c:366",
    "sys/bus/pci/pci.c:4348",
    "sys/bus/pci/pci.c:4365"
  ],
  "poc_changes": "Seed concept only; harness written fresh (msileak.c KLD): reads the polling-mode attach state from the live softc, walks the PCI capability list to locate the MSI cap, performs device_detach(xhci0) from a module kernel thread (gd_sysctllock constraint, same as DF-5544/5545 rigs), then uses pci_release_msi()s return value as the decisive leak oracle (0 == vectors were still allocated = leak; ENODEV == clean). Two hardware attempts were needed: -device qemu-xhci exposes MSI-X only so DFs classic-MSI alloc fails silently (rid stayed 0, probe ENODEV -- saved as run.hw-precondition.log); -device nec-usb-xhci,msi=on,msix=off provides the classic MSI cap and the leak reproduced.",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline; fix validated on rebuilt kernel installed Wed Oct  7 09:43:48 UTC 2026, md5 29a0c51c2e9202a724a7b626b3416d39)",
  "runtime_sec": 2280,
  "guest_dirty": 0,
  "build_cmd": "cd /root/df5546 && make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC",
  "run_cmd": "kldload /root/df5546/msileak.ko; sysctl hw.df5546=1   (boot: -device nec-usb-xhci,msi=on,msix=off + hw.usb.xhci.use_polling=1)",
  "code_hash": "c26d0f38302d3fdcc55f418d4e71548e55b670670d8fc4bc5620c628250d3b5c",
  "notes": "Cross-checked the DF-5464 KASSERT class: this files DF branch has no MSI count math (pci_alloc_1intr fixed count=1) -- not a recurrence. The dead FALLTHROUGH - use polling comment at :266 actually goto-errors at :326 unless the tunable is set; only the tunable path reaches the leak. Guest reset to with-src after the run.",
  "recommended_fix": "Call pci_release_msi(self) unconditionally in xhci_pci_detach() after the IRQ-resource block (it is a no-op returning ENODEV when nothing is allocated), so polling-mode attaches cannot leak the MSI allocation.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff applied to guest /usr/src together with the DF-5545 fix in one quickkernel+installkernel rebuild; identical trigger on the same emulated hardware and tunable now yields pci_release_msi probe ENODEV(19) clean: nothing left to release -- the driver releases the vectors itself during detach. Leak gone; no regression to the normal IRQ-mode detach path (release is idempotent).",
  "fix_evidence": "run.fix.log; fix_build.log (xhci_pci.c recompile + installkernel completed Wed Oct  7 09:43:48 UTC 2026)"
}