# DF-1177 — `rv_init_cp_jump_table` jt_size OOB + `mec2_fw` NULL deref

## Finding

`rv_init_cp_jump_table()` at `sys/dev/drm/amd/amdgpu/gfx_v9_0.c:1068-1128`
copies jump-table entries from up to five firmware blobs (CE, PFP, ME, MEC,
MEC2) into the `cp_table` BO. The loop is:

```c
/* gfx_v9_0.c:1077 */  dst_ptr = adev->gfx.rlc.cp_table_ptr;
/* gfx_v9_0.c:1078 */  for (me = 0; me < max_me /* 5 */; me++) {
                            ... fw_data = <firmware ucode_array_offset_bytes>
                            table_offset = le32_to_cpu(hdr->jt_offset);
                            table_size   = le32_to_cpu(hdr->jt_size);
/* gfx_v9_0.c:1121 */      for (i = 0; i < table_size; i++) {
/* gfx_v9_0.c:1122 */          dst_ptr[bo_offset + i] =
/* gfx_v9_0.c:1123 */              le32_to_cpu(fw_data[table_offset + i]);
                            }
                            bo_offset += table_size;
                        }
```

### Bug 1 — `jt_size` unbounded → OOB write past `cp_table` BO

The `cp_table` BO is allocated at `gfx_v9_0.c:1178-1183` with size
`ALIGN(96 * 5 * 4, 2048) + (64 * 1024)` = `2048 + 65536` = `67584` bytes =
**16896 u32 dwords**. `jt_size` (a `u32` from each firmware header,
`amdgpu_ucode.h:83`) is used as the inner loop bound with no validation
against the remaining BO capacity. A large `jt_size` writes past the BO
mapping → **OOB write into adjacent VRAM** (corrupts whatever follows).
`table_offset + i` is likewise unvalidated against `fw->datasize` → **OOB
read past the firmware buffer**.

### Bug 2 — `me == 4` dereferences `mec2_fw->data` unconditionally

The `me == 4` branch at line 1111-1118 reads `adev->gfx.mec2_fw->data` with
no NULL check. `mec2_fw` is set to `NULL` at `gfx_v9_0.c:744` when
`request_firmware` for the (optional) mec2 firmware fails:

```c
/* gfx_v9_0.c:730-745 */
err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
if (!err) {
    err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
    ...
} else {
    err = 0;
    adev->gfx.mec2_fw = NULL;     /* <-- optional firmware absent */
}
```

`rv_init_cp_jump_table` runs unconditionally for `max_me = 5`, so a Raven APU
with missing optional mec2 firmware will dereference NULL at line 1113 →
**immediate kernel panic**.

Same class as DF-1134 (gfx_v7) and DF-1164 (gfx_v8).

## Reproducibility on the audit guest

`amdgpu` is `optional` (`sys/conf/files:2492+`); not in `X86_64_GENERIC`;
QEMU guest has no AMD GPU. The `amdgpu.ko` module cannot initialize without
AMD hardware, so a live trigger is not possible on this guest.

A userspace harness (`harness.c`) reconstructs the loop with the 16896-dword
`cp_table` and demonstrates both bugs:

```
=== Case 1: large jt_size in CE firmware -> OOB write past cp_table ===
  CE jt_size = 25088 (cp_table = 16896 dwords) -> overflows by 8192 dwords
  BUG: write past cp_table[CP_TABLE_DWORDS] detected -- kernel equivalent: OOB write past cp_table BO

=== Case 2: me==4 dereferences adev->gfx.mec2_fw->data with mec2_fw==NULL ===
  (mimics Raven APU boot with missing optional mec2 firmware)
  BUG: NULL deref of mec2_fw (signal 11) -- kernel equivalent: panic in rv_init_cp_jump_table at gfx_v9_0.c:1113
```

## Threat model

Same as DF-1176: triggerable by root (planting crafted firmware) or a
malicious hypervisor. The NULL-deref variant (Bug 2) is also triggerable on
**any** Raven APU system where the optional mec2 firmware file is absent at
boot — that is a realistic operational condition, not an attack.

Severity Medium: OOB write requires privileged firmware placement; NULL deref
is a real DoS on misconfigured Raven systems.

## Recommended fix

1. Validate `jt_size` against the remaining cp_table capacity
   (`CP_TABLE_DWORDS - bo_offset`) and against `fw->datasize` before each
   copy loop.
2. Skip `me == 4` when `mec2_fw == NULL`.

See `fix.diff`.
