# DF-1837 — Verification Verdict

## Verdict: REPRODUCED (source-confirmed + arithmetic-harness)

The unbounded EDID length is confirmed at
`sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c:583-584`. The
harness reproduces the 128-byte overflow for a 4-extension EDID.

## Mechanism

```c
// amdgpu_dm_helpers.c:583-584
sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);  // :583
memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length); // :584
```

`edid->extensions` is a `u8` (0..255) (drm_edid.h:317); `EDID_LENGTH`
is 128 (drm_edid.h:32); `raw_edid` is `uint8_t[DC_MAX_EDID_BUFFER_SIZE=512]`
(dc_types.h:98,169). `length` can be up to `128*256 = 32768`, overflowing
`raw_edid` by up to `32256` bytes into the heap-allocated `dc_sink`
(kzalloc, dc_sink.c:87), corrupting `edid_caps`, `dc_container_id`,
`priv`, `link`, `ctx`, refcount, and adjacent slab objects.

`drm_do_get_edid` (drm_edid.c:1649) reads `edid[0x7e]=extensions` with
no upper bound, only validating per-block checksums — so a malicious
monitor, EDID-emulator/dummy plug, or `drm.edid_firmware` override
controls the count. The sibling `dc.c:1774` DOES check
`if (len > DC_MAX_EDID_BUFFER_SIZE) return NULL` before its memmove at
dc.c:1794, proving the bound is required.

## Harness evidence

```
DF-1837: dm_helpers_read_local_edid (amdgpu_dm_helpers.c:583-584)
  edid->extensions = 4
  computed length = EDID_LENGTH * (ext+1) = 640
  raw_edid[DC_MAX_EDID_BUFFER_SIZE=512] (dc_types.h:98)
  OVERFLOW = 128 bytes past raw_edid into dc_sink heap object
  Harness: simulated memmove wrote 124 sentinel bytes past raw_edid
  Contrast dc.c:1774 which checks (len > DC_MAX_EDID_BUFFER_SIZE) before memmove — the bound is required and missing here.
```

## Why no live trigger on this guest

`dm_helpers_read_local_edid` runs during AMD GPU display connector probe.
The audit guest has no AMD GPU; `amdgpu.ko` is present but not loaded.
A crafted EDID on a dummy plug or a root `drm.edid_firmware=` override
on real AMD HW is the trigger. Valid Phase-6 hard blocker.

## Exploit chain

Not applicable (AMD-GPU-gated). No `uid=0` claim. Live ceiling: panic
or 128..32256-byte heap corruption in the `dc_sink` slab bucket; with
slab grooming on real HW, potentially an arbitrary write → kernel
priv-esc.

## PoC changes

- Added `harness.c`: flat-buffer model showing the overflow length and
  sentinel corruption.
- Added `fix.diff`: cap the EDID length at DC_MAX_EDID_BUFFER_SIZE,
  mirroring dc.c:1774.

## Fix

`fix.diff` adds `if (edid->extensions + 1 > DC_MAX_EDID_BUFFER_SIZE /
EDID_LENGTH) return EDID_NO_RESPONSE;` before the length computation.

- BEFORE: harness shows 128-byte overflow for extensions=4.
- AFTER: the check rejects extensions > 3 before any memmove.
