# DF-4405 — VERDICT

**Finding:** the UVD firmware loader in `sys/dev/drm/amd/amdgpu/amdgpu_uvd.c`
consumes `common_firmware_header.ucode_size_bytes` and
`.ucode_array_offset_bytes` with no bound against the actual firmware blob —
the only gate, `amdgpu_ucode_validate()` (`sys/dev/drm/amd/amdgpu/amdgpu_ucode.c:251-260`),
checks a *different* field (`fw->datasize == hdr->size_bytes`).

**Verdict: `inconclusive`** — the kernel path cannot be executed on the audit
guest (no AMD GPU: `pciconf` shows only QEMU bochs VGA, `/dev/dri` absent,
`amdgpu.ko` loads but never attaches) and triggering it additionally requires
a root-installed malicious firmware file. The defect itself is **certain**:

1. `amdgpu_uvd.c:253` — `bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)`:
   `ucode_size_bytes + 8` is u32 arithmetic; at `0xFFFFFFF8` it wraps to 0 and
   the UVD bo is created without firmware space (demo: run.log, sw_init block).
2. `amdgpu_uvd.c:405-407` — resume (when `saved_bo == NULL`, the normal
   first-resume path for direct-load firmware) executes
   `memcpy_toio(cpu_addr, fw->data + offset, ucode_size_bytes)` — a 4 GiB OOB
   read past the `firmware` buffer for the same header (demo: run.log, resume
   block: 4,294,938,616 bytes past a 32 KiB blob).
3. `amdgpu_uvd.c:408-411` — `size -= ucode_size_bytes` underflows u32 and the
   subsequent `memset_io(ptr, 0, size)` runs past the bo's mapped extent.

This is the `amdgpu_uvd.c` instance of the DF-1946 family (root:
`amdgpu_ucode.c:251`; siblings DF-1164 gfx_v7_0, DF-1451 sdma_v4_0,
DF-1598 sdma_v2_4, DF-1854 psp_asd …). Pass 1 of this file did not file it
(only DF-1595/DF-1596 exist for this file).

## Severity rationale

Low: the attacker must control a firmware file under `/boot/modules/`
(root-only write) *and* the machine must have AMD hardware. The impact if those
preconditions hold is a kernel OOB read of arbitrary length and an OOB
`memset_io` — memory corruption — so the family fix is worth backporting, but
the privilege model keeps it Low.

## Attempts

One build+run cycle on the guest (exact arithmetic replication, deterministic,
exit 0, two runs — run.log, run.2.log). No kernel execution possible.

## Fix

`fix.diff` (git-apply clean) bounds the ucode extent against
`adev->uvd.fw->datasize` in `sw_init`, immediately after
`amdgpu_ucode_validate()` — the same style as the family fix; this also
inoculates `resume` (firmware blob is immutable between init and resume).
A patched-kernel run is not possible on this guest (no AMD GPU), so
`fix_status: not_testable`.

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