# DF-1260 — AIOGCAP NULL-deref on d->mixer_dev (LATENT on audit guest; source-confirmed)

## Verdict
**NOT REPRODUCED on the audit guest (LATENT / HW-gated).** The bug is
**confirmed real by source-level trace**; it cannot fire on this guest
because no audio hardware attaches, so `/dev/dsp` cannot be opened and the
AIOGCAP handler is never reached.

## Mechanism (confirmed in source)
- `dsp.c:1311`  `pdev = d->mixer_dev;`                          (no NULL check)
- `dsp.c:1313`  `p->inputs = pdev->si_drv1 ? mix_getdevs(pdev->si_drv1) : 0;`
  The ternary guards `pdev->si_drv1` but **not** `pdev` itself. If
  `d->mixer_dev == NULL` (mixer_init failed, or mid-detach after
  `mixer_uninit`), the read `pdev->si_drv1` dereferences
  `NULL + offsetof(struct cdev, si_drv1)` → fatal trap.
- **Every sibling ioctl in the same file guards it**: `dsp.c:1124`,
  `dsp.c:1852`, `dsp.c:1865`, `dsp.c:2760` all do
  `if (d->mixer_dev != NULL)`. Only AIOGCAP (1311-1313) forgets to.
- `/dev/dsp` is mode `0666` (`crw-rw-rw-`), so reaching it from an
  unprivileged user is trivial **once** a pcm device with a NULL mixer exists.

## Why it does not reproduce here
- `kldload sound.ko` succeeds and creates `/dev/dsp` (0666), BUT
- `pciconf -lv` shows **no multimedia/audio class** device; no `snd_*` PCI
  bridge driver attaches, so **zero pcm devices are registered**
  (`/dev/sndstat` is empty).
- With no registered pcm device, `open("/dev/dsp", O_RDWR)` returns fd=-1
  (EBADF on DragonFly), so the AIOGCAP handler — which operates on a
  `snddev_info d` obtained from an open pcm cdev — is never entered.
- Reaching the bug needs: real audio HW + a `snd_*` driver that registers a
  pcm device whose `mixer_init` failed (or a detach race leaving
  `mixer_dev==NULL`).

This is a **valid hard blocker** for live reproduction: the path is unreachable
at runtime on this guest and no userspace action exercises it without audio HW.

## Exploit chain
N/A — NULL-deref panic (DoS), HW-gated (latent). No write primitive, no
escalation chain. Realistic threat: a local unprivileged user on a machine
whose audio driver registered a mixer-less pcm device (or racing a detach)
triggers a kernel panic via a single `ioctl(AIOGCAP)` on `/dev/dsp`.

## PoC changes
`trigger.c` opens `/dev/dsp` and attempts `ioctl(AIOGCAP)`; on this guest it
reports the open failure (no pcm device). The trigger documents the path; the
fix is the deliverable.

## Fix (`fix.diff`)
Guard `pdev` itself, not only `pdev->si_drv1` — matching the sibling ioctls:
```c
p->inputs = (pdev != NULL && pdev->si_drv1 != NULL)
            ? mix_getdevs(pdev->si_drv1) : 0;
```
Applies cleanly (`patch -p1` rc=0). Matches the finding proposal.

## Fix validation
See `fix_build.log` / `fix_run.log`. A sound-enabled kernel (`DF1260` config =
`X86_64_GENERIC` + `device sound`) was built with the fix applied to confirm
the patched `dsp.c` compiles cleanly. The bug itself is not triggerable on the
guest (no audio HW), so there is no live before/after; `fix_status=not_testable`
per the latent-bug rule, with compile validation.
