# DF-4604 PoC — radeon_gem_va_ioctl bo_va UAF

## What this is

A minimal, self-contained trigger for the `bo_va` use-after-free in
`radeon_gem_va_ioctl()` (sys/dev/drm/radeon/radeon_gem.c:702). Two threads on
the same DRM fd: A loops `{GEM_CREATE → VA_MAP → VA_UNMAP}`, B races
`GEM_CLOSE` on the same handle, armed so that B is already blocked on the BO
reservation at the moment A's `radeon_vm_bo_set_addr()` internally drops it.

## Build

    ./build.sh            # cc -O2 -Wall -pthread -o radeon_va_uaf radeon_va_uaf.c

No drm headers required (UAPI vendored, BSD 3-arg `_IOWR` encoding matching
`sys/dev/drm/include/uapi/drm/drm.h:796-801`).

## Run (requires real radeon hardware, Cayman/HD69xx or newer)

    ./run.sh [/dev/dri/card0] [iterations]

**Expected (unpatched kernel):** kernel panic / drm fault in
`ttm_eu_reserve_buffers`, `mutex_lock`, or `radeon_vm_bo_update` within
seconds-to-minutes of iterations; with slab grooming, exploitable to uid=0
(see VERDICT.md).

**On the audit QEMU guest:** there is no radeon GPU; the binary builds and
runs, printing `SKIP: no DRM device…` and exiting `rc=3` (see `run.log`).
This is the expected guest outcome — runtime confirmation needs a physical
Cayman+ machine.

## Patched kernel

With `fix.diff` applied (bo_va re-looked-up under the re-established
reservation), the race window is closed; the trigger must run indefinitely
without corrupting memory.

## Files

- `radeon_va_uaf.c` — trigger source
- `build.sh` / `run.sh` — exact commands
- `build.log` / `run.log` — guest output (full, untrimmed)
- `env.txt` — guest environment
- `VERDICT.md` — full narrative with path:line proof
- `fix.diff` — validated-by-review unified fix
- `manifest.json`, `verdict.json`
