# DF-4943 — hw_translate_dce80.c: offset_to_id returns success for DDC-family offsets without writing *id → consumer switches on an uninitialized gpio_id

File audited (pass 2): `sys/dev/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c`
Lines: 172-196. Consumer: `gpio_service.c:143-157` (`dal_gpio_service_create_irq`).

## What to run

```
./build.sh && ./run.sh     # harness_dce80.c T1 section (run.log)
```

## Expected (reproduced on the DF 6.5-DEVELOPMENT guest)

```
== T1: DDC/VGA/I2CPAD offsets return success WITHOUT writing *id ==
offset_to_id(mmDC_GPIO_DDCVGA_A,0x100) = true en=6(id==(other))
  -> BUG(DF-4943): success returned, *id NEVER WRITTEN; consumer switches on uninitialized id
offset_to_id(mmDC_GPIO_I2CPAD_A,0x1)  = true en=7(id==(other))
offset_to_id(mmDC_GPIO_DDC1_A,0x100)  = true en=0(id==(other))
```

(0x7B7B7B7B poison left in `id` — the function returns `true` having only
written `*en`; the same holds for DDC2..DDC6.)

## Kernel chain (code trace)

1. VBIOS GPIO pin LUT entry (`usGpioPin_AIndex`, arbitrary u16 —
   `bios_parser.c:1819-1820`) that decodes to a DDC-family register offset
   is passed by `get_hpd_gpio` (`dc_link.c:115-118`) into
   `dal_gpio_service_create_irq` for a connector's hotplug pin.
2. `gpio_service.c:148-149` declares `enum gpio_id id; uint32_t en;`
   **uninitialized**; `offset_to_id` (line 151) returns true without writing
   `id` for DDC offsets (hw_translate_dce80.c:172-196).
3. Line 156 passes the indeterminate `id` to `dal_gpio_create_irq`
   (gpio_service.c:366-391): only `GPIO_ID_HPD(3)` / `GPIO_ID_GPIO_PAD(4)`
   proceed; everything else is (correctly) rejected.
4. If the garbage value is 3 (`GPIO_ID_HPD`), `dal_gpio_create(service, HPD,
   en∈{0..7}, …)` → `dal_gpio_service_open(HPD, en)` → `define_hpd_registers(
   pin, en)` (gpio_service.c:258-261) → `hpd->regs = &hpd_regs[en]`
   (hw_factory_dce80.c:143) with `hpd_regs[]` sized **6** → `en` 6/7 is an
   OOB const-array read; the garbage `int_status`/`toggle_filt_cntl`
   descriptors then drive `REG_GET`/`REG_UPDATE_2` MMIO (hw_hpd.c:89,110).
   (`id_to_offset` itself would reject HPD en≥6 — proven in the harness T5 —
   but that check sits in a different function than the open path.)

Uninitialized-memory use is MSan-detectable and CWE-457 regardless of which
garbage value lands in the slot; the OOB sub-chain additionally requires that
value to equal 3 (per-build deterministic, unknown statically).

## After fix.diff

T1 shows `*id = GPIO_ID_DDC_DATA` written on every DDC decode
(fixrun.log: "-> FIXED: *id now written (GPIO_ID_DDC_DATA), consumer guard
accepts"), eliminating the uninitialized read entirely.

## Impact ceiling

Same VBIOS-craft precondition as DF-4942 plus a stack-garbage coin flip;
worst case OOB rodata read → wild MMIO (DoS). Rated Low because both stages
are probabilistic relative to DF-4942's deterministic producer.
