# VERDICT — DF-3626: intel_dp_check_mst_status() unbounded `go_again` loop

**verdict: inconclusive (runtime) / certain (source-level)** — `reproduced=0`,
`impact=none` (nothing demonstrable on this guest), expected impact on real HSW+
hardware with an attached hostile MST branch device: **DoS** (kthread livelock +
permanent power-well reference + display hotplug starvation).

## Why runtime verification was not possible

The audit guest is QEMU/KVM with a virtio display device:

```
$ pciconf -l | grep -i -E "vgapci|display"
vgapci0@pci0:0:2:0:  class=0x030000 card=0x11001af4 chip=0x11111234 rev=0x02 hdr=0x00
$ kldstat | grep drm      → (nothing)
$ ls /dev/dri             → NO_DEV_DRI
```

chip 0x1111:1234 is the QEMU/virtio display adapter. `i915.ko`'s PCI ID table
(`i915_pciids.h` → `i915_pci_register`) matches only Intel vendor 0x8086 IDs, so
the driver never attaches; `intel_dp_hpd_pulse()` can never run. No amount of
setup inside the guest substitutes for Intel display hardware plus a hostile
DP branch device on the physical connector.

## Proof the vulnerable code ships in the default install

```
$ nm /boot/kernel/i915.ko | grep intel_dp_check_mst_status
00000000000cbd80 t intel_dp_check_mst_status
$ strings /boot/kernel/i915.ko | grep -E "got esi"
got esi %3ph
got esi2 %3ph          <- the re-read branch inside the go_again loop
```

`i915.ko` is built and shipped in `/boot/kernel` of the stock DragonFly
6.5-DEVELOPMENT install booted here, and `enable_dp_mst` defaults to **true**
(`sys/dev/drm/i915/i915_params.h:69`).

## Line-accurate path trace (this tree)

| step | where | note |
|---|---|---|
| 1 | `sys/dev/drm/i915/i915_irq.c` → `intel_hpd_irq_handler()` | platform irq handlers call it for each short pulse |
| 2 | `sys/dev/drm/i915/intel_hotplug.c:496-497` | `queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work)` |
| 3 | `sys/dev/drm/i915/intel_hotplug.c:313` | `dig_port->hpd_pulse(dig_port, long_hpd)` → `intel_dp_hpd_pulse` |
| 4 | `intel_dp.c:5684` | `intel_display_power_get()` — ref never dropped if we never return |
| 5 | `intel_dp.c:5687` | `intel_dp_check_mst_status(intel_dp)` (is_mst == true) |
| 6 | `intel_dp.c:4293` | `intel_dp_get_sink_irq_esi()` — 14-byte sink read, attacker data |
| 7 | `drm_dp_mst_topology.c:2450-2473` | `handled = true` on sink-count change / DOWN_REP_MSG_RDY / UP_REQ_MSG_RDY — **all sink-controlled bits** |
| 8 | `intel_dp.c:4309-4317` | clear-write of `esi[1..3]` to `DP_SINK_COUNT_ESI+1` — a *request*; sink may ignore |
| 9 | `intel_dp.c:4319-4322` | re-read succeeds → `goto go_again` — **no bound anywhere in the function** |

The only exits are: ESI read failure (`intel_dp_get_sink_irq_esi` != 14 bytes)
or `handled == false`. Both are fully under the sink's control.

Note also the `esi[10]` sub-analysis: `drm_dp_channel_eq_ok(&esi[10], …)`
(drm_dp_helper.c:60-77) only indexes `link_status[0..2]` → `esi[10..12]`, in
bounds of the 14-byte array — the *memory-safety* reads are fine; the defect is
purely the unbounded control loop.

## Exploit chain

Not a memory-corruption primitive; no escalation chain. Chain is:
evil dock → MST handshake → 1 short HPD → infinite `go_again` → dp_wq kthread
livelock + leaked display power-well reference + all-port hotplug starvation
→ display subsystem dead until reboot (DoS).

## Fix validation

`fix.diff` bounds the loop to 8 bounces and schedules a hotplug event on
exhaustion. Not buildable/testable on this guest (no Intel GPU to modeset, and
the path needs hostile HW); `fix_status: not_testable`.

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