# DF-3993 — VERDICT

**Status: inconclusive (source-certain, hardware-gated) — kernel NULL-deref
panic (local DoS), unprivileged, on radeon-equipped systems.**

## What was verified (source level, line-by-line)

1. **User control of the ring index.** `radeon_cs_parser_init()` reads the
   user FLAGS chunk: `ring = p->chunks[i].kdata[1]` at
   `sys/dev/drm/radeon/radeon_cs.c:357`. `radeon_cs_get_ring()`
   (`radeon_cs.c:204-245`) maps `RADEON_CS_RING_UVD`(3)→
   `R600_RING_TYPE_UVD_INDEX`(5) and `RADEON_CS_RING_VCE`(4)→
   `TN_RING_TYPE_VCE1_INDEX`(6) with **no family/`has_uvd`/`has_vce` gate**
   — compare the DMA case, which *does* gate by family
   (`radeon_cs.c:224-234`), proving the omission is not a design invariant.

2. **The dispatch hub leaves those slots NULL.** In the audited file
   `sys/dev/drm/radeon/radeon_asic.c`, the per-family `.ring[]` designated
   initializers only set existing rings; all other slots are NULL:
   - r100/r200/r300(+pcie)/r420/rs400/rs600/rs690/rv515/r520 tables: GFX only
     (radeon_asic.c:214-216, 282-284, 378-380, 446-448, 514-516, 582-584,
     650-652, 718-720, 786-788, 854-856);
   - `r600_asic`: GFX+DMA, UVD/VCE NULL (radeon_asic.c:950-953);
   - `cayman_asic`: VCE NULL while VM is enabled (radeon_asic.c:1686-1693);
   - only trinity/si/ci/kv wire VCE (1804-1813, 1942-1951, 2112-2121,
     2225-2234).

3. **Unchecked deref before the op-level NULL check.**
   `radeon_cs.c:375-386`:
   ```c
   if ((p->cs_flags & RADEON_CS_USE_VM) == 0) {
           if (p->rdev->asic->ring[p->ring]->cs_parse == NULL) {   /* line 376 */
   ```
   The NULL check protects the *op inside the ring struct* — not the *ring
   slot itself*. `cs_parse` is the 5th pointer in `struct radeon_asic_ring`
   (`sys/dev/drm/radeon/radeon.h:1821-1847`, offset 0x20 LP64) → kernel read
   at absolute address 0x20 → fatal page fault. Same shape on the VM branch,
   line 381 (`->ib_parse`, offset 0x1c).

4. **Reachability.** `DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl,
   DRM_AUTH|DRM_RENDER_ALLOW)` (`sys/dev/drm/radeon/radeon_kms.c:912`) — the
   exact surface of DF-3763/DF-3953 (unpriv local user + DRI node access).
   The crash precedes all GEM/IB validation, so a single FLAGS chunk
   `{0, 3}` suffices; no buffers or handles needed.

## Why not "reproduced"
No radeon hardware exists on the audit guest and QEMU has no radeon device
model (evidence: `env.txt` — no `/dev/dri`, no DRM kmod, only virtio-VGA
0x1234:1111). Same posture as the accepted DF-3763/DF-3953 verdicts
(inconclusive/panic, source-certain).

## Impact ceiling
NULL+0x20 **read** whose result only feeds a comparison — the outcome is a
kernel panic (local DoS), not control flow or memory corruption beyond the
fault. No route to uid=0 from this primitive.

## Fix
Gate UVD/VCE ring selection by family/feature in `radeon_cs_get_ring()` and
add a NULL-slot guard before the member deref in `radeon_cs_parser_init()`
(see `fix.diff`).

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