# DF-3573 VERDICT — legacy-firmware size-check bypass → heap OOB reads in legacy loaders

**Status: not_testable** (kernel path requires CIK radeon hardware; guest is
virtio-only) · **logic-level reproduction: 3/3 runs, deterministic** ·
**confidence: certain** (source-traced + upstream-diffed)

## Reproduced?

At the logic level, yes — deterministically, on the guest itself (compiled
with the guest's cc 8.3). At the kernel level, no — and honestly so:

- The trigger path is `vgapci attach (CIK device) → radeon_driver_load →
  cik_init → cik_init_microcode → (later) cik_cp_resume →
  cik_cp_gfx_load_microcode legacy loop`.
- The audit guest's only display device is `vgapci0@pci0:0:2.0:
  chip=0x11111234` (QEMU virtual VGA). QEMU has no radeon CIK emulation.
  `radeon.ko` and the `radeonkmsfw_BONAIRE_*` modules exist in /boot/kernel
  but nothing attaches, so `cik_init_microcode()` can never run.
- Per the honest-status table this is "guest reachable but the target device
  is absent" → `not_testable`, `reproduced=0`, `impact=none` (on this guest).

## Why the finding is nonetheless certain (the full source chain)

1. **The gate is asymmetric.** Only the pfp block does `err = -EINVAL; goto
   out;` (cik.c:2056-2061). The me/ce/mec/rlc/sdma blocks (cik.c:2080-2084,
   2103-2107, 2126-2130, 2164-2168, 2187-2191), the mc block (2216-2221) and
   the smc block (2248-2252) set `err` and **continue**.
2. **err is a scratch variable.** Each next stage begins
   `err = request_firmware(&rdev->X_fw, ...)` which assigns 0 on success
   (e.g. cik.c:2096-2098). After the last stage, the only remaining guard is
   the mixing check (cik.c:2265-2272), which sets `err` only when
   `1 <= new_fw < num_fw`. With **all-legacy** firmware (`new_fw == 0`) the
   final `err` is simply whatever the last successful assignment left: **0**.
   → function returns 0 with the wrong-size fw installed, `new_fw=false`.
3. **The consumers are constant-bounded.** With `new_fw == false` the loaders
   loop over `CIK_ME_UCODE_SIZE` (2144 dwords, cik.c:3980),
   `CIK_MEC_UCODE_SIZE` (4192 dw, cik.c:4318/4326),
   `BONAIRE|KV|KB|ML_RLC_UCODE_SIZE` (cik.c:6001-6002) and
   `CIK_SDMA_UCODE_SIZE` (1050 dw, cik_sdma.c:501/508) — reading from
   `rdev->X_fw->data` regardless of the actual allocation. The size gate in
   (1) was the ONLY thing guaranteeing `datasize >= CONSTANT*4`.
4. **Net effect:** heap OOB read of `(CONSTANT*4 - datasize)` bytes per
   short legacy fw, streamed into `CP_*_UCODE_DATA` / `RLC_GPM_UCODE_DATA` /
   `SDMA*_UCODE_DATA` register FIFOs. Worst single span: MEC 4192*4=16768 B
   minus file size. Can also fault (panic) if the read walks past the last
   mapped page of the firmware allocation.
5. **Upstream parity verified:** downloaded Linux v4.7
   `drivers/gpu/drm/radeon/cik.c` and confirmed the identical asymmetric
   `goto out` (only pfp) — this is an upstream bug faithfully ported, not a
   DFly transcription error. `cve_match=equivalent`.

## Harness result (run.log, run.2.log, 3/3 stable)

- S1 (truncated legacy ME, 1024 B vs 8576 B): baseline `err=0 (ACCEPTED)`,
  `me_fw(1024B)` installed → simulated cik.c:3980 loop reads 8576 B →
  **7552 bytes past allocation**. With `-DFIXED` (fix.diff): `err=-22`,
  all firmware released at `out:` (models cik.c:2275-2297).
- S2 control (truncated **pfp**): rejected in BOTH modes — proving the
  asymmetry is the bug, not the harness.
- S3 control (all stock): accepted in both modes — fix has no false
  positives on a healthy system.

## Exploit chain — why this stops at defense-in-depth

Precondition: root must place a wrong-size legacy firmware module
(`radeonkmsfw_BONAIRE_me.ko` &c.) in /boot/kernel — the DFly firmware
loader only reads root-owned modules. That makes the primitive root-gated
(no unpriv→root path), consistent with DF-1119's rating of the sibling
new-format issue. The OOB data goes to GPU ucode registers, not directly to
userspace, so even the leak ceiling is indirect. Residual risk: kernel panic
(page-crossing OOB) and GPU-state corruption on systems with mis-installed
firmware — a robustness hole more than an attacker primitive, hence **Low**.

## Fix validation

`fix.diff` (7 × `goto out`, pfp-parity) applies `patch -p0` clean to a
scratch copy of sys/dev/drm/radeon/cik.c and compiles conceptually identical
logic in the harness's FIXED mode (reject + release-all). A patched-kernel
boot test is impossible on this guest (no CIK device), so
`fix_status=not_testable`; the logic-level A/B (baseline accepts / fixed
rejects / controls unchanged) is recorded in run.log.

## Recommendation

Carry the fix.diff upstream as well — the asymmetric `goto out` is live in
Linux's radeon cik.c today.

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