# DF-4792 — vega20_smumgr signed `table_id` guard bypass (`entry[]` OOB read/write)

## What

`vega20_copy_table_from_smc()` / `vega20_copy_table_to_smc()` in
`sys/dev/drm/amd/powerplay/smumgr/vega20_smumgr.c` take `int16_t table_id`
but the whole public API surface (`hwmgr.h:218`, `smumgr.h:114`,
`vega20_smc_table_manager` at vega20_smumgr.c:563) is `uint16_t`. The only
bounds check is a **signed** comparison:

```c
PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, "Invalid SMU Table ID!", return -EINVAL);
```

Any API value in `0x8000..0xFFFF` narrows to a negative `int16_t`, passes the
guard, and indexes `priv->smu_tables.entry[table_id]` **out of bounds** (before
the array — `struct vega20_smumgr` puts `smu_tables.entry[]` at offset 0, so
`entry[-1]` reads the preceding heap object). The OOB `.table` pointer and
`.size` then feed a `memcpy` in both directions = heap OOB **read and write**
whose target/length come from adjacent kernel memory.

Pass-1 missed vega20; this is the exact family twin of DF-2021 (vega12),
DF-2034 (vega10), DF-2072 (smu10) — all fixed the same way.

## Reachability (honest)

**Latent.** Every in-tree vega20 caller passes a compile-time constant
(`vega20_hwmgr.c:760,1106,1234,1253,1310,1924,1958,2726,2735,2961` —
TABLE_PPTABLE / TABLE_OVERDRIVE / TABLE_SMU_METRICS / TABLE_WATERMARKS).
No sysfs/ioctl path forwards a user-controlled `table_id`. The bug becomes
memory corruption the day any caller routes a 16-bit selector through
`smum_smc_table_manager()` — exactly how the twins were rated.

## Reproduce (inside the guest, after `./build.sh`)

```
./build.sh   # builds df4792.baseline.ko (verbatim int16_t) + df4792.fixed.ko (fix.diff's uint16_t)
./run.sh     # kldload baseline -> kldunload -> kldload fixed -> kldunload
```

Expected console (dmesg) — baseline:

```
DF-4792 harness loaded (param type: int16_t)
DF-4792: in-bounds id=9 (unalloc) rc=-22 (want -EINVAL)
DF-4792: to_smc(0xFFFF) rc=0 victim[0..7]=4141414141414141 << CONTROLLED KERNEL WRITE
DF-4792: from_smc(0xFFFF) rc=0 victim[0..7]=4141414141414141 << OOB KERNEL READ
DF-4792: from_smc(0x8000 -> entry[-32768], far OOB) rc=-22
```

fixed (`int16_t -> uint16_t`, exactly fix.diff):

```
DF-4792 harness loaded (param type: uint16_t)
PP: Invalid SMU Table ID!
DF-4792: to_smc(0xFFFF) rc=-22 victim[0..7]=0000000000000000 (untouched)
...
```

The harness is a DragonFly KLD that compiles the **verbatim** function bodies
(vega20_smumgr.c:163-236, 563-574) and struct layout (vega20_smumgr.h:29-43)
with only the MMIO SMC-message sender stubbed to `return 0` — see the header
comment of `vega20_oob_kld.c` for the exact substitution contract. A groomed
`entry[-1]` (32 bytes before the allocation, as on a real
`kzalloc(sizeof(struct vega20_smumgr))`) supplies `version=1, size=8,
table=victim`, so the OOB write/read land on a module-owned buffer — fully
deterministic, no wild writes, no panic.

## Fix

`fix.diff` — widen the two internal `table_id` parameters from `int16_t` to
`uint16_t` (matching the public API), making the existing `< TABLE_COUNT`
guard an unsigned comparison. Validated: harness-fixed variant rejects
`0xFFFF`/`0x8000` with `-EINVAL`, and the patched TU compiles clean in the
default `-Werror` kernel build (`fix_build.log`).
