# DF-4774 VERDICT — reproduced (harness), impact=dos (+device-directed disclosure)

## What was verified

The exact kernel functions from `sys/dev/drm/amd/powerplay/smumgr/smu7_smumgr.c`
(`smu7_upload_smc_firmware_data` :461-478 and `smu7_upload_smu_firmware_image`
:481-500, copied verbatim) were compiled on the DragonFly 6.5-DEVELOPMENT
guest against 1:1 struct layouts (`common_firmware_header`,
`smc_firmware_header_v1_0`, `cgs_firmware_info`, `smu7_smumgr`) and fed by the
verbatim SMU branch of `amdgpu_cgs_get_firmware_info`
(amdgpu_cgs.c:437-472) with `amdgpu_ucode_validate` (amdgpu_ucode.c:251-259)
as the only gate. MMIO writes are captured in a mock SMC SRAM sink; the
firmware blob is an mmap'd allocation followed by read-only canary pages
(unique `0xCCnnnnnn` dwords) and a PROT_NONE guard page — modeling the
kernel heap allocation that `request_firmware` produces (`fw->data`,
`fw->datasize`).

## Result (run.log; identical in run.2.log, run.3.log)

1. **Adjacent OOB read confirmed.** With a crafted header
   (`size_bytes == filesize` → validate passes; `ucode_array_offset_bytes`
   = end of blob; `ucode_size_bytes` = 0x1000 ≤ SMU7_SMC_SIZE), the verbatim
   upload loop streamed **1024/1024 canary dwords into the SMC SRAM sink**
   (`sink sample: cc000000 cc000001 cc000002 …`). In the kernel this is
   adjacent heap memory disclosed dword-by-dword into GPU SMC SRAM via
   `cgs_write_register(mmSMC_IND_DATA_11, *src++)` (smu7_smumgr.c:470-471).
2. **Wild-read panic class.** `ucode_array_offset_bytes = 0x40000000` (1 GB
   past) with `ucode_size_bytes = 0x20000` — the *maximum* the length gate
   permits — kills the reading child with SIGSEGV. Same at 0xFFFFF000
   (~4 GB, u32 near-wrap base). In-kernel equivalent: unrecoverable page
   fault at driver load → panic.
3. **The only check is the length gate.** `limit >= byte_count`
   (smu7_smumgr.c:465, `limit = SMU7_SMC_SIZE = 0x20000`) rejects
   `ucode_size_bytes > 0x20000` but never examines the base offset, and
   nothing on the path compares `ucode_array_offset_bytes` or
   `ucode_size_bytes` against `fw->datasize`.

## Why this is a real kernel memory-safety bug

`amdgpu_ucode_validate()` proves only `fw->datasize == hdr->size_bytes`
(self-declared). `amdgpu_cgs_get_firmware_info()` then builds
`info->kptr = fw->data + ucode_array_offset_bytes` and
`info->image_size = ucode_size_bytes` (amdgpu_cgs.c:464-472) and
`smu7_upload_smu_firmware_image()` hands both to the upload loop
(smu7_smumgr.c:497). The kernel therefore dereferences a pointer/length pair
fully controlled by the firmware file, against an allocation whose size it
knows (`fw->datasize`) but never checks. Reached unconditionally at powerplay
`start_smu` for Tonga/Fiji/Polaris10/11/12/Topaz/VegaM
(polaris10_smumgr.c:209, tonga_smumgr.c:104, fiji/vegam/iceland equivalents).

Preconditions: AMD smu7-family GPU + attacker-supplied SMC firmware file
(root on the box / malicious firmware package). Identical trust model and
severity band as the filed twins DF-2065 (Medium), DF-2104 (Medium), DF-2096
(Low, amdgpu direct path).

## Fix validation (patched twin)

`smu7_fw_upload_oob_patched.c` is byte-identical to the baseline except for
the `fix.diff` bound check inserted at the pointer construction (the exact
hunk proposed for amdgpu_cgs.c). All three attack scenarios print
**FIX VALIDATED**: the header is rejected with `-EINVAL` before any read,
0 dwords streamed, no fault; the legit-header scenario still uploads 512
dwords (no functional regression).

Note on patched `[2]` printing `upload result: 0`: this is *verbatim* kernel
behavior, not a harness artifact — `smu7_upload_smu_firmware_image()`
**ignores the return of `cgs_get_firmware_info()`** (smu7_smumgr.c:488-493),
so a rejected info lookup leaves `info = {0}` and the length-0 upload
"succeeds" with zero reads. The OOB read is gone; the pre-existing
error-swallowing wart (also noted for smu7_send_msg_to_smc) is a separate
reliability issue, not filed.

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-4665/DF-3683/DF-2096).

## Exploit chain

crafted SMC firmware file (root-placed) → powerplay start_smu at driver
attach → request_firmware + amdgpu_ucode_validate (self-declared sizes pass)
→ amdgpu_cgs_get_firmware_info builds `fw->data + attacker_u32` /
`attacker_u32 ≤ 0x20000` → smu7_upload_smc_firmware_data reads up to 128 KB
OOB from the kernel heap → (a) wild base → panic; (b) adjacent base →
heap memory streamed into SMC SRAM (device-side disclosure; no userland
readback primitive absent a second bug). Ceiling: DoS + limited disclosure,
hence Medium.

## Artifacts

* `smu7_fw_upload_oob.c` / `smu7_fw_upload_oob_patched.c` — sources
* `build.sh`, `run.sh`, `build.log`, `run.log`, `run.2.log`, `run.3.log`, `env.txt`
* `fix.diff` — bound check at amdgpu_cgs.c:461-472 (never applied to `sys/`)

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