aureal: bad: unwind frees au BEFORE bus_teardown_intr (live IRQ handler over freed softc β UAF write in au_intr) and releases NULL reg[] entries after a mid-list BAR failure (NULL-deref panic)
Summary
The unwind frees au while au_intr is still registered (IRQs enabled by au_testirq and au_init) - an interrupt in the window writes au->interrupts++ and does bus_space IO through freed memory. Separately the BAR loop advances j on failed allocations after earlier success, so the unwind can release NULL. DF-1506-class ordering bug. Reorder-the-unwind fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4725 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 735 B | β raw | |
| VERDICT.md | β | 3.4 KB | β raw | |
| fix.diff | β | 1.2 KB | view raw | |
| verdict.json | β | 2.0 KB | view raw |
DF-4725 β PoC evidence pack
Finding: aureal attach bad: unwind frees au before bus_teardown_intr
(live au_intr over freed softc β UAF write in interrupt context) and can
hand NULL reg[] entries to bus_release_resource (NULL-deref panic).
Contents
VERDICT.mdβ full narrative with path:line citations.verdict.jsonβ machine verdict (status: untested; hw-gated).fix.diffβ reorder unwind + NULL-guard +if (reg[j]) j++.
Reproduce / Expected
Not runnable in QEMU: requires an Aureal Vortex AU8820 PCI card whose attach
fails after snd_setup_intr succeeded. Static trace in VERDICT.md.
See DF-4724's run.log for the same newbus attach-failure semantics verified
live on the guest.
DF-4725 β aureal: attach bad: unwind frees au while the IRQ handler is still live (UAF write in au_intr) and releases NULL reg[] entries
File: sys/dev/sound/pci/aureal.c Β· Severity: Low Β· Bucket: memcorrupt Β· Confidence: certain
Root cause (path:line)
The unwind block is ordered and guarded wrongly:
bad: /* aureal.c:658 */
if (au) free(au, M_DEVBUF); /* 659 β FIRST! */
for (i = 0; i < j; i++)
bus_release_resource(dev, type[i], regid[i], reg[i]); /* 660-661 */
if (ih) bus_teardown_intr(dev, irq, ih); /* 662 β AFTER free */
if (irq) bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
return ENXIO;
(a) live IRQ handler over freed softc
snd_setup_intr(dev, irq, 0, au_intr, au, &ih) at aureal.c:620 installs
au_intr(void *p) with p = au. Interrupts are already enabled at that point:
au_testirq() (aureal.c:528-537, called at aureal.c:625) writes
AU_REG_IRQEN = 0x00001030, and au_init() (aureal.c:505-506) sets
AU_REG_IRQGLOB |= AU_IRQ_ENABLE. Every later failure path
(au_init fail :627, AC97_CREATE fail :633, mixer_init fail :634,
bus_dma_tag_create fail :644, pcm_register fail :651) runs bad:,
which frees au before bus_teardown_intr. In the window between the
free and the teardown, a level-triggered/shared PCI interrupt dispatches
au_intr(au) β au->interrupts++ (aureal.c:401) is a write into freed
heap, and au_rd(au, ...) (aureal.c:402) reads bus-space tags/handles
(au->st[]/au->sh[]) from freed, reallocatable memory β UAF write/read in
hard-interrupt context. Correct order: teardown intr β release irq β release
mems β free au last.
(b) NULL reg[i] handed to bus_release_resource
The BAR loop (aureal.c:571-605) increments j whenever any earlier BAR
mapped, even when the current BAR failed both allocations:
if (reg[j]) { au->st[i] = ...; mapped++; } /* 591-595 */
if (mapped) j++; /* 599 β runs even if reg[j]==NULL */
So BAR k failing after BAR 0..k-1 succeeded leaves reg[j] == NULL inside the
0..j-1 range that bad: unconditionally releases at aureal.c:661
(bus_release_resource(dev, type[i], regid[i], NULL) β NULL-deref panic in
rman).
Impact
Both require the AU8820 card and an attach failure, hence Low: kernel UAF write/read in interrupt context (a) or immediate NULL-deref panic (b). (driver additionally not wired into any default build β see DF-4724 notes.)
Verification
Hardware-gated (no Aureal PCI emulation in QEMU) β source-trace only.
Ordering semantics cross-checked against sys/kern/subr_bus.c
(bus_teardown_intr must precede the resource free that unmaps the handler's
target) and the DF-1506 (emu10kx) precedent for dangling-IRQ-on-attach-failure.
Recommended fix
Rewrite bad: in the canonical order (teardown intr β release irq β release
regs, skipping NULL β destroy mixer/codec if live β free au last). The
if (mapped) j++ must become if (reg[j]) j++; (or only track non-NULL
entries). 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_testableFix not kernel-validated: bug requires physical AU8820 hardware and an attach failure; not reproducible on the QEMU guest.
fix.diff authored against read-only sys/; ordering semantics checked against subr_bus.c teardown requirements.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md with path:line trace; fix.diff
PoC changes
n/a (no runtime PoC possible without the card)
Verified recommended fix
Unwind in order: teardown intr, release irq, release non-NULL regs, free au last; count j only for mapped BARs
Verdict
au_pci_attach's bad: unwind (aureal.c:658-664) frees au at :659 while au_intr is still registered (snd_setup_intr at :620; IRQs enabled by au_testirq :528-537 / au_init :505) until bus_teardown_intr at :662 β any interrupt in that window writes au->interrupts++ and does bus_space IO through the freed softc (UAF in hardirq context). Additionally the BAR loop's if (mapped) j++ at :599 advances j past allocations that failed after any earlier success, so :661 releases NULL reg[] entries -> NULL-deref panic in rman. Hardware-gated (AU8820 PCI card + attach failure); not runnable in QEMU; source-trace verified.
No comments yet.