β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4727

aureal: au_intr calls chn_intr(au->pch.channel) while the channel is NULL β€” NULL-deref panic in the snd_setup_intr-to-pcm_addchan window that au_testirq deliberately enables IRQs inside

Summary

pch.channel is NULL until pcm_addchan runs auchan_init, but au_intr is live from snd_setup_intr and au_testirq enables AU_IRQ_PCMOUT plus raises a test interrupt with DELAY(1s) - on PCMOUT, chn_intr derefs NULL. Misbehaving/crafted AU8820 hardware; healthy cards raise the test irq as UNKNOWN. NULL-guard + enable-after-addchan fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4727 Β· 4 files
FileTypeDescriptionSize
README.md β€” 604 B ↓ raw
VERDICT.md β€” 2.8 KB ↓ raw
fix.diff β€” 723 B view raw
verdict.json β€” 1.9 KB view raw

DF-4727 β€” PoC evidence pack

Finding: chn_intr(au->pch.channel) with NULL channel in the attach window between snd_setup_intr (aureal.c:620) and pcm_addchan (:653); au_testirq enables AU_IRQ_PCMOUT inside that window β†’ NULL-deref panic.

Contents

  • VERDICT.md β€” path:line trace incl. chn_intr's unconditional lock deref.
  • verdict.json β€” machine verdict (status: untested; hw-gated).
  • fix.diff β€” NULL guard.

Reproduce / Expected

Requires the AU8820 card and a PCMOUT-sourced interrupt before the channel exists (spurious/crafted hardware). Not reproducible in QEMU.

VERDICT.md
↓ download raw

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):
    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.

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.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Fix not kernel-validated: requires physical AU8820 card and a spurious PCMOUT interrupt during attach.

fix.diff authored against read-only sys/.
↓ fix.diffper-fix-DF-4727

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md path:line trace; fix.diff

PoC changes

n/a

Verified recommended fix

NULL-guard chn_intr(au->pch.channel) in au_intr; enable PCMOUT irq only after pcm_addchan

Verdict

au_intr (aureal.c:396-433) calls chn_intr(au->pch.channel) at :413 whenever intsrc & AU_IRQ_PCMOUT, but au->pch.channel is NULL until pcm_addchan (aureal.c:653) -> auchan_init (:306) assigns it; the IRQ is live from snd_setup_intr (aureal.c:620) and au_testirq (:625, body :528-537) explicitly enables AU_IRQ_PCMOUT (IRQEN 0x1030 includes 0x20) and raises an interrupt, leaving >1s of enabled-IRQ window; chn_intr (channel.c:683) unconditionally does CHN_LOCKOWNED(c) = lockstatus(c->lock) (channel.h:312) -> NULL-deref panic in interrupt context. Healthy hardware raises the test irq as AU_IRQ_UNKNOWN so the window normally passes quietly β€” Low/likely, hw-gated, not reproducible in QEMU.