# DF-4405 — `amdgpu_uvd_sw_init`/`amdgpu_uvd_resume` trust unvalidated firmware header extent fields (DF-1946 family instance)

**File:** `sys/dev/drm/amd/amdgpu/amdgpu_uvd.c:195-202` (only gate),
`:250-253` (bo_size wrap), `:403-411` (OOB copy / underflowed memset).
**Severity:** Low (requires attacker-installed firmware — root-only supply
path — on AMD hardware) · **Confidence:** certain (arithmetic demo +
line-certain inspection; family root = DF-1946 in `amdgpu_ucode.c:251`).

`amdgpu_ucode_validate()` only checks `fw->datasize == hdr->size_bytes`
(`sys/dev/drm/amd/amdgpu/amdgpu_ucode.c:251-260`). The UVD loader then trusts
`hdr->ucode_size_bytes` and `hdr->ucode_array_offset_bytes` without any bound
against the blob:

* `amdgpu_uvd.c:253` — `AMDGPU_GPU_PAGE_ALIGN(ucode_size_bytes + 8)`: with
  `ucode_size_bytes = 0xFFFFFFF8` the u32 `+8` wraps to 0 and the UVD bo is
  allocated **without any firmware space**;
* `amdgpu_uvd.c:405-407` — resume copies `ucode_size_bytes` bytes from
  `fw->data + ucode_array_offset_bytes` into VRAM: with the same header that
  is a **~4 GiB OOB read** past a 32 KiB kernel firmware buffer;
* `amdgpu_uvd.c:408-411` — `size -= ucode_size_bytes` underflows and the
  following `memset_io(ptr, 0, size)` writes past the bo's ioremap extent.

## Build

```
cc -O2 -Wall -o fw_hdr_overflow fw_hdr_overflow.c      # or ./build.sh (guest)
```

## Run

```
./fw_hdr_overflow                                     # or ./run.sh (guest)
```

## Expected output

Exact-arithmetic replica showing: `amdgpu_ucode_validate` returns 0
(ACCEPTED) for a 32 KiB blob whose header claims `ucode_size_bytes =
0xFFFFFFF8` at offset `0x1000`; the `+8` wrap zeroes the bo_size term; resume
would copy `0xfffffff8` bytes (4 GiB) from the blob — 4,294,938,616 bytes past
its end — and then `memset_io` 8 bytes past the bo end. Exit 0.

## Not-a-PoC note

Executing the real path needs an AMD GPU **and** a root-installed malicious
firmware file (`/boot/modules/amdgpufw_*_uvd`); the audit guest has neither
the hardware (QEMU bochs VGA only, no `/dev/dri`) nor, as policy, root-attacker
scope. Status: `inconclusive`; the arithmetic is deterministic C semantics and
is demonstrated in full (see run.log).
