ess_attach() pcm_register-failure unwind kfrees sc while the 0666 /dev/mixerN that mixer_init() published survives β dangling mixer devinfo UAF on open/ioctl (DF-4156 family, 8th instance)
Summary
mixer_init at :1045 publishes the 0666 /dev/mixerN with devinfo == sc; if pcm_register at :1052 fails, the no: unwind frees sc without mixer_uninit (newbus never runs detach for a failed attach). Every subsequent unpriv open+ioctl dispatches through the freed softc including port I/O via bus-space pointers read from freed heap. Trigger = half-failed attach on ESS Solo-1 hardware (absent on guest - inconclusive, family-consistent). mixer_uninit-in-unwind fix (EBADF-safe).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4468 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| trigger.c | β | 2.7 KB | view raw | |
| build.sh | β | 81 B | view raw | |
| run.sh | β | 102 B | view raw | |
| build.log | β | 198 B | view raw | |
| run.log | β | 157 B | view raw | |
| env.txt | β | 411 B | view raw | |
| VERDICT.md | β | 3.5 KB | β raw | |
| fix.diff | β | 477 B | view raw |
DF-4468 VERDICT β snd_solo dangling /dev/mixerN after failed attach (8th family instance)
Status: INCONCLUSIVE (code-proven; not exercisable on this guest)
The audit guest has no ESS Solo-1 PCI function (QEMU emulates es1370, not
ES1938/ES1946), and the failure precondition (pcm_register() failing after
mixer_init() succeeded) requires either a feeder-subsystem veto flag or
PCMMAXUNIT sound units β neither injectable at runtime on stock hardware. Same verification posture as family instances DF-4421 (ich) and DF-4457 (cmi).
Root cause (path:line)
sys/dev/sound/pci/solo.c:1045βmixer_init(dev, &solomixer_class, sc)is called BEFOREpcm_register(line 1052).sys/dev/sound/pcm/mixer.c:730-733βmixer_init()immediately doesmake_dev(&mixer_ops, ..., 0666, "mixer%d", unit)and storespdev->si_drv1 = m; snddev->mixer_dev = pdev;where the kobj mixermkeepsm->devinfo = sc(mixer.c:616-649,mixer_obj_create).sys/dev/sound/pci/solo.c:1052-1053β ifpcm_register(dev, sc, 1, 1)fails,goto norunsess_release_resources(sc, dev).sys/dev/sound/pci/solo.c:878βkfree(sc, M_DEVBUF). Nomixer_uninit()runs: the only caller ofmixer_uninitispcm_unregister(sound.c:1205), which newbus never invokes for a failed attach.- Result:
/dev/mixerNremains a registered world-writable cdev whose kobj devinfo points into freed memory. Firstopen()+ioctl()by any local user reachesessmix_init/essmix_set/essmix_setrecsrc(solo.c:651/668/728) βmix_getdevinfo(m)(mixer.c:616) returns the freedscβess_setmixer()(solo.c:241) readssc->sb(astruct resource *) from freed heap and performs port I/O viarman_get_bustag(sc->sb). UAF-read β forged bus_space handle β out-of-bounds port I/O; realistic outcome is kernel fault / DoS, with heap-grooming dependent potential for worse.
Why pcm_register can fail (solo.c:1052)
sound.c:1021-1025βpcm_veto_loadset (feeder subsystem error at boot, sound.c:50 / feeder.c:126).sound.c:1027-1033β device unit > PCMMAXUNIT.
Both are operator/boot dependent; not attacker-triggerable on demand β hence Low severity, consistent with the 7 filed family instances.
Fix
Match the family fix: unwind the mixer before freeing resources β
--- a/sys/dev/sound/pci/solo.c
+++ b/sys/dev/sound/pci/solo.c
@@ -1049,6 +1049,8 @@ ess_attach(device_t dev)
rman_get_start(sc->io), rman_get_start(sc->sb), rman_get_start(sc->vc),
rman_get_start(sc->irq),PCM_KLDSTRING(snd_solo));
+ sc->mixer_ok = 1; /* mark: mixer_init() succeeded */
+
if (pcm_register(dev, sc, 1, 1))
goto no;
@@ -1060,6 +1062,9 @@ ess_attach(device_t dev)
no:
+ if (sc->mixer_ok)
+ mixer_uninit(dev);
ess_release_resources(sc, dev);
return ENXIO;
}
(plus int mixer_ok; in struct ess_info). The systemic fix is moving the
mixer_init() call after pcm_register()+pcm_addchan() success across the
whole sound family, or making pcm_register failure paths call
mixer_uninit.
Attempts
- Guest run of
./trigger /dev/mixer0β ENOENT (no ESS hw): run.log. - Code-level trace completed as above; no false-positive indicators.
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 validated on guest (finding itself not guest-reproducible: no ESS hw, failure precondition not injectable); fix.diff is the code-level unwind correction matching the family fix pattern
findings/poc/DF-4468/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (path:line proof), trigger.c (family-standard mixer ioctl UAF trigger), run.log (guest ENOENT), fix.diff (mixer_uninit on the `no:` unwind - safe for pre-mixer paths since mixer_uninit returns EBADF with no mixer registered)
PoC changes
none (family-standard trigger; seed sketch replaced with complete trigger.c + full precondition analysis)
Verified recommended fix
Call mixer_uninit(dev) on the ess_attach no: unwind before ess_release_resources() frees sc.
Verdict
8th instance of the dangling-/dev/mixerN family: ess_attach() calls mixer_init() (solo.c:1045) which immediately publishes a 0666 /dev/mixerN cdev holding devinfo=sc (mixer.c:730-733); the only post-mixer failure path, pcm_register() failing (solo.c:1052), jumps to no: which kfrees sc (solo.c:878) without mixer_uninit() (only ever called from pcm_unregister, sound.c:1205, which newbus never runs for a failed attach). First open()+SOUND_MIXER_*_VOLUME ioctl by any local user then executes essmix_set/ess_setmixer through the freed softc (solo.c:667/241) including port I/O via pointers read from freed heap. Not reproducible on the audit guest: QEMU does not emulate ES1938/1946 (only es1370) so snd_solo never attaches, and the pcm_register failure precondition (veto-load flag or unit>PCMMAXUNIT) is not runtime-injectable. Code-level trace complete; PoC builds and runs on the guest (ENOENT), same verification posture as family instances DF-4421/DF-4457.
No comments yet.