# 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`):
```c
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`:
```c
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**:
```c
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.

## Recommended fix

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