# DF-4863 — `adev->firmware.ucode[fw_type_convert(...)]` one-past-end index on the default path

## What

`amdgpu_cgs_get_firmware_info()` non-SMU branch
(`sys/dev/drm/amd/amdgpu/amdgpu_cgs.c:214-215`):

```c
id = fw_type_convert(cgs_device, type);
ucode = &adev->firmware.ucode[id];
if (ucode->fw == NULL)              /* <-- OOB read here */
        return -EINVAL;
```

`fw_type_convert()` (`amdgpu_cgs.c:111-156`) returns
`AMDGPU_UCODE_ID_MAXIMUM` (= 21) from its **default** case — exactly the
declared size of `adev->firmware.ucode[]` (`amdgpu_ucode.h:252-253`), and
the return value is never range-checked before indexing. Any CGS ucode id
that `fw_type_convert` does not map — today that includes
`CGS_UCODE_ID_GMCON_RENG` (`cgs_common.h:58`, which exists in the enum but
is unhandled), `CGS_UCODE_ID_MAXIMUM` itself, or any future/garbage value —
produces a one-past-the-end element:

- `ucode[MAXIMUM].fw` (element offset +8) reads **exactly**
  `adev->firmware.fw_buf` (the `struct amdgpu_bo *` at struct offset 1016 —
  `_Static_assert`ed in the harness, and proven at runtime:
  `&ucode[MAXIMUM].fw == &firmware.fw_buf`).
- On SMU/PSP-load asics `fw_buf` is non-NULL after `amdgpu_ucode_init_bo()`
  (which `smu7_request_smu_load_fw()` invokes first thing,
  `smu7_smumgr.c:343`), so the NULL guard passes and
  `header = (gfx_firmware_header_v1_0 *)ucode->fw->data` treats
  `struct amdgpu_bo` internals as `struct firmware` (`sys/sys/firmware.h:51`,
  `data` at offset 8) and dereferences the result — a type-confused wild
  read (panic class), with garbage flowing into `info->image_size` /
  `info->version` / `info->kptr` for downstream SMU consumers.

**Reachability today: latent** — every in-tree caller
(smu7/smu8/ci/iceland/vega10/vega12/vega20 smumgrs) passes only types that
`fw_type_convert` maps. The defect is the missing bound on a converter whose
default return is precisely the array size — a landmine for the next caller
(the enum already contains the unhandled `GMCON_RENG` value). Filed as
Low/hardening; the alias itself is proven at runtime.

## Build / run / expected

Same harness as DF-4862 (`sh build.sh && sh run.sh`); this finding's
trigger is **scenario [4]**. Expected baseline:

```
[4] fw_type_convert default -> AMDGPU_UCODE_ID_MAXIMUM one-past-end
  &firmware.ucode[MAXIMUM].fw = 0x403758  == &firmware.firmware... : ALIAS CONFIRMED
  cgs_get_firmware_info(CGS_UCODE_ID_GMCON_RENG) = 0
  type-confused header=bo+8 -> image_size=0x5a5a5a5a ... propagated to caller
```

Patched twin (index guard from `fix.diff`):

```
  cgs_get_firmware_info(CGS_UCODE_ID_GMCON_RENG) = -22 (one-past-end index rejected — FIX VALIDATED)
```

The harness sets `firmware.fw_buf` to a mapped mock whose +8 qword points
into a readable page, so the verbatim code runs to completion and the
garbage propagation is *shown* instead of crashing; on real hardware that
qword is `struct amdgpu_bo`/`ttm_buffer_object` internals — an arbitrary
pointer.
