aureal: attach failure after mixer_init() leaves the live 0666 /dev/mixerN over the freed au softc β DF-4156 mixer-UAF family, 15th instance (premise live-verified on the guest)
Summary
mixer_init publishes the 0666 cdev holding codec->au as devinfo; bus_dma_tag_create and pcm_register can still fail and bad: frees au without mixer_uninit - and DF newbus never detaches a failed attach (premise LIVE-verified on the 6.5 guest with a make_dev-then-ENXIO KLD: node persisted 0666 and unpriv uid=1001 open reached module code). Any later mixer ioctl dispatches through freed softc (UAF r/w). 15th family instance; driver not in default builds. mixer_uninit-in-unwind fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4724 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.9 KB | β raw | |
| VERDICT.md | β | 4.1 KB | β raw | |
| premtest.c | β | 3.1 KB | view raw | |
| Makefile | β | 125 B | β download | |
| build_and_load.sh | β | 283 B | view raw | |
| build.log | β | 832 B | view raw | |
| run.log | β | 935 B | view raw | |
| dmesg_premtest.txt | β | 979 B | view raw | |
| env.txt | β | 205 B | view raw | |
| fix.diff | β | 1.3 KB | view raw | |
| verdict.json | β | 2.9 KB | view raw |
DF-4724 β PoC evidence pack
Finding: aureal attach failure after mixer_init() leaves live 0666 /dev/mixerN
over freed au β DF-4156 mixer-UAF family, 15th instance.
Contents
premtest.c+Makefile+build_and_load.shβ premise-verification KLD: a driver whose attach() does make_dev(0666) then returns ENXIO, exactly the aureal mixer_init-success + goto-bad shape. Probe only matches the unbound PIIX4 PM function (0x7113:8086) so it cannot hijack real devices.build.logβ full guest compiler output (successful KLD build).run.logβ decisive runtime output: attach failed, node persisted 0666, unprivileged open() reached module code, clean unload.dmesg_premtest.txt,env.txtβ guest kernel messages / environment.VERDICT.mdβ full narrative with path:line citations.verdict.jsonβ machine verdict (status: untested; hw-gated, premise verified).fix.diffβ git-apply-able fix (mixer_uninit on post-mixer failure paths); authored against the read-only sys/ tree, never applied there.
Reproduce
# on a DragonFly guest with /usr/src: make -C /tmp/premtest SYSDIR=/usr/src/sys # build kldload ./premtest.ko # attach runs, then FAILS ENXIO ls -l /dev/premtest* # node persists, crw-rw-rw- # as an unprivileged user: sh -c 'exec 3<>/dev/premtest0'; echo $? # -> 0 dmesg | tail # -> open() reached module code kldunload premtest # cleanup (real driver has none)
Expected
The /dev node survives the failed attach with 0666 perms and dispatches to
the module β in the real aureal driver those dispatches would dereference the
already-freed au softc (au_rdcd/au_wrcd β au_rd/au_wr via
au->st[]/au->sh[]), a UAF read/write. The physical AU8820 card required
for the end-to-end UAF is not present in QEMU; that part is code-verified only
(see VERDICT.md).
DF-4724 β aureal: attach failure after mixer_init() leaves live 0666 /dev/mixerN over freed au (mixer-UAF family, 15th instance)
File: sys/dev/sound/pci/aureal.c Β· Severity: Low Β· Bucket: memcorrupt Β· Confidence: certain
Family: DF-4156 / DF-4193 / DF-4299 / DF-4334 / DF-4344 / DF-4421 / DF-4457 / DF-4468 / DF-4504 / DF-4537 / DF-4550 / DF-4610 / DF-4651 (13 filed prior; this is the next instance of the same pattern in a driver the family sweep had not yet reached)
Root cause (path:line)
au_pci_attach() publishes the mixer before the last fallible steps and has no cleanup
for it on failure:
sys/dev/sound/pci/aureal.c:634βmixer_init(dev, ac97_getmixerclass(), codec)succeeds βmixer.c:make_dev(&mixer_ops, ..., UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit)creates a world-writable /dev/mixerN whose mixer object keepscodec(βau) as its devinfo.- Two later steps can still fail and
goto bad: sys/dev/sound/pci/aureal.c:636-645βbus_dma_tag_create(...) != 0sys/dev/sound/pci/aureal.c:651βpcm_register(dev, au, 1, 1)bad:(sys/dev/sound/pci/aureal.c:658-664) doesfree(au, M_DEVBUF)and releases bus resources β it never callsmixer_uninit(dev)/ac97_destroy(codec).
DragonFly newbus does not run device_detach() when attach returns an error
(sys/kern/subr_bus.c:2095-2117, device_doattach() β on error it only prints
"attach returned %d", clears the driver, and marks the device NOTPRESENT), so nothing
anywhere destroys the devfs node or the mixer object.
Impact
After such a failed attach, /dev/mixerN (mode 0666) stays registered forever. Any
unprivileged local user opening it and issuing a mixer ioctl dispatches through
au_rdcd()/au_wrcd() (aureal.c:126-169) with the freed au as arg:
au_wr/au_rd dereference au->st[mapno]/au->sh[mapno] (aureal.c:93-122) β freed,
heap-groomable kernel memory driving bus_space_{read,write} β a UAF read/write
primitive (plus the codec object itself is leaked dangling). Ceiling: kernel memory
corruption; floor: panic.
Preconditions (why Low, per family convention): an Aureal Vortex 8820 PCI card
(PCI ID 0x12eb:0x0001) must be present, the driver must be compiled in β note
aureal.c is not wired into any build file (sys/conf/files has no entry;
sys/dev/sound/driver/Makefile SUBDIR lacks it; no snd_aureal.ko ships in the
default build) β and one of the post-mixer_init allocations must fail
(kmem pressure). Not user-triggerable on demand.
Verification (what ran on the QEMU guest, 2026-09-23)
The full UAF cannot run in QEMU (no Aureal PCI device emulation). The load-bearing premise was verified live on DragonFly 6.5-DEVELOPMENT:
- Built a minimal KLD (
premtest.c) whose attach() doesmake_dev(..., 0666, ...)and then returns ENXIO β the exact shape ofmixer_init()-success followed bygoto bad. kldloadβ dmesg:PREMTEST: attach() ... FAIL ENXIO/device_probe_and_attach: premtest0 attach returned 6β attach failed./dev/premtest0persisted,crw-rw-rw- root wheel.- As unprivileged uid=1001:
exec 3<>/dev/premtest0β OPEN_RC=0, and the module's d_open handler executed (PREMTEST: open() reached module code) β i.e. an unprivileged user reaches module code that, in the real driver, dereferences the freed softc. - Unloaded; guest left clean.
Newbus premise additionally proven from source: sys/kern/subr_bus.c:2095-2117.
Recommended fix
On every failure path after mixer_init() succeeds, run mixer_uninit(dev) (which
destroys the cdev and the codec via ac97mix_uninitβac97_destroy) before freeing
au. See fix.diff. (First wire the driver into the build or retire it β see notes.)
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: the bug itself cannot be triggered on this guest (no Aureal PCI hardware), so no baseline panic/corruption exists to flip.
fix.diff authored against read-only sys/ after line-level verification; not applied to sys/.
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log (attach returned 6 + persistent crw-rw-rw- node + unpriv OPEN_RC=0 + 'open() reached module code'), VERDICT.md, dmesg_premtest.txt, build.log, premtest.c
PoC changes
n/a (premise KLD written fresh; no seed existed)
Verified recommended fix
Call mixer_uninit(dev) on every failure after mixer_init() succeeds; also unwind in correct order (teardown intr, release irq/regs, free au last)
Verdict
15th instance of the DF-4156 mixer-UAF family: au_pci_attach publishes the 0666 /dev/mixerN (mixer_init, aureal.c:634) before bus_dma_tag_create (aureal.c:636-645) and pcm_register (aureal.c:651) can still fail; the bad: unwind (aureal.c:658-664) frees au with no mixer_uninit, and DragonFly newbus never detaches a failed attach (subr_bus.c:2095-2117), so the node dangles into freed memory and any unprivileged user's mixer ioctl reaches au_rdcd/au_wrcd over the freed au (aureal.c:126-169, 93-122). End-to-end UAF not runnable in QEMU (no Aureal PCI device); the load-bearing premise WAS verified live on the 6.5-DEVELOPMENT guest with a make_dev-then-fail KLD: /dev node persisted 0666 after 'attach returned 6' and unprivileged uid=1001 open() reached module code (see run.log, dmesg_premtest.txt). Note aureal.c is not wired into any build file today (no sys/conf/files entry, not in sys/dev/sound/driver/Makefile SUBDIR, no snd_aureal.ko in default builds), further gating reachability.
No comments yet.