# DF-4495 — dce100_link_encoder_create OOB const-table reads (VBIOS-indexed)

**File:** `sys/dev/drm/amd/display/dc/dce100/dce100_resource.c:560-577`
**Family:** DF-4312 (dcn10) / DF-4319 (dce80) / DF-4352 (dce110) / DF-4375 (dce112) twin.

## What

`dce100_link_encoder_create()` indexes three `static const` register tables
with values taken straight from the GPU VBIOS object tables, with no
validation anywhere on the path:

```c
dce110_link_encoder_construct(enc110, enc_init_data, &link_enc_feature,
        &link_enc_regs[enc_init_data->transmitter],      /* :573 — 7 entries */
        &link_enc_aux_regs[enc_init_data->channel - 1],  /* :574 — 6 entries */
        &link_enc_hpd_regs[enc_init_data->hpd_source]);  /* :575 — 6 entries */
```

The values are produced by (all in `sys/dev/drm/amd/display/dc/core/dc_link.c`):

- `translate_encoder_to_transmitter()` (:1006-1069): emits
  `TRANSMITTER_UNKNOWN` (-1) for unknown encoder ids/enum_ids, and 7/8/9
  (`TRAVIS_CRT`/`TRAVIS_LCD`/`UNIPHY_G`) for external TRAVIS / UNIPHY3
  encoder objects — `-1, 7, 8, 9` are all OOB for `link_enc_regs[7]`.
- `get_ddc_line()` (:964-1004): emits `CHANNEL_ID_UNKNOWN` (0),
  `CHANNEL_ID_DDC_VGA` (7), `CHANNEL_ID_I2C_PAD` (8) — after the `- 1`
  these give indices `-1, 6, 7`, all OOB for `link_enc_aux_regs[6]`.
- `get_hpd_line()` (:925-962): returns `HPD_SOURCEID_UNKNOWN` (7) for any
  connector without a mapped HPD gpio (default arm) — OOB for
  `link_enc_hpd_regs[6]`.

The OOB-read garbage is stored as the encoder's register base set; every
subsequent register access on that link encoder issues MMIO at
VBIOS-steerable wild offsets (bring-up hang / machine check during `amdgpu`
bind / link detection). No userspace-readable leak; no unprivileged or
remote trigger — the attacker model is crafted/flashed VBIOS or a malicious
PCIe device.

## Reproduce (guest-side model — no AMD GPU required)

```
cc -O2 -Wall -o df4495 df4495.c   # build.sh
./df4495                          # run.sh
```

Expected decisive output (`run.log`, re-confirmed in `run.2.log`):

```
CONST-TABLE OOB READ CONFIRMED (model): dce100_resource.c:573-575 forms
&link_enc_regs[tx], &link_enc_aux_regs[ch-1], &link_enc_hpd_regs[hpd] with
unvalidated VBIOS-derived indexes — garbage becomes the encoder's MMIO
register bases.
```

with the per-table tally: 4/11 transmitter, 3/9 channel, 1/7 hpd_source
reachable values OOB (8/27), and a concrete craftable triple
(TRAVIS_CRT + DDC_VGA + no-HPD → indices 7/6/7, all three OOB at once).

## Why not a kernel PoC on the audit guest

`env.txt`: the guest has **0 AMD/ATI PCI devices**; the amdgpu/dce100 path
never executes. Same situation as the accepted family twins
(DF-4352/DF-4375). The defect is source-certain; runtime impact is
hardware-gated.

## Fix

`fix.diff` (git-apply clean against this tree): bounds-check the three
values in `dce100_link_encoder_create` and return NULL — the caller
(`dc_link.c:1184-1190`) already handles a NULL link encoder by failing just
that link.
