als_pci_attach error path after mixer_init leaves a live 0666 /dev/mixerN pointing at freed sc β dangling mixer devinfo UAF on open/ioctl (DF-4156 family, 11th instance)
Summary
mixer_init publishes the 0666 mixer cdev holding devinfo=sc before pcm_register can fail; bad_attach kfrees sc while the cdev survives (failed newbus attach never runs detach). Any subsequent unpriv mixer ioctl dispatches alsmix_set/setrecsrc through the freed softc and drives bus-space I/O through stale handles over an already-released region. Family-calibrated severity; hardware-gated on guest. pcm_register-first + unregister-on-mixer-fail fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4550 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| mixer_uaf_exerciser.c | β | 1.6 KB | view raw | |
| guest_hw_evidence.txt | β | 480 B | view raw | |
| snd_unload_df4116_panic.txt | β | 2.2 KB | view raw | |
| fix.diff | β | 916 B | view raw | |
| VERDICT.md | β | 4.1 KB | β raw | |
| README.md | β | 1.3 KB | β raw |
DF-4550 β als4000: attach-failure path after mixer_init leaves a live 0666 /dev/mixerN over freed softc (mixer-UAF family, 11th instance)
File: sys/dev/sound/pci/als4000.c lines 842-863.
Build / Run
cc -o /tmp/mixer_uaf_exerciser mixer_uaf_exerciser.c /tmp/mixer_uaf_exerciser /dev/mixerN # only exists after an als4000 attach
Expected output (on real hardware, after a pcm_register() failure)
MIXER_WRITE ioctls succeed while reading/writing through the FREED sc
(use-after-free in alsmix_set β als4000.c:574-603 β reading stale
sc->st/sc->sh bus handles and RMW-ing freed heap); typically crashes or
corrupts once the slab is reused.
Guest result
Not reproducible in QEMU: no ALS4000 PCI device (ALS_PCI_ID0
0x40004005) exists in the guest β snd_als4000.ko loads but als_pci_attach
never runs (see guest_hw_evidence.txt). The dangling-/dev/mixerN trigger
(add the card + force pcm_register failure: pcm_veto_load set, unit >
PCMMAXUNIT, or ENOMEM inside pcm_register β sound.c:1021-1033) cannot be
constructed on this guest.
Note: kldunload snd_als4000 during exploration panicked the guest in
sndstat_sysuninit β that is the already-filed DF-4116 (sound.ko unload
bug), a different finding not re-reported here (see
snd_unload_df4116_panic.txt).
VERDICT β DF-4550
Status: not_reproduced (hardware-gated trigger). Impact: none on this guest; on real hardware the class is an unprivileged UAF (family precedent: DF-4156/4193/4299/4334/4344/4421/4457/4468/4504/4537, all filed Low).
Root cause (path:line)
als_pci_attach β sys/dev/sound/pci/als4000.c:808-864:
if (mixer_init(dev, &als_mixer_class, sc)) { // :842 <-- publishes mixer
device_printf(dev, "failed to initialize mixer\n");
goto bad_attach;
}
if (pcm_register(dev, sc, 1, 1)) { // :847 <-- can fail AFTER
device_printf(dev, "failed to register pcm entries\n");
goto bad_attach; // mixer is live
}
...
bad_attach:
als_resource_free(dev, sc); // :861
kfree(sc, M_DEVBUF); // :862 mixer->devinfo dangles
return ENXIO;
mixer_init() (sys/dev/sound/pcm/mixer.c:687-763) creates the snd_mixer with
m->devinfo = devinfo (= sc) at mixer.c:635, then publishes a
world-accessible device node β make_dev(&mixer_ops, ..., UID_ROOT,
GID_WHEEL, 0666, "mixer%d", unit) at mixer.c:730-732 with
pdev->si_drv1 = m. On pcm_register() failure (sound.c:1021-1025
pcm_veto_load β EINVAL; :1027-1033 unit > PCMMAXUNIT β ENODEV; or ENOMEM
inside pcm_register), bad_attach frees sc (als4000.c:862) but never
unregisters the mixer: a failed newbus attach does not run detach, so
/dev/mixerN survives with m->devinfo pointing into freed M_DEVBUF memory.
Any subsequent open/ioctl (0666 β unprivileged) on that node reaches
mixer_set β MIXER_SET β alsmix_set (als4000.c:574-603), which calls
mix_getdevinfo(m) β freed sc, then als_mix_rd/sc, ... /
als_mix_wr(sc, ...) (als4000.c:133-145) dereferencing the stale
sc->st/sc->sh β UAF reads and RMW writes through freed heap (plus actual
I/O port writes to a bus_space region that als_resource_free already
released, als4000.c:741-744). alsmix_setrecsrc (als4000.c:605-626) is the
same via SOUND_MIXER_WRITE_RECSRC. Same defect shape as the ten filed family
instances.
Why not reproduced
The QEMU guest has no Avance Logic ALS4000 PCI device
(ALS_PCI_ID0 0x40004005, als4000.h:29 β guest_hw_evidence.txt: pciconf has
no vendor 4005; kldload snd_als4000 succeeds but the driver never probes,
so neither mixer_init nor pcm_register ever runs). No QEMU device model
exists for this card; constructing the trigger additionally requires the
attach-time pcm_register failure. Confidence certain is by code inspection
(the family defect was previously verified in-tree for sibling drivers and
the framework side is identical here).
Exploration note (guest crash β separate, already-filed finding)
During exploration kldunload snd_als4000 (which cascades the sound.ko
unload) panicked the guest:
panic: sbuf_delete called with uninitialized or corrupt sbuf sbuf_delete() at sbuf_delete+0x1b sndstat_sysuninit() at sndstat_sysuninit+0x8c linker_file_unload() at ...
This is the already-filed DF-4116 (sys/dev/sound/pcm/sndstat.c), not
re-reported here; the panic log is preserved as
snd_unload_df4116_panic.txt. Guest was reset clean (vm.sh reset with-src)
afterwards.
Exploit chain
(on real hardware) add ALS4000 card β induce pcm_register failure during
attach (e.g., raise unit count past hw.snd.maxunit/PCMMAXUNIT with many sound
cards, or pcm_veto_load from a failed sound init) β 0666 /dev/mixerN left
over freed softc β unprivileged MIXER_WRITE hammers freed M_DEVBUF slab β
heap groom β als_mix_wr writes attacker-influenced bytes to I/O ports via
stale handles and RMW's freed memory (family impact ceiling; gated behind
rare attach failure, hence Low).
Fix validation
not_testable (no reproduced corruption; no hardware).
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_testablenot_testable: no ALS4000 hardware in guest; fix.diff (reorder + pcm_unregister on later failure) is the standard family remedy, line-accurate against als4000.c:839-863.
fix.diff
Confirmed kernel references
Detail
Exploit chain
real hw: insert ALS4000 + induce pcm_register failure at attach -> surviving 0666 /dev/mixerN over freed sc -> unprivileged MIXER_WRITE loop -> UAF read/RMW-write of freed M_DEVBUF slab via als_mix_rd/als_mix_wr and stale bus_space handles
Evidence (decisive lines)
VERDICT.md (root cause with mixer.c/sound.c line refs); guest_hw_evidence.txt (no vendor 4005 device; module loads, never attaches); mixer_uaf_exerciser.c (the post-trigger exerciser); snd_unload_df4116_panic.txt (unrelated DF-4116 crash observed during exploration)
PoC changes
No seed existed; authored the post-trigger exerciser. It cannot run without the card, which is the documented reason for not_reproduced.
Verified recommended fix
Reorder mixer_init after successful pcm_register and pcm_unregister(dev) on any later failure before freeing sc.
Verdict
Certain by code inspection, hardware-gated in execution: als_pci_attach calls mixer_init (als4000.c:842) which publishes a 0666 /dev/mixerN holding devinfo=sc (mixer.c:635,730-732), then pcm_register (als4000.c:847) can fail (sound.c:1021-1033 paths / ENOMEM) and bad_attach kfrees sc (als4000.c:862) without tearing down the mixer β dangling cdev over freed heap, unprivileged UAF via alsmix_set/alsmix_setrecsrc. Not reproducible on the QEMU guest: no ALS4000 PCI device (guest_hw_evidence.txt), driver never attaches. 11th instance of the filed mixer-UAF family (severity calibrated to Low like all family members).
No comments yet.