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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4725 Β· 4 files
FileTypeDescriptionSize
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.

VERDICT.md
↓ download raw

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.

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_testable
baseline no→ patch + rebuild →patched clean

Fix 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.
↓ fix.diffper-fix-DF-4725

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.