# VERDICT — DF-1127

## Verdict: REPRODUCED (primitive) / NOT REACHABLE on guest (HW-gated)

The cited bug is **real and confirmed** by source trace + userspace
demonstration. **Important correction:** the finding cited
`sys/dev/drm/amd/amdgpu/si_dpm.c` which is **dead code** on DragonFly
(absent from the amdgpu Makefile SRCS). The **same bug** exists in the
**compiled** copy `sys/dev/drm/radeon/si_dpm.c:6848-6850` which IS shipped
in `radeon.ko`. Both are patched in `fix.diff`.

## Mechanism (confirmed path:line)
1. `si_parse_power_table` (amdgpu copy `si_dpm.c:7210`, radeon copy
   `si_dpm.c:6808`) parses the PowerPlayInfo table from VBIOS.
2. amdgpu `:7253-7255` / radeon `:6848-6850`:
   ```c
   non_clock_array_index = power_state->v2.nonClockInfoIndex;
   non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
       &non_clock_info_array->nonClockInfo[non_clock_array_index];
   ```
   `nonClockInfoIndex` is read from the (untrusted) VBIOS with **no check
   against `ucNumEntries`**.
3. The sibling clock loop at amdgpu `:7267-7275` / radeon `:6864-6872`
   **does** check `if (clock_array_index >= clock_info_array->ucNumEntries)
   continue;` — proving the omission is an oversight, not policy.
4. Same issue at amdgpu `:7288-7290` / radeon `:6885` for VCE `clk_idx`.
5. Crafted/malformed VBIOS → `nonClockInfo[huge_index]` → OOB read from
   BIOS mapping → info leak via sysfs `pp_dpm_sclk` or panic.

## Reproduction (userspace harness)
The harness builds a simulated BIOS mapping with a valid 4-entry
`nonClockInfo` array, then indexes at `nonClockInfoIndex = 42`:
```
[buggy path] si_dpm.c:7253-7255 -- NO bounds check
  nonClockInfoIndex = 42 (ucNumEntries = 4)
  accesses bios_mapping[674] (mapping size = 256)
  -> READ PAST MAPPING BOUNDARY -> kernel OOB read
```

## Impact ceiling
- **Per-trigger**: kernel OOB read from BIOS mapping. The read data feeds
  `si_parse_pplib_non_clock_info` which populates `dpm.ps[i]` — some
  fields are exposed via sysfs (`pp_dpm_sclk`) → info leak. A sufficiently
  out-of-range index may fault → panic.
- **Privilege**: requires AMD GPU (Tahiti/Southern Islands) + crafted VBIOS
  (VFIO GPU passthrough romfile, corrupt EEPROM). Not local unpriv.
- **Realistic**: VFIO passthrough with attacker-controlled romfile is the
  realistic vector. Niche but real in cloud/VFIO scenarios.

## Fix
`fix.diff` adds the bounds check to **both** copies:
```c
if (non_clock_array_index >= non_clock_info_array->ucNumEntries) {
    power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
    continue;
}
```
— mirroring the existing clock-loop check. The `power_state_offset` advance
is duplicated so the `continue` correctly skips to the next state.

Validated: **`radeon.ko` builds with `RC=0`** after applying the fix (this
is the module that actually ships the bug).

## Fix validation
- Patch applies cleanly to both files: amdgpu `Hunk #1 succeeded at 7251`,
  radeon `Hunk #1 succeeded at 6846`.
- `make` in `sys/dev/drm/radeon/` → `radeon.ko` linked (2.0 MB), `rc=0`.
- `amdgpu.ko` also builds with `rc=0` (though it doesn't compile si_dpm.c).
- Cannot boot-test (no AMD GPU; VGA is a QEMU stub `chip=0x11111234`);
  `fix_status: not_testable`.

## Correction to the finding
The finding cites `sys/dev/drm/amd/amdgpu/si_dpm.c` — this file is NOT
compiled into any shipped module (not in amdgpu's Makefile SRCS). The live
copy with identical code and the identical bug is
`sys/dev/drm/radeon/si_dpm.c`, confirmed compiled via
`nm /boot/kernel/radeon.ko | grep si_dpm_init`. The `fix.diff` patches
both; the radeon copy is the one that matters for shipped security.

## PoC changes
- `harness.c` written from scratch. Simulates a BIOS mapping and
  demonstrates the OOB read at a bogus index, with a side-by-side
  comparison to the validated clock loop.
