i915 MMIO register mapping (pmap_mapdev KVA + global iomap node + shim bus resource) leaked on every driver detach: the only pci_iounmap in the i915 tree is #if 0'd
Summary
i915_mmio_setup() pci_iomap()s the MMIO BAR into pmap_mapdev_attr KVA plus a kmalloc'd iomap_list node plus an unreleased bus resource hold; the ONLY pci_iounmap anywhere under sys/dev/drm/i915/ is compiled out, and intel_uncore_fini() never unmaps. Each attach/detach cycle (root kldload/kldunload, or probe-fail->retry) permanently leaks all three; unbounded accumulation. DF-3768's twin for a different resource on the same unload path - the two compound on real hardware. Root-gated; slow permanent kernel KVA/resource exhaustion. Un-#if-0 fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3900 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.5 KB | β raw | |
| VERDICT.md | β | 3.2 KB | β raw | |
| mmio_leak_cycle.sh | β | 579 B | view raw | |
| build.sh | β | 75 B | view raw | |
| run.sh | β | 133 B | view raw | |
| build.log | β | 363 B | view raw | |
| run.log | β | 363 B | view raw | |
| env.txt | β | 332 B | view raw | |
| fix.diff | β | 510 B | view raw | |
| manifest.json | β | 805 B | view raw | |
| verdict.json | β | 2.6 KB | view raw |
DF-3900 β i915 MMIO register mapping (and shim bus resource) leaked on every driver detach
File: sys/dev/drm/i915/i915_drv.c
Class: resource leak / teardown asymmetry (DF-3768 twin, distinct resource)
Severity: Low (root-gated: kldload/kldunload of i915kms.ko, or error-probe β re-probe)
What
i915_mmio_setup() (i915_drv.c:1027) maps the MMIO BAR:
dev_priv->regs = pci_iomap(pdev, mmio_bar, mmio_size); /* 512KB gen<5, 2MB gen>=5 */
On DragonFly, pci_iomap() (sys/dev/drm/include/linux/pci.h:299) =
pci_resource_start() + pci_resource_len() + ioremap(base, size):
* pci_resource_start does bus_alloc_resource_any(..., RF_SHAREABLE) and the
caller never releases that resource (shim-wide issue), and
* ioremap() β __ioremap_common() (sys/dev/drm/linux_iomapping.c:44) does
pmap_mapdev_attr() (kernel KVA) and links a kmalloc'd struct iomap
onto the global iomap_list.
The only unmap call anywhere under sys/dev/drm/i915/ is compiled out:
static void i915_mmio_cleanup(struct drm_i915_private *dev_priv) /* :1040 */
{
intel_teardown_mchbar(dev_priv);
#if 0
pci_iounmap(pdev, dev_priv->regs); /* :1048 β never compiled */
#endif
}
intel_uncore_fini() (intel_uncore.c:1643 β called on the same unload path,
i915_drv.c:1867 β 1105) only sanitizes/forcewake-resets; it does not unmap.
i915_driver_unload() therefore never releases dev_priv->regs.
Impact
Every i915 attach/detach cycle (kldload/kldunload i915kms.ko, or a probe that
fails after i915_driver_init_mmio() and is retried) permanently leaks:
* 512KB / 2MB of pmap_mapdev KVA,
* one struct iomap node on the global list, and
* one bus-resource acquisition of the MMIO BAR.
Unbounded accumulation; on 32-bit kernels KVA exhaustion is realistic, on 64-bit it is a slow permanent leak. Root-gated (module load), no unprivileged path, no memory corruption. Same class as DF-3768 (GGTT fictitious range, i915_gem_gtt.c) but a distinct leaked resource and a distinct fix.
Reproduce (on hardware with an Intel GPU)
See mml_leak_cycle.sh β kldload/kldunload loop; after N cycles
vmstat -m | grep drm / KVA map inspection shows N leaked iomap nodes
(2MB KVA each on gen5+). Not runnable on this audit guest (virtio VGA
only, no /dev/dri, no i915 device) β status honestly inconclusive,
source-certain (rg proves the single #if 0'd pci_iounmap).
Fix
Un-#if 0 the unmap in i915_mmio_cleanup() (fix.diff) β iounmap(dev_priv->regs)
undoes exactly what pci_iomap() did (pmap_unmapdev + node removal).
DF-3900 VERDICT
Status: inconclusive (source-certain; not runnable on this guest) reproduced: 0 Β· impact class: dos (KVA/resource exhaustion, root-gated) Β· confidence: certain
Why the bug is certain from source alone
i915_mmio_setup()maps the MMIO BAR per attach:dev_priv->regs = pci_iomap(pdev, mmio_bar, mmio_size)β i915_drv.c:1027.- On DragonFly
pci_iomapβpci_resource_start(sys/dev/drm/include/linux/pci.h:267) doesbus_alloc_resource_any(RF_SHAREABLE)β never released by anyone β andioremapβ__ioremap_common(sys/dev/drm/linux_iomapping.c:44-57) doespmap_mapdev_attr()+kmalloc(struct iomap)+SLIST_INSERT_HEAD(&iomap_list). - The ONLY
pci_iounmapin the entiresys/dev/drm/i915/tree is at i915_drv.c:1048, inside#if 0(verified:rg -n "pci_iounmap" sys/dev/drm/i915/β exactly one hit, that line). - The unload path calls
i915_driver_cleanup_mmio()(i915_drv.c:1106 withini915_driver_cleanup_mmio=intel_uncore_fini+i915_mmio_cleanup, reached fromi915_driver_unload:1867) andintel_uncore_fini(intel_uncore.c:1643-1653) never touches the mapping.
Therefore each attachβdetach cycle of i915 leaks 512KB (gen<5) or 2MB (genβ₯5)
of KVA plus the iomap node plus a bus resource hold. No code path frees them.
Trigger: kldload i915kms && kldunload i915mks as root, repeated; or repeated
probe-failβreprobe. After N cycles, NΓ2MB KVA is gone permanently (reboot only).
Why not live-verified
The audit guest is QEMU with virtio VGA (vgapci0: chip=0x11111234 = virtio-gpu),
no Intel GPU, no /dev/dri, i915kms.ko cannot attach (see env.txt). Exactly the
situation DF-3634/DF-3768 hit; recorded inconclusive per the honest-status table.
Exploit chain
None β no memory corruption, no unprivileged reach. This is a permanent kernel resource leak enabling slow system degradation / eventual attach failures (same operational impact family as DF-3768, which exhausts the 8-slot fictitious range; this one exhausts KVA instead β the two compound on real hardware).
Fix validation
fix.diff un-#if 0s the pci_iounmap in i915_mmio_cleanup. Not build-tested
on the guest because the i915 driver is not buildable/loadable there (no drm
in the guest kernel config path used; kernel build of drm requires the module
set). fix_status: not_applicable (no reproduced memory corruption; mandatory
fix-validation trigger not met).
kernel_refs
- sys/dev/drm/i915/i915_drv.c:1027 (pci_iomap at setup)
- sys/dev/drm/i915/i915_drv.c:1040-1050 (cleanup with #if 0'd pci_iounmap)
- sys/dev/drm/i915/i915_drv.c:1103-1108 (i915_driver_cleanup_mmio)
- sys/dev/drm/i915/i915_drv.c:1866-1867 (unload calls cleanup_mmio)
- sys/dev/drm/linux_iomapping.c:44-57 (__ioremap_common alloc)
- sys/dev/drm/include/linux/pci.h:299-312 (pci_iomap; pci_resource_start leak)
- sys/dev/drm/i915/intel_uncore.c:1643 (intel_uncore_fini β no unmap)
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.
Fix verification
not_testablefix.diff un-#if 0's pci_iounmap(pdev, dev_priv->regs) in i915_mmio_cleanup; not build-validated (guest cannot build/load i915kms; no reproduced corruption to gate mandatory fix-validation)
fix.diff in this directory
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (step-by-step proof); run.log (guest kldload attempt fails: no i915 hardware); mmio_leak_cycle.sh (hardware trigger); fix.diff (un-#if 0 pci_iounmap)
PoC changes
Trigger authored fresh (kldload cycle script); no seed existed
Verified recommended fix
Compile the pci_iounmap(pdev, dev_priv->regs) back into i915_mmio_cleanup() (and NULL dev_priv->regs)
Verdict
Source-certain teardown asymmetry: i915_mmio_setup() pci_iomap()s the MMIO BAR (i915_drv.c:1027) into pmap_mapdev KVA + a global iomap_list node + a shim bus-resource hold, but the only pci_iounmap in the whole i915 tree is #if 0'd out in i915_mmio_cleanup() (i915_drv.c:1042-1049) and intel_uncore_fini() (intel_uncore.c:1643) never unmaps. Every i915 attach/detach cycle (root kldload/kldunload i915kms.ko or error-probe-retry) permanently leaks 512KB/2MB KVA plus metadata; unbounded accumulation; DF-3768's twin for a different resource. Not runnable on the audit guest (virtio VGA only, no /dev/dri β kldload i915kms: 'No such file or directory'), so honestly inconclusive with the code path proven by rg across the tree.
No comments yet.