# DF-4820 — `radeon_ring_restore()` leaks the kvmalloc'd ring-backup buffer on `radeon_ring_lock()` failure

**File:** `sys/dev/drm/radeon/radeon_ring.c:341-361` (sink: :350-352)
**Severity:** Medium (kernel heap exhaustion DoS, `kernleak` bucket) · **Confidence:** likely
**Upstream:** bug byte-identical in Linux v4.15 and v6.1 (never fixed upstream).

## Build

```
./build.sh            # baseline: stock kernel body (verbatim extraction)
./build.sh fixed      # + one-line fix from fix.diff
```
`build.sh` extracts lines 341-361 (the function under test) VERBATIM from
the kernel tree (falls back to the packed `body_fallback.inc`, extracted
from the audited tree) and compiles it inside `harness_env.h`'s mock
environment (DragonFly `cc`, userspace).

## Run

```
./run.sh
```

## Expected output (decisive lines)

```
================ BASELINE (stock kernel body) ================
injected radeon_ring_lock error: -35 (-EDEADLK (needs_reset still true during restore))
LIVE (leaked) blocks: 1000  (65532000 bytes = 63996 KiB)
RESULT: LEAK REPRODUCED — every failed restore leaks its 65532-byte kvmalloc backup buffer
injected radeon_ring_lock error: -2 (-ENOENT (no pending fences))
LIVE (leaked) blocks: 1000  (65532000 bytes = 63996 KiB)
RESULT: LEAK REPRODUCED ...
================ FIXED (kvfree on error path) ================
LIVE (leaked) blocks: 0  (0 bytes = 0 KiB)
RESULT: FIXED build leaks nothing — fix VALIDATED   (both modes)
```

Every simulated GPU-reset cycle in which the restore's ring allocation
fails leaks one `ring_size`-byte (here 64 KiB, typical GFX rings 1 MiB)
kvmalloc block. See `VERDICT.md` for why `-EDEADLK`/`-ENOENT` is the
deterministic kernel condition at that call site, not an invention.
