# DF-1319 — Unvalidated DisplayPort lane_count → stack buffer overflow (amdgpu)

## Verdict
**INCONCLUSIVE (real bug, needs hardware + driver absent from guest).**
Source trace confirms the stack buffer overflow; it cannot be reproduced
on this QEMU audit guest because **amdgpu is not compiled into
`X86_64_GENERIC`, is not a loadable module, and there is no AMD GPU
hardware** (the only display PCI device is QEMU std-VGA `0x11111234`,
which amdgpu does not drive).  The fix was validated to apply cleanly
(`git apply --check`) against `sys/dev/drm/amd/display/dc/core/dc_link_dp.c`.

## Mechanism

A malicious DP sink (dongle / MST hub / monitor) responds to an
automated link-training test request with an out-of-range lane count.

```
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:1768  dp_test_send_link_training(link)
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:1772    core_link_read_dpcd(link, DP_TEST_LANE_COUNT,
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:1775        &link_settings.lane_count, 1);   // raw byte, NO validation
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:1784    link->verified_link_cap.lane_count = link_settings.lane_count;
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:1787    dp_retrain_link_dp_test(link, &link_settings, false);
```

`lane_count` is a raw byte from DPCD `DP_TEST_LANE_COUNT` (0x220), whose
lower 5 bits encode 0..31.  It is propagated unvalidated into the
link-training helpers:

```
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:168  union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {0}; // LANE_COUNT_DP_MAX=4
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:171  uint8_t dpcd_lt_buffer[5] = {0};
...
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:194  for (lane = 0; lane < (uint32_t)lt_settings->link_settings.lane_count; lane++) {
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:197      dpcd_lane[lane].bits.VOLTAGE_SWING_SET = ...;   // *** OOB write for lane_count>4 ***
...
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:212  size_in_bytes = lane_count * sizeof(dpcd_lane[0]);  // up to 31*4 = 124
sys/dev/drm/amd/display/dc/core/dc_link_dp.c:215  memmove(&dpcd_lt_buffer[...], dpcd_lane, size_in_bytes);  // *** dpcd_lt_buffer[5] overflow ***
```

`LANE_COUNT_DP_MAX = LANE_COUNT_FOUR = 4`
(`sys/dev/drm/amd/display/dc/dc_dp_types.h:35-37`).  Valid DP lane counts
are {1, 2, 4}; a sink-supplied `lane_count` of 5..31 overflows the
4-element `dpcd_lane[]` stack array (line 197) and, via the `memmove` at
215, the 5-byte `dpcd_lt_buffer[]` (by up to 119 bytes).  The sibling
helper `get_lane_status_and_drive_settings`
(`sys/dev/drm/amd/display/dc/core/dc_link_dp.c:432`,
`:444-450`) has the same `dpcd_lane_adjust[LANE_COUNT_DP_MAX]` overflow.

This is a **stack buffer overflow** with attacker-influenced content
(VOLTAGE_SWING/PRE_EMPHASIS bitfields) reachable through an
**unauthenticated** physical-layer attack: hotplug a malicious DP
peripheral → HPD IRQ → `handle_automated_test`
(`dc_link_dp.c:1965/2053`) → `dp_test_send_link_training`.

## Reachability on this guest

- amdgpu is **not** in `X86_64_GENERIC` (grep for `amdgpu`/`drm5` in
  `sys/config/X86_64_GENERIC` → nothing; the `amd` device line at :88 is
  the AMD 53C974 SCSI chip, unrelated).
- `kldstat -v | grep -iE 'amdgpu|drm'` → **empty** (no amdgpu loaded).
- `/dev/dri` does **not** exist.
- The only display PCI device is `vgapci0@pci0:0:2:0` chip `0x11111234`
  (QEMU std/Bochs VGA) — not an AMD GPU, not bound by amdgpu.

There is therefore no amdgpu code path active on this guest, and no DP
peripheral attack surface at all.  Phase-4(d): real bug, unreachable on
this guest (needs an AMD GPU host + amdgpu + a malicious DP sink).

## Exploit chain

The primitive is a **stack buffer overflow** (write-capable).  On a
hypothetical amdgpu host with a malicious DP peripheral, escalation
would proceed via stack corruption of `dpcd_set_lt_pattern_and_lane_settings`
(local frame).  However, this is a display driver code path that
**cannot be driven from userspace on the audit guest** — it requires
physical DP-layer attacker input.  The audit's escalation bar (unpriv
local user → `uid=0`) does not apply: this is a hardware-attack-surface
finding, evaluated at its realistic impact ceiling (stack overflow →
potential kernel RCE on an amdgpu host via a malicious peripheral).  No
userspace exploit chain is developable or applicable here.

## PoC changes

No runnable userspace PoC exists for a DP-peripheral attack; the folder
was empty.  I authored `build.sh`/`run.sh` that document the
hardware-required reproduction steps and validate `fix.diff` applies
cleanly.  `VERDICT.md` is the primary evidence.

## Fix

`fix.diff` validates `lane_count` at the source — in
`dp_test_send_link_training`, immediately after the DPCD read and
**before** it is propagated into `link->verified_link_cap` and
`dp_retrain_link_dp_test`.  Anything not in {`LANE_COUNT_ONE`,
`LANE_COUNT_TWO`, `LANE_COUNT_FOUR`} logs a warning and returns early,
dropping the malformed automated-test request.  This is defense at the
trusted-boundary (DPCD read) and is the root-cause fix; it closes the
overflow for both `dpcd_set_lt_pattern_and_lane_settings` and
`get_lane_status_and_drive_settings`.  The diff applies cleanly
(`git apply --check`).

## Fix validation

`fix_status: not_testable` — amdgpu is not in the kernel build on this
guest, so neither the bug nor the fix can be exercised at runtime or
even compile-tested via `nativekernel` (the translation unit is not
compiled into GENERIC).  Validated by: clean `git apply --check`, and
source inspection confirming the guard uses the existing
`LANE_COUNT_*` enum and the existing `DC_LOG_WARNING` macro (both
already used elsewhere in the same file).
