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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4550 Β· 6 files
FileTypeDescriptionSize
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.md
↓ download raw

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

not_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
↓ fix.diffper-fix-DF-4550

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