# DF-4727 — aureal: `chn_intr(au->pch.channel)` runs with NULL channel in the attach window before `pcm_addchan` — NULL-deref panic in interrupt context

**File:** `sys/dev/sound/pci/aureal.c` · **Severity:** Low · **Bucket:** base:dev · **Confidence:** likely

## Root cause (path:line)

- `au->pch.channel` is only assigned in `auchan_init()` (`aureal.c:306-307`),
  which runs when `pcm_addchan()` (`aureal.c:653`) instantiates the play
  channel. Until then it is NULL (`au` is `M_ZERO`-allocated, `aureal.c:564`;
  `struct au_chinfo` embedded at `aureal.c:85`).
- The interrupt handler is live much earlier: `snd_setup_intr(..., au_intr,
  au, &ih)` at `aureal.c:620`.
- `au_intr()` (`aureal.c:396-433`) does, on `intsrc & AU_IRQ_PCMOUT`
  (`AU_IRQ_PCMOUT = 0x0020`, `aureal.h:56`):

```c
	if (intsrc & AU_IRQ_PCMOUT) {          /* aureal.c:411 */
		i = au_rd(...);
		chn_intr(au->pch.channel);     /* aureal.c:413 — NULL until :653 */
```

- `chn_intr()` (`sys/dev/sound/pcm/channel.c:683`) immediately evaluates
  `CHN_LOCKOWNED(c)` = `lockstatus((c)->lock, ...)` (`channel.h:312`) —
  unconditional dereference → **NULL-pointer write/panic in hardirq context**.

The window is real and interrupts are *enabled inside it*: `au_testirq()`
(`aureal.c:625`, body `528-537`) writes `AU_REG_IRQEN = 0x00001030`
(`aureal.c:531`) — bit 5 = `0x0020` = **AU_IRQ_PCMOUT enabled** — and
deliberately pokes the chip to raise an interrupt ("this apparently generates
an irq", `aureal.c:535`), followed by `DELAY(1000000)` — a full second of
window. `au_init()` (`aureal.c:627`) then keeps IRQs globally on
(`AU_REG_IRQGLOB |= AU_IRQ_ENABLE`, `aureal.c:505-506`) through
`AC97_CREATE`/`mixer_init`/`bus_dma_tag_create`/`pcm_register` until
`pcm_addchan` at `aureal.c:653`.

Any spurious PCMOUT interrupt in this ~1s+ window (misbehaving or crafted
device, shared-IRQ noise after `au_init` state changes) panics the kernel.
Normal healthy hardware only raises the test interrupt as
`AU_IRQ_UNKNOWN(0x1000)` (also enabled by 0x1030), which is why this does not
fire on well-behaved cards — hence Low/likely rather than certain.

## Verification

Hardware-gated (no AU8820 in QEMU). Source trace cross-checked against
`channel.c:683`/`channel.h:312` (no NULL guard in `chn_intr`) and the
`au_testirq` enable mask.

## Recommended fix

Guard the call: `if (au->pch.channel != NULL) chn_intr(au->pch.channel);`
(and ideally only enable AU_IRQ_PCMOUT after the channel exists). 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.
