DF-5253 / verdict.json
{ "finding_id": "DF-5253", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "REPRODUCED on the QEMU guest with an emulated USB audio device (QEMU -device usb-audio on piix3-uhci): uaudio_mixer_sysctl_handler() (sys/bus/u4b/audio/uaudio.c:2736) drops sc->sc_mixer_lock, sleeps in sysctl_handle_int() crossing user memory, then re-reads the field and lockmgr()s it; a USB audio detach racing that window runs mixer_uninit() -> uaudio_mixer_uninit_sub() (sc_mixer_lock = NULL, uaudio.c:5385) and snd_mtxfree() (mixer.c:811) BEFORE the sysctl OIDs are unregistered (device_sysctl_fini runs after driver detach, subr_bus.c:234-240), so the handler executes lockmgr(NULL) -> Fatal trap 12, Stopped at lockmgr_release+0x11: movq 0x8(%rdi),%rsi (stock kernel, root sysctl-write hammer, <=10 device_del cycles; instrumented stock driver separately logged RACE HIT: handler reached 2nd lockmgr after teardown (pmc=..., chan=1) in 8 cycles). Reachability is limited: the second lockmgr needs the sysctl WRITE path which is privilege-gated (caps_priv_check SYSCAP_NOSYSCTL_WR, kern_sysctl.c:1446), so unprivileged hammers never traversed it in 100+ cycles; severity is Low (privileged writer racing unplug). fix.diff (uaudio-owned mixer sysctl ctx freed in uaudio_detach BEFORE bus_generic_detach, draining in-flight handlers via the sysctllock, + defensive NULL re-check in the handler) validated: 25 cycles under the same root hammer = zero panics vs stock panic in <=10.", "exploit_chain": "", "evidence": "panic.txt (stock-kernel Fatal trap 12 ... lockmgr_release+0x11 + instrumented DF5253: RACE HIT line); VERDICT.md (full chain path:line); fix.diff (validated); run.sh/cycle.py (exact reproduction); env.txt (guest uname)", "kernel_refs": [ "sys/bus/u4b/audio/uaudio.c:2736", "sys/bus/u4b/audio/uaudio.c:2748", "sys/bus/u4b/audio/uaudio.c:2764", "sys/bus/u4b/audio/uaudio.c:2772", "sys/bus/u4b/audio/uaudio.c:5385", "sys/bus/u4b/audio/uaudio.c:1214", "sys/dev/sound/pcm/mixer.c:809", "sys/dev/sound/pcm/mixer.c:811", "sys/kern/subr_bus.c:238", "sys/kern/kern_sysctl.c:1446" ], "poc_changes": "Original concept (CLI sysctl -w hammer) replaced by in-process sysctlbyname read+write loop (hammer.c); discovered en route that unprivileged writes are EPERM-gated before the handler, so the decisive runs execute the hammer as root; QEMU usb-audio device attached via QEMU_EXTRA/piix3-uhci; device cycling driven from the host via the QEMU monitor (cycle.py).", "attempts": 4, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 7800, "guest_dirty": 0, "build_cmd": "cc -O2 -o /root/hammerc hammer.c (guest); cd /usr/src/sys/bus/u4b/audio && make (uaudio.ko for instrumented/fix builds)", "run_cmd": "for i in 1..8: nohup /root/hammerc & ; host: python3 cycle.py 10", "code_hash": "93354a6f5371aed50a81d77089b3568bbb576e8f4b2583f226912ebcc579533c", "notes": "Side observation (out of scope, different subsystem, root-triggered): one run of kldunload uaudio panicked in sndstat_sysuninit -> sbuf_delete (sbuf_delete called with uninitialized or corrupt sbuf) via linker_file_unload - sound.ko teardown bug worth a separate ticket. Guest restored via vm.sh reset with-src afterwards (guest_dirty=0). USB emulation worked via QEMU 7.2 -device usb-audio with -audiodev driver=none on piix3-uhci (xHCI root-port attach of the FS device failed to enumerate in the guest).", "recommended_fix": "Give uaudio its own sysctl_ctx_list for the mixer control OIDs and free it in uaudio_detach() before bus_generic_detach() (drains in-flight handlers via the sysctllock before mixer_uninit frees the lock), plus a defensive NULL re-check of sc_mixer_lock before the handlers second lockmgr.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Baseline stock kernel panicked in <=10 device cycles under the root sysctl-write hammer (Fatal trap 12 in lockmgr_release, fault VA 0x8). After applying fix.diff to the guest /usr/src, rebuilding uaudio.ko, installing and rebooting: 25 identical cycles under the same hammer produced ZERO panics (25x pcm0: detached completed, guest stayed healthy, mixer sysctls functional after each replug). Fix closes the window by removing the OIDs (draining handlers under the sysctllock) before the PCM/mixer teardown that frees the lock.", "fix_evidence": "VERDICT.md steps 6-7; run.log (baseline panic + patched 25-cycle clean run summary); fix.diff" } |