β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2401

intel_gtt_insert_page swaps index/physical arguments causing out-of-bounds MMIO write into Intel IGD BAR

Summary

intel_gtt_insert_page() passes its (addr pg) arguments to install_gtt_pte() in wrong order. install_gtt_pte signature is (device_t u_int index vm_offset_t physical int flags) - every other caller passes (index physical). Here it passes (addr pg) where addr is real DMA address and pg is small GTT page index so driver writes value pg|VALID to MMIO offset addr*4 inside BAR0. On systems with >512MB RAM this is write tens-to-thousands of MB past BAR end and even on small-RAM systems writes wrong PTE value into wrong GTT slot. Reachable from any unprivileged local user with /dev/dri/card0 access on Intel IGD gen<=5. i915 picks i915_gmch_probe assigning ggtt->vm.insert_page=i915_ggtt_insert_page invoked from EXECBUFFER2 fast path PREAD/PWRITE. Impact: OOB MMIO write Master-Aborts causing machine check/NMI/kernel panic (DoS) or wrong GTT entry written with bogus PTE GPU reading from arbitrary/stale physical memory (kernel-memory disclosure via GPU blits).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2401 Β· 6 files
FileTypeDescriptionSize
VERDICT.md verdict gate analysis + swapped-argument trace 3.3 KB ↓ raw
fix.diff suggested-fix swap install_gtt_pte args to (pg, addr) 352 B view raw
build.sh build-script documents HW gate 148 B view raw
run.sh run-script prints gate proof 403 B view raw
env.txt environment guest env 1.1 KB view raw
gate_proof.txt gate-proof no Intel IGD, no /dev/dri*/agpgart 67 B view raw
VERDICT.md verdict gate analysis + swapped-argument trace
↓ download raw

DF-2401 β€” intel_gtt_insert_page swaps index/physical arguments (sys/dev/agp/intel-gtt.c)

Verdict: NOT REPRODUCED (HW-gated); REAL BUG IN SOURCE (defense-in-depth fix warranted)

Hardware gate (why the PoC cannot run on this guest)

intel_gtt_insert_page() is part of the Intel IGD (integrated graphics) agp_i810-class GTT driver and is reached only when an Intel IGD GPU (gen <= 5) is present and the i915/Intel GTT path attaches. The audit QEMU/KVM guest has only the Bochs/QEMU std VGA (chip 0x11111234) β€” not an Intel IGD β€” and no DRM/AGP device nodes:

$ pciconf -l | grep -iE "0x030000|0x030200|intel|8086.*2a|8086.*2770|8086.*2562"
vgapci0@pci0:0:2:0:  class=0x030000 chip=0x11111234 rev=0x02   # not Intel IGD
$ ls /dev/dri* /dev/agpgart 2>&1      # No such file or directory
$ kldstat | grep -iE "i915|agp|intel" # (none)

No Intel IGD means the agp_i810/Intel-GTT attach path that wires intel_gtt.insert_page never runs on this guest. The unprivileged maxx user cannot reach intel_gtt_insert_page (it is invoked from kernel-internal i915 GEM paths on Intel IGD hardware).

Source trace β€” the bug is REAL (sys/dev/agp/intel-gtt.c)

install_gtt_pte ops-vector signature (intel-gtt.c:186):

void (*install_gtt_pte)(device_t, u_int index, vm_offset_t physical, int flags);

All correct callers pass (dev, index, physical, flags), e.g. agp_intel_gtt_insert_pages at intel-gtt.c:1400:

sc->match->driver->install_gtt_pte(dev, first_entry + i,    /* index */
                                   VM_PAGE_TO_PHYS(pages[i]),/* physical */
                                   flags);

But intel_gtt_insert_page at intel-gtt.c:1407-1412 passes the arguments in the wrong order:

void
intel_gtt_insert_page(dma_addr_t addr, unsigned int pg, unsigned int flags)
{
    struct agp_i810_softc *sc = device_get_softc(intel_agp);
    sc->match->driver->install_gtt_pte(intel_agp, addr, pg, flags);
                                              /* ^^^ index slot gets the DMA addr,
                                               *     physical slot gets the GTT index */
}

addr (a real DMA/bus address, potentially large) is passed as index, and pg (a small GTT page index) is passed as physical. The implementation (e.g. agp_i915_install_gtt_pte) then writes the PTE pg | VALID to GTT slot addr β€” i.e. MMIO offset addr * 4 inside BAR0. On systems with > 512 MB RAM (or a large DMA address) this is tens-to-thousands of MB past the BAR end β†’ OOB MMIO write β†’ Master-Abort / machine-check / NMI / kernel panic; even on small-RAM systems the wrong PTE value lands in the wrong GTT slot. Reachable from any unprivileged user with /dev/dri/card0 access on Intel IGD gen<=5 via the i915 EXECBUFFER2 / PREAD / PWRITE fast paths.

Exploit chain status

Not pursuable β€” primitive (OOB MMIO write / wrong-GTT-entry) behind absent Intel IGD hardware (valid Phase-6 hard blocker: dead path at runtime on this guest). On Intel IGD hardware this is a real DoS / kernel-memory-disclosure primitive.

PoC changes

None. No Intel IGD / DRM device on guest; verified by source trace only.

Pass the arguments in the correct order (index, physical). See fix.diff (matches the finding proposal exactly β€” it is a one-token argument swap).

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not_testable: PoC cannot run on this guest (HW-gated, no target device). fix.diff validated by git apply --check (clean) + line-accurate source trace confirming it closes the cited path.

git apply --check findings/poc/DF-2401/fix.diff -> OK (clean apply). No runtime test possible (HW-gated).
↓ fix.diffn/a (no target HW/device on this guest)

Confirmed kernel references

Detail

Exploit chain

none β€” valid hard blocker (driver/device path dead at runtime on this guest: no target HW / no attached device). No unprivileged->root path.

Evidence (decisive lines)

usbconfig list -> No device match or lack of permissions.; pciconf -l -> no target controller HW; ifconfig -l -> vtnet0 lo0; kldstat -> kernel/ehci/xhci only; ls /dev/<target> -> No such file or directory; id maxx -> uid=1001 groups=1001 (not operator). Source confirmed at cited lines.

PoC changes

Created findings/poc/DF-2401/{VERDICT.md,fix.diff,build.sh,run.sh,env.txt,gate_proof.txt,manifest.json}. No PoC source (HW-gated).

Verified recommended fix

swap args to install_gtt_pte(intel_agp, pg, addr, flags). Full git-apply-able diff in findings/poc/DF-2401/fix.diff (git apply --check OK).

Verdict

NOT REPRODUCED (HW-gated). The bug is REAL in source (traced line-by-line). intel-gtt intel_gtt_insert_page swaps index/physical args (OOB MMIO write); no Intel IGD. Gate confirmed via usbconfig list (No device match / no /dev/ugen*), pciconf -l (no target controller HW), ifconfig (vtnet0 lo0 only), kldstat (no target module), and ls /dev (no target nodes). maxx (uid 1001, not in operator) cannot reach any /dev/usbctl write path.