# DF-3993 — CS ioctl ring dispatch → NULL `asic->ring[]` slot deref (kernel panic)

## Finding
`radeon_cs_parser_init()` dereferences `p->rdev->asic->ring[p->ring]` at
`sys/dev/drm/radeon/radeon_cs.c:376` (non-VM path) and `:381` (VM path)
**before any check that the ring slot exists for this asic family**.
`p->ring` is chosen by `radeon_cs_get_ring()` (`radeon_cs.c:204-245`) from the
**second dword of the user-supplied RADEON_CHUNK_ID_FLAGS chunk**
(`radeon_cs.c:354-357`), and the UVD / VCE cases perform **no family gating**:

```c
case RADEON_CS_RING_UVD:                       /* radeon_cs.c:236 */
        p->ring = R600_RING_TYPE_UVD_INDEX;    /* = 5 */
        break;
case RADEON_CS_RING_VCE:                       /* radeon_cs.c:239 */
        p->ring = TN_RING_TYPE_VCE1_INDEX;     /* = 6 */
        break;
```

The dispatch tables in the audited hub file `sys/dev/drm/radeon/radeon_asic.c`
only populate the ring slots that exist per family. Every designated
initializer leaves unlisted indices NULL:

- `r100_asic` (radeon_asic.c:214-216), `r200_asic` (282-284), `r300_asic`
  (378-380), `r300_asic_pcie` (446-448), `r420_asic` (514-516), `rs400_asic`
  (582-584), `rs600_asic` (650-652), `rs690_asic` (718-720), `rv515_asic`
  (786-788), `r520_asic` (854-856): only `[RADEON_RING_TYPE_GFX_INDEX]`.
- `r600_asic` (radeon_asic.c:950-953): GFX + DMA only →
  `[R600_RING_TYPE_UVD_INDEX]` (5) and `[TN_RING_TYPE_VCE1_INDEX]` (6) NULL.
- `rv6xx_asic` … `cayman_asic`: UVD (5) wired, **VCE (6/7) NULL** — including
  `cayman_asic` (radeon_asic.c:1686-1693), whose VM manager *is* enabled, so
  even the `RADEON_CS_USE_VM` branch (radeon_cs.c:381) dereferences the NULL
  slot.
- Only `trinity_asic` (1804-1813), `si_asic` (1942-1951), `ci_asic`
  (2112-2121), `kv_asic` (2225-2234) wire the VCE rings.

`struct radeon_asic_ring` (sys/dev/drm/radeon/radeon.h:1821-1847) places
`cs_parse` at offset 0x20 (5th pointer on LP64), so the unchecked
`asic->ring[5]->cs_parse` is a kernel read at absolute address 0x20 → fatal
page fault → kernel panic.

## Crash matrix (user-selectable)
| user ring id | asic family | crash site |
|---|---|---|
| `RADEON_CS_RING_UVD` (3), no USE_VM | r100 … r600 (all pre-RV610 + R600) | radeon_cs.c:376 |
| `RADEON_CS_RING_VCE` (4), no USE_VM | every family except TN/SI/CI/KV | radeon_cs.c:376 |
| `RADEON_CS_RING_VCE` (4), USE_VM | cayman (VM enabled, VCE ring NULL) | radeon_cs.c:381 |

(UVD+VM on pre-cayman is rejected earlier at radeon_cs.c:365-369 because the
VM manager is disabled there.)

## Reachability
`RADEON_CS` ioctl is registered `DRM_AUTH|DRM_RENDER_ALLOW`
(sys/dev/drm/radeon/radeon_kms.c:912) — same attack surface as DF-3763 /
DF-3953 (unprivileged local user with access to the DRI device: render node
by design needs no master; on a master-less primary node any user can become
DRM master and authenticate). The crash happens inside
`radeon_cs_parser_init()` — **before** any GEM handle lookup or IB
validation — so the ioctl needs only a well-formed FLAGS chunk:
`{chunk_id=3, length_dw=2, chunk_data={flags=0, ring=3}}`.

## Reproduce (real hardware only)
```
cc -O2 -o cs_nullring cs_nullring.c
./cs_nullring            # on any pre-RV610 / R600 radeon with radeonkms
# expected: instant kernel panic, "Fatal kernel mode data access: read at 0x20"
```

## Guest status
Not reproducible on the audit QEMU guest: it has no `/dev/dri`, no DRM kmod,
and QEMU provides no radeon VGA device model at all (see `env.txt`).
Status: **inconclusive** — source-level certainty, hardware-gated.
