# DF-4862 — VERDICT

**Status: reproduced** (verbatim-function harness, 3/3 deterministic runs)
**Impact: dos** (device-side OOB DMA read of up to ~4 GB from the staged
firmware window + SMU/GPU fault → driver-load DoS; limited device-side
disclosure of adjacent GTT pages into SMC SRAM, no userland readback
primitive absent a second bug — same ceiling/convention as DF-4774)
**Severity filed: Medium · bucket: kernleak · confidence: certain**

## What was run

`build.sh && run.sh` on the DragonFly 6.5-DEVELOPMENT guest
(`cc 8.3 [DragonFly]`), baseline + patched twin, plus two extra baseline
runs for determinism. No AMD GPU is present on the guest; per house
methodology (DF-4774, DF-4665, DF-3683, DF-2096) the harness executes the
verbatim kernel function bodies with 1:1 struct layouts against a mock
GTT/SMU-DMA model.

## Baseline observations (run.log)

- Scenario [2] — crafted MEC header with `jt_offset=0x4000` dwords,
  `jt_size=0x100` dwords, `ucode_size_bytes=0x1000`, file 0x12000 bytes,
  `size_bytes == datasize` so `amdgpu_ucode_validate` PASSES:
  - `kernel-side OOB reads during init_bo/patch_jt: 0 bytes` — the file is
    fully self-consistent, so nothing in the kernel staging path (including
    `patch_jt`'s source read) ever leaves the allocation. This is what makes
    the finding distinct from DF-1947 (staging memcpy OOB) — that bug's
    kernel-side read window is never entered.
  - TOC entry: `data_size_byte=0x10000 (65536)` with `image_addr` pointing
    at the MEC1 staged window `[..0x3000, ..0x5000)` (0x2000 bytes).
  - Mock SMU DMA (walks the read like the SMU would, through the GPU
    mapping): `8192 bytes in-bounds, 57344 bytes BEYOND the staged window`
    and the walk hits the unmapped page at +0x13000 → GPU page fault /
    SMU hang class.
  - Marker: `RESULT: SMU-SIDE OOB DMA READ CONFIRMED: 57344 bytes beyond
    the staged fw_buf window + unmapped-page fault class`.
- Scenario [1] — legit header (`jt_offset=0x300`): `0xc00` bytes, fully
    in-bounds. No false positive.
- Scenario [3] — `jt_offset=0x3F000000`: the child dies on SIGSEGV inside
    the verbatim `patch_jt` emulation because the JT source
    (`fw->data + array_offset + jt_offset*4` = ~4 GB past the blob) is
    unmapped — on real hardware this is the kernel-side panic through the
    DF-1947 site at driver attach. Included to show the field is unbounded
    end-to-end; the *clean* DF-4862 window is scenario [2], which needs no
    kernel-side violation at all.
- `image_size` from `jt_offset<<2` also wraps mod 2^32 (`0x3F000000<<2 =
    0xFC000000`), i.e. the reported window is attacker-chosen arbitrarily.

## Root cause chain (path:line)

1. `sys/dev/drm/amd/amdgpu/amdgpu_cgs.c:234-235` —
   `info->image_size = le32_to_cpu(header->jt_offset) << 2;` with no bound
   against `data_size` (`ucode_size_bytes`, line 221), the file, or the
   staged window.
2. `sys/dev/drm/amd/amdgpu/amdgpu_ucode.c:251-259` — the only validation is
   `datasize == size_bytes` (DF-1946).
3. `sys/dev/drm/amd/amdgpu/amdgpu_ucode.c:449-485` — the staged MEC1 window
   is `ALIGN(ucode_size_bytes,PAGE)` + `ALIGN(jt_size<<2,PAGE)`;
   nothing checks the TOC-reported window against it.
4. `sys/dev/drm/amd/powerplay/smumgr/smu7_smumgr.c:305-327` —
   `entry->data_size_byte = info.image_size`; `:405` CP_MEC entry;
   `:424` TOC → SMU DRAM; `:431` `PPSMC_MSG_LoadUcodes` → SMU DMA of
   `data_size_byte` bytes from `image_addr`.
5. Reachability: `gfx_v8_0.c:1204` registers `ucode[CP_MEC1].fw` on exactly
   the SMU-load asics (Topaz/Tonga/Fiji/Polaris/VegaM per
   `amdgpu_ucode.c:290-304`), driver attach → powerplay `start_smu` →
   `smu7_request_smu_load_fw`. Threat: crafted root-placed MEC firmware
   file (or compromised firmware source) — same threat model as DF-4774.

## Fix validation (fix.diff)

Patched twin = every byte identical except the bound at the construction
(`jt_offset<<2 > ucode_size_bytes → -EINVAL`, plus the DF-4863 index guard).
- Scenario [1] legit header: unchanged, `0xc00` in-bounds, still loads.
- Scenario [2]: `populate CP_MEC entry: -22 (rejected at the cgs
  construction — FIX VALIDATED)` — no TOC entry, no SMU DMA attempted.
- 3/3 runs. Full kernel rebuild not performed: no AMD GPU exists on the
  audit guest, so the verbatim-function harness is the faithful validation
  surface (same methodology as DF-4774, whose `fix.diff` used the identical
  pattern for the SMU branch).

## Notes

- `hwmgr->not_vf` VF `info.image_size -= 20` underflow
  (`smu7_smumgr.c:326`) is a pre-existing wart noted in DF-4774 — not
  re-filed, not part of this fix.
- The JT1/JT2 branch (`amdgpu_cgs.c:223-227`) is self-consistent with the
  staging layout (jt window `ALIGN(jt_size<<2,PAGE)`), no finding there.
- `CGS_UCODE_ID_GMCON_RENG` one-past-end aliasing is filed separately as
  DF-4863 (scenario [4] of the same harness).

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