# DF-3614 — Verdict

## Verdict: REPRODUCED (source-level + harness) — OOB write past lowSMIO[32], confined to the si_power_info allocation; corrupts SMC-bound power configuration

radeon twin of the **lowSMIO sink** half of amdgpu DF-3585. The `entries[]`
half of the same root cause is pass-1 **DF-1136**; this sink is a distinct
write primitive that survives an entries-only clamp.

## Bug confirmation

Reachability — all three flags are VBIOS-derived (si_dpm_init):

```c
si_dpm.c:7001-7003  pi->voltage_control      = VDDC advertises GPIO_LUT  (true)
si_dpm.c:7017-7023  eg_pi->vddci_control     = VDDCI GPIO_LUT            (false)
                     si_pi->vddci_control_svi2= VDDCI SVID2               (true)
si_dpm.c:7004-7011  si_pi->voltage_control_svi2 = VDDC SVID2              (false)
```

Data flow:

```c
si_dpm.c:3967-3976  VDDC GPIO table fetched AND TRIMMED to 32
si_dpm.c:3998-4004  vddci_control_svi2 -> si_get_svi2_voltage_table(
                         &dyn_state.vddci_dependency_on_mclk, &vddci_voltage_table)
                     -> vddci_voltage_table.count = dependency count (u8, <=255)
                        NO TRIM (GPIO paths trim at :3973/:3993/:4020)
                     [entries[] overflow there == DF-1136; the COUNT survives]
si_dpm.c:4058       if (si_pi->voltage_control_svi2) { ... } else {        // else taken:
si_dpm.c:4079           if (eg_pi->vddci_voltage_table.count) {
si_dpm.c:4080               si_populate_smc_voltage_table(rdev,
                                    &eg_pi->vddci_voltage_table, table);
si_dpm.c:4046-4047           for (i = 0; i < voltage_table->count; i++)
                                 table->lowSMIO[i] |= cpu_to_be32(entries[i].smio_low);
```

`lowSMIO` is `uint32_t[32]` (sislands_smc.h:207/215) inside the packed
3012-byte `SISLANDS_SMC_STATETABLE`, embedded in the `kzalloc`'d
`si_power_info` (si_dpm.h:196). With count 33..255 the OR-write walks up to
1020 bytes past `lowSMIO[0]`, corrupting `voltageMaskTable`,
`phaseMaskTable`, `dpm2Params`, the four SWSTATEs and `dpmLevels[]` —
everything that `si_init_smc_table` uploads to the GPU power-management
microcontroller at si_dpm.c:4779-4781 (`si_copy_bytes_to_smc(... sizeof
(SISLANDS_SMC_STATETABLE) ...)`). Consequence: wrong VDDC/VDDCI/MVDD masks,
wrong TDP limits, wrong state clocks programmed on the GPU — miscalibrated
voltages (undervoltage instability / overvoltage stress) from a crafted
VBIOS. The overflow is CONTAINED within the single si_power_info allocation
(max touched offset 1087 vs struct size 3012+), so no cross-object kernel
heap corruption — hence Medium, not High.

## Harness confirmation

`run.log` (verbatim packed struct replicas from sislands_smc.h):

```
sizeof(SISLANDS_SMC_STATETABLE) = 3012; lowSMIO spans 4..132
last byte touched by buggy loop: lowSMIO[254] at offset 1020
[A] lowSMIO[32]=0xa5a55a5a (OOB start)
    voltageMaskTable.lowMask[0] (VDDC mask) = 0xa5a55a5a  CORRUPTED
    phaseMaskTable.lowMask[0]                = 0xa5a55a5a  CORRUPTED
    dpm2Params.TDPLimit                      = 0xa5a55a5a  CORRUPTED
    initialState.levels[0].sclk.sclk_value   = 0xa5a55a5a  CORRUPTED
    first corrupted byte at allocation offset 68; last touched offset 1087
[B] lowSMIO[32]=0x00000000 (untouched) ... dpm2Params.TDPLimit intact
```

GCC independently flags the replica loop:
`warning: iteration 32 invokes undefined behavior [-Warray-bounds]` /
`array subscript 32 is above array bounds of 'uint32[32]'` — the compiler's
own confirmation that i>=32 is out of bounds.

## Trigger conditions (not met on this guest)

SI GPU + radeon DPM (virtio-only guest) + mixed-VRM VBIOS (VDDC GPIO_LUT,
VDDCI SVID2) with `vddci_dependency_on_mclk.ucNumEntries > 32`.

## Exploit chain

Contained corruption — no cross-object primitive, no kernel-memory info leak;
the attacker-visible effect is tampered GPU power config (hardware risk), so
impact is DoS-grade for the kernel itself.

## Fix

`fix.diff` — bound the sink loop:

```c
for (i = 0; i < voltage_table->count && i < SISLANDS_MAX_NO_VREG_STEPS; i++)
```

(defense-in-depth at the sink; independently recommended alongside the
DF-1136 root-cause clamp in si_get_svi2_voltage_table).
Validation: apply-check OK; `make si_dpm.o` -Werror clean (stacked);
harness `[B]` shows the statetable tail intact after the fix.

`fix_status: fixed` (compile + harness-level).

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