# DF-1314 — btc_copy_vbios_mc_reg_table off-by-one (radeon BTC DPM)

## Verdict
**NOT TESTABLE AT RUNTIME on this guest — confirmed real latent vulnerability in source.**

## Mechanism (confirmed by source trace)
`sys/dev/drm/radeon/btc_dpm.c` initialises the MC register table for
Barts/Turks/Caicos (evergreen-family) radeon GPUs.

1. `btc_copy_vbios_mc_reg_table()` (line 1987) copies the VBIOS table into the
   driver struct.  Line 1992:
   ```c
   if (table->last > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)   /* SIZE = 16 */
       return -EINVAL;
   ```
   uses `>` instead of `>=`, so it **admits `last == 16`**.  It then sets
   `eg_table->last = table->last` (= 16) at line 2000.

2. `btc_initialize_mc_reg_table()` (line 2014) then calls
   `btc_set_mc_special_registers()` (line 2050).

3. `btc_set_mc_special_registers()` (line 1913) starts `j = table->last` = 16
   (line 1920) and, in the `MC_SEQ_MISC1 >> 2` case, writes
   `table->mc_reg_address[j]` and `table->mc_reg_table_entry[k].mc_data[j]`
   **at index 16** (lines 1924, 1927) — which is one past the
   `mc_reg_address[16]` / `mc_data[16]` arrays (indices 0–15) — **BEFORE** the
   guard `if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) return -EINVAL;` at
   line 1933 (a post-write check).

   Result: `last == 16` ⇒ an OOB write at array index 16, overflowing
   `struct evergreen_mc_reg_table` (`cypress_dpm.h`) into adjacent fields
   (e.g. `vddc_voltage_table`).

4. Sibling bug: `ni_dpm.c:2850` has the identical `>` pattern with
   `SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE`.  Same off-by-one; same fix.  (Noted
   for maintainers; the included fix.diff targets the cited btc_dpm.c.)

## Why it does not reproduce on this guest
- radeon is **not** in GENERIC (loadable `radeon.ko`, not loaded); no AMD GPU
  present.  The MC-reg-table init runs only at radeon evergreen/BTC bring-up,
  which never happens on this GPU-less guest.  (Case d.)

## Severity / realistic ceiling
On a host with a Northern-Islands/evergreen radeon GPU whose VBIOS reports
`last == 16`, this is a kernel heap OOB write during DPM init → heap
corruption / panic; firmware-data-driven (malformed/malicious VBIOS).

## Fix (see fix.diff)
Change `>` to `>=` at `btc_dpm.c:1992` so `last == 16` is rejected before the
arrays are populated and before `btc_set_mc_special_registers` writes past
them.  Compile-validated (radeon module build).  Runtime not exercisable here.
