# DF-4946 VERDICT — reproduced (deterministic unit-level; kernel stage needs Raven HW + crafted VBIOS)

## What was run

`harness_dcn10.c` embeds **verbatim** copies of `offset_to_id` and `id_to_offset`
from `sys/dev/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c` (lines 61-201,
203-388) with the single substitution `ASSERT_CRITICAL(x)` → printf marker.
Constants are the real DCN10 values: `DCE_BASE__INST0_SEG2 = 0x34C0`
(vega10_ip_offset.h:277) and the `mmDC_GPIO_*` offsets/BASE_IDX from
dcn_1_0_offset.h:10349-10584. Enums are the real gpio_types.h values
(`GPIO_DDC_LINE_I2C_PAD` aliases `VIP_PAD` = 7; `COUNT` = 8).

## Result (run.log)

- **T1:** all 8 DDC-family offsets return `true` with `*id` untouched
  (`id==0x7b7b7b7b UNTOUCHED` on every line). DDC1..6 → en 0..5, DDCVGA →
  **en=6**, I2CPAD → **en=7**. `hpd_regs[]` in hw_factory_dcn10.c:71-78 has
  exactly 6 entries (indices 0..5) — en 6/7 are out of bounds.
- **T2 (negative):** raw mmGPIOPAD-style offset 0x183 (the DF-4942 dce80
  deterministic producer) is rejected — DCN10 has **no GPIOPAD case**, so the
  cross-domain producer is absent; `REG(DC_GPIO_DEBUG)` correctly returns false.
- **T4 (negative):** the HPD branch is well-formed (writes `*id`, en 0..5).

## Consumer chain (source-cited)

1. `get_hpd_gpio` (core/dc_link.c:96-119) calls `dal_gpio_service_create_irq`
   with `pin_info.offset/mask` taken from the VBIOS atom gpio pin table
   (`dcb->funcs->get_gpio_pin_info`, bios_parser2.c:537-539).
2. `dal_gpio_service_create_irq` (gpio_service.c:143-157) declares
   `enum gpio_id id;` **uninitialized** and passes `&id` to `offset_to_id`;
   on `true` it forwards the garbage `id` + DDC-line `en` to
   `dal_gpio_create_irq`.
3. `dal_gpio_create_irq` (gpio_service.c:366-391) accepts `GPIO_ID_HPD`;
   `dal_gpio_create` → `dal_gpio_open_ex` → `dal_gpio_service_open`
   (gpio_service.c:224-290): `busyness[HPD]` is 1 uint (number_of_pins[HPD]=6,
   hw_factory_dcn10.c:186) so `is_pin_busy(en=6/7)` stays inside the
   allocation, and if the bit is clear → `create_hpd` +
   `define_hpd_registers(pin, 6/7)`.
4. `define_hpd_registers` (hw_factory_dcn10.c:149-157) evaluates
   `&hpd_regs[en]` — **OOB read of the 6-entry const array**; the garbage
   `struct hpd_registers` (register offsets read past the array into adjacent
   rodata) then drives `dal_hw_gpio_open`/`hw_hpd` MMIO programming
   (wrong-register writes / reads at attacker-uncontrolled MMIO offsets) →
   misbehavior to panic (dos). The final stage is probabilistic (depends on
   the uninitialized stack slot decoding to 3).

The **primary** DDC consumer, `dal_gpio_create_ddc` (gpio_service.c:408-457),
ignores `id` and hardcodes `GPIO_ID_DDC_DATA/CLOCK`; with DCN10's
`ddc_data_regs[8]`/`ddc_clk_regs[8]` (hw_factory_dcn10.c:94-114) and
`number_of_pins[DDC_*]=8` (hw_factory_dcn10.c:183-184), en 0..7 are in-bounds —
so, unlike dce80 (DF-4942), the DDC happy path itself is safe on DCN10. The
uninit-`*id` defect matters only through the IRQ path above.

## Why not kernel-stage on this guest

`env.txt`: 0 AMD PCI devices in the QEMU guest — no `amdgpu`/DC attach, no
VBIOS under test. Same situation as the verified family twins DF-4943/4945;
their precedent (unit-level deterministic proof + cited kernel chain) is
followed exactly.

## Fix validation

`fix.diff` adds `*id = GPIO_ID_DDC_DATA;` to all eight DDC-family branches.
`harness_fixed.c` applies the same edit to the embedded copy: every DDC-family
success now reports `id=0 (WRITTEN)`, and with `id==GPIO_ID_DDC_DATA`
`dal_gpio_create_irq` takes its default branch and returns NULL —
`define_hpd_registers` can never be reached with en=6/7 (0 residual
violations, FIXEXIT=0). A kernel rebuild cannot alter the output of a
userland unit harness; structural validation matches the family precedent
(DF-4943/4945 fix_status=validated).

## fix.diff applies cleanly?

Authored against the read-only sys/ tree at
hw_translate_dcn10.c:165-189; hunks are one-line insertions on distinct
`case` labels — no context drift.

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