# DF-5229 — radeon UVD v4.2 VCPU cache-window chain overruns `vcpu_bo` by 512 bytes (shipping CIK firmware)

**File:** `sys/dev/drm/radeon/uvd_v4_2.c:46-64` (vs bo sizing `sys/dev/drm/radeon/radeon_uvd.c:184-186`)
**Severity:** Low (GPU-scope VRAM overhang only) · **Bucket:** memcorrupt
**Family:** radeon twin of DF-4832 (uvd_v1_0, 128 B); amdgpu cousins DF-4524 (vce_v3_0, 256 B) / DF-4742 (vce_v2_0, 256 B)

## What to run

```
./build.sh        # host: decode the in-tree shipping fw -> fw_header.txt
python3 check_arith.py   # -> arith.log (exhaustive sweep; no kernel/hw needed)
```

## Expected output (decisive lines, arith.log)

```
header path: overrun bytes: min=512 max=512 ; vulnerable sizes: 65472/65536 (99.90%)
safe residues (ds%4096): [4089, 4090, 4091, 4092]
control: headerless path ... overrun sizes: 0/65536
datasize=232752 (v1.64 fw -> N=30): bo_size=2236416 span=2236928 overrun=512 bytes
  last window tail = gpu_addr + 0x222200 vs bo end gpu_addr + 0x222000
post-fix span == bo_size (header path): True
```

The **shipping** CIK UVD firmware (`sys/contrib/dev/drm/radeonfw/bonaire_uvd.bin.uu`,
loaded as `radeonkmsfw_bonaire_uvd` — the *preferred* fw for
BONAIRE/KABINI/KAVERI/HAWAII/MULLINS, radeon_uvd.c:124-131,139-141) decodes as
`datasize=232752, %4096=3376` (fw_header.txt), so `ALIGN(ds+4)==ALIGN(ds+8)`
and the STACK/SESSION window programmed by `uvd_v4_2_resume` ends **exactly
512 bytes past the end of `rdev->uvd.vcpu_bo`** — inside the VRAM object
allocated after it.

## Reproduce on hardware (not possible here)

1. Bare metal / GPU-passthrough VM with a CIK UVD GPU (BONAIRE, KABINI,
   KAVERI, HAWAII, MULLINS — radeonkms driver, new-format UVD fw loaded).
2. Trigger UVD use (any VDPAU/video decode CS on the UVD ring) — windows are
   programmed at ring start (cik.c:8175) or DPM ungate (kv_dpm.c:1628).
3. The last 512 B of the SESSION region (tail of handle 30's session) are
   GPU-written into the adjacent VRAM object — cross-object GPU
   read/write between GEM bo's (e.g. another user's buffer).

## Control & fix

* Headerless control (uvd_v4_2.c:49 +0 / `ALIGN(ds+4)`): 0 overruns for all
  65536 sizes — identical to the accepted-clean uvd_v2_2 shape.
* `fix.diff`: shrink region0 by the 0x200 skip so `offset0+size0` equals the
  fw region the bo actually holds (`ALIGN(datasize+8)`) — the same invariant
  amdgpu uses (`AMDGPU_UVD_FIRMWARE_OFFSET + AMDGPU_UVD_FIRMWARE_SIZE ==
  ALIGN(ucode_size+8)`, `sys/dev/drm/amd/amdgpu/amdgpu_uvd.h:32-38`).
  Post-fix span == bo_size for every ds in [0,0x2FFFF] and both N (arith.log).
