# DF-4942 VERDICT

**Status: reproduced (unit-level, verbatim function copy executed on the DF guest); kernel chain proven by code trace — full execution requires an AMD ASIC + crafted VBIOS, which the QEMU guest does not have.**

## What was proven, and how

- The audited functions `index_from_vector`, `offset_to_id`, `id_to_offset`
  were copied **verbatim** from
  `sys/dev/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c:44-400` into
  `harness_dce80.c`, with the real register constants from
  `dce_8_0_d.h`/`dce_8_0_sh_mask.h`/`smu_7_0_1_d.h` and the real enum values
  from `gpio_types.h`. Compiled with gcc 8.3 (`-O2 -Wall -Wextra`, zero
  warnings) and executed on the DragonFly 6.5-DEVELOPMENT guest.
- Output (`run.log`): `offset_to_id(mmGPIOPAD_A, 1<<20)` returns **true**
  with `id=GPIO_ID_GPIO_PAD(4)`, `en=20`. 20 ≥ 8 = the number of entries in
  `ddc_data_regs[]`/`ddc_clk_regs[]` (hw_factory_dce80.c:84-104). That is the
  exact decode result the kernel consumer receives.
- Negative controls (T3): `1<<31` → false (31 > GPIO_GPIO_PAD_MAX=30),
  multi-bit mask → false (GPIO_ENUM_UNKNOWN=32 > 30), zero → false. The
  *internal* GPIOPAD bound is sound; the defect is that success is reported in
  a call context whose only consumer (`dal_gpio_create_ddc`,
  gpio_service.c:408-457) discards `*id` and interprets `en` in the
  `gpio_ddc_line` domain (8 entries).

## Kernel chain (traced, path:line)

`bios_parser.c:1881` (usClkA_RegisterIndex, arbitrary VBIOS u16; equals
mmGPIOPAD_A=0x183 on the DCE8 input path — smu_7_0_1_d.h:138) →
`dc_link_ddc.c:272-276` (`dal_gpio_create_ddc(gpio_service, 0x183, 1<<shift, …)`)
→ `gpio_service.c:418-419` offset_to_id success, `428-437` creates
DDC_DATA/DDC_CLOCK gpio objects with `en` (id output ignored) → first DDC use
`gpio_base.c:59-72` `dal_gpio_open_ex` → `gpio_service.c:244-253`
`create_ddc_data` + `define_ddc_registers(pin, en)` → `hw_factory_dce80.c:122`
`ddc->regs = &ddc_data_regs[en]` — **OOB const-array read for en ∈ [8..30]** —
→ `hw_ddc.c`/`hw_gpio.c` use `regs->…` addresses for `REG_UPDATE`/`REG_GET`
MMIO (garbage offsets from adjacent .rodata: likely ddc_clk_regs[0..] for
en 8..15 — wrong-but-in-layout register descriptors; beyond that, shift/mask
constants reinterpreted as register addresses → unmapped MMIO → panic/MCE).

Related already-filed finding (consumer side, different array): DF-4827
(dce_i2c_sw.c sw_i2cs[MAX_PIPES=6] vs GPIO_DDC_LINE_COUNT=8). DF-4942 is the
translate-side producer defect for a *different* consumer array pair
(ddc_data_regs/ddc_clk_regs, 8 entries) with the GPIOPAD domain (en≤30) as the
OOB source — not a re-report.

## Why not executed end-to-end

Guest has no AMD GPU (pciconf: 0 devices vendor 0x1002; amdgpu module not
loaded — env.txt). The VBIOS→GPIO path only executes on real ASICs at driver
attach. The deterministic producer stage was executed verbatim instead; the
consumer stage is a four-hop straight-line trace with no branches that could
change the outcome (`en` is passed unmodified: create_ddc_data(ctx,id,en) →
define_ddc_registers(pin,en) → array index).

## Fix validation

`fix.diff` (3 files: dce80 translate sets `*id=GPIO_ID_DDC_DATA` on all 8 DDC
cases; dce120 same; `gpio_service.c:dal_gpio_create_ddc` rejects
`id != GPIO_ID_DDC_DATA`) — `git apply --check` clean; `harness_fixed.c`
models the fixed translate + consumer guard: en=20 decode now rejected at the
consumer (`accepted=0`), 0 regressions, T4/T5 behaviors preserved (fixrun.log).

## Impact

Medium. DoS-class (panic/wrong-register MMIO) at driver attach with a
crafted/corrupt VBIOS; not unprivileged-user-reachable on stock hardware.

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