# DF-1181 — VERDICT

**Status:** NOT REPRODUCED (HW-gated; bug confirmed in source)
**Impact:** none (cannot trigger on this guest)
**Confidence:** certain (line-by-line source trace)
**Class:** heap OOB read (CWE-125) — latent

## Mechanism (cited)

The powerplay Vega10 hwmgr patches VBIOS dependency tables by reading
per-entry voltage indices and looking them up in fixed-size allocation
tables.  All index fields are `uint8_t` from the VBIOS:

`vega10_hwmgr.c:658-680` (inside
`vega10_patch_voltage_dependency_tables_with_lookup_table`):

```c
for (entry_id = 0; entry_id < vdt->count; entry_id++) {
    voltage_id = vdt->entries[entry_id].vddInd;          // u8
    vdt->entries[entry_id].vddc =
        table_info->vddc_lookup_table->entries[voltage_id].us_vdd;   // no check
}
...
for (entry_id = 0; entry_id < mm_table->count; ++entry_id) {
    voltage_id = mm_table->entries[entry_id].vddcInd;     // u8
    mm_table->entries[entry_id].vddc =
        table_info->vddc_lookup_table->entries[voltage_id].us_vdd;   // no check
}
for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
    voltage_id = mclk_table->entries[entry_id].vddInd;        // u8
    mclk_table->entries[entry_id].vddc =
        table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
    voltage_id = mclk_table->entries[entry_id].vddciInd;      // u8
    mclk_table->entries[entry_id].vddci =
        table_info->vddci_lookup_table->entries[voltage_id].us_vdd;
    voltage_id = mclk_table->entries[entry_id].mvddInd;       // u8
    mclk_table->entries[entry_id].mvdd =
        table_info->vddmem_lookup_table->entries[voltage_id].us_vdd;
}
```

`vega10_hwmgr.c:1856-1857` (`vega10_populate_single_display_type`):
```c
vddc = table_info->vddc_lookup_table->
    entries[dep_table->entries[i].vddInd].us_vdd;   // no check
```

`vega10_hwmgr.c:4248-4249` (`vega10_get_clock_by_type_with_voltage`):
```c
clocks->data[i].voltage_in_mv = (uint32_t)(table_info->vddc_lookup_table->
    entries[dep_table->entries[i].vddInd].us_vdd);   // no check
```

Allocation sizing in `vega10_processpptables.c:1014-1043` (`get_vddc_lookup_table`):
```c
table_size = sizeof(uint32_t) +
    sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels;
table = kzalloc(table_size, GFP_KERNEL);
table->count = vddc_lookup_pp_tables->ucNumEntries;
```

Callers at `vega10_processpptables.c:1108-1127` pass `max_levels` = 8 for
vddc, 4 for vddmem, 4 for vddci.  With `vddciInd = 100` from the VBIOS
the kernel reads ~1000 bytes past the 4-entry (40-byte) allocation —
CWE-125 heap OOB read.  Read values flow back to the SMC firmware and
into sysfs.

## Why it cannot be reproduced on this guest

* No AMD GPU on the PCI bus (`pciconf -l`: vgapci0 is QEMU stdvga vendor
  0x1234, not AMD).
* `amdgpu`, `radeon`, `drm`, `powerplay` are **not** in
  `X86_64_GENERIC`; the powerplay module never attaches, so the Vega10
  hwmgr init path that calls
  `vega10_patch_voltage_dependency_tables_with_lookup_table` is never
  taken.
* Even with hardware present the trigger requires a malicious VBIOS
  (root or physical access to flash).

**Latent / hardware-gated** bug; confirmed real by source trace,
unreachable on the audit guest, not an unprivileged-local-to-root
escalation.  `harness.c` is a userspace transcription of the indexing
logic; it builds, runs, and prints which indices would OOB-read, but
produces no kernel effect.

## Fix
`fix.diff` adds `if (index >= table->count) return -EINVAL/-1;` before
every `vddInd`/`vddciInd`/`mvddInd`/`vddcInd` index site (3 functions,
7 sites).  Validated as **applies + compiles** only — the bug path
cannot be exercised without AMD hardware, so `fix_status: not_testable`.
