DF-5605 / verdict.json
{ "finding_id": "DF-5605", "status": "reproduced", "reproduced": true, "impact": "none", "confidence": "certain", "verdict": "The reentrancy decision in ua_mixer_set() (uaudio_pcm.c:139) and ua_mixer_setrecsrc() (uaudio_pcm.c:159) uses lockowned(), which on DragonFly returns true for a lock held shared by ANY thread (kern_lock.c:1365, We can only guess re: shared locks), so under a foreign-shared holder the calling thread concludes it already owns the lock and runs uaudio_mixer_set()/uaudio_mixer_setrecsrc() with zero exclusion. A production-API KLD harness replaying the exact decision shape proved the divergence deterministically (P3: lockowned=1 while lockstatus(curthread)=LK_SHARED -> do_unlock=0, 3/3 runs), and a fixed-decision twin using the precise lockstatus(...)==LK_EXCLUSIVE check (the same check the sound core itself uses at mixer.c:273/346) blocks behind the shared holder and acquires properly. Impact is none TODAY because every in-tree acquisition of the mixer lock is LK_EXCLUSIVE (zero LK_SHARED under sys/dev/sound; sole external consumer uaudio.c:5359 takes it exclusively at 2753/2772/3019) - filed as Info hardening of a latent protocol hole with a two-line fix, validated to compile against the real driver.", "exploit_chain": "", "evidence": "run.log/run.2.log/run.3.log decisive line DF5605 P3-foreign-SHARED: lockowned=1 lockstatus=1 ... do_unlock=0 (runs uaudio_mixer_set with NO lock held); fix_run.log DF5605FIX P3-foreign-SHARED: ... do_unlock=1 (took 200 ticks); fix_build.log (patched uaudio_pcm.c compiles -Werror clean into uaudio.ko); code-reading.txt (no shared holders in-tree)", "kernel_refs": [ "sys/bus/u4b/audio/uaudio_pcm.c:139", "sys/bus/u4b/audio/uaudio_pcm.c:159", "sys/kern/kern_lock.c:1365", "sys/dev/sound/pcm/mixer.c:273", "sys/dev/sound/pcm/mixer.c:346", "sys/dev/sound/pcm/sound.c:92", "sys/bus/u4b/audio/uaudio.c:5359" ], "poc_changes": "Authored the harness from scratch (no seed): replicated the uaudio_pcm.c:136-148 decision shape verbatim, lock created with snd_mtxcreates exact flags (lockinit LK_CANRECURSE), foreign-shared holder via kthread_create+LK_SHARED+tsleep. Fixed-dance twin authored for fix validation. During fix-diff application, an interactive patch session half-applied a hand-authored diff to the guest tree; regenerated fix.diff mechanically (diff -u) and restored the pristine file before the recorded clean apply+build.", "attempts": 3, "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": 420, "guest_dirty": 1, "build_cmd": "sh build.sh (in-tree: mkdir /usr/src/sys/modules/df5605_demo; cc via bsd.kmod.mk -> /usr/obj/.../df5605_demo.ko)", "run_cmd": "sh run.sh (kldload df5605_demo.ko; sleep 8; kldunload; dmesg | grep DF5605)", "code_hash": "66759566761cd9fc3e7302a91c91582299575355a2fc9f8e033e52bc7df1ac0a", "notes": "Info/latent: no in-tree manifestation (mixer lock never taken shared; grep-proven). Becomes live if any future reader-side shared acquisition of m->lock is added. FreeBSDs mtx_owned() is exact, so this is a DFly-specific porting divergence. Guest /usr/src was modified during fix compile-validation; guest reset with-src performed before returning.", "recommended_fix": "Replace lockowned(lock) with lockstatus(lock, curthread) == LK_EXCLUSIVE in ua_mixer_set() and ua_mixer_setrecsrc() (uaudio_pcm.c:139/159), matching the precise check the sound(4) core uses for the identical decision at mixer.c:273/346.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fix.diff (both hunks at uaudio_pcm.c:136/156) applied to the guests pristine driver and compiled clean with -Werror into uaudio.ko (fix_build.log). Decision-shape runtime validation via lockowned_demo_fixed.c: in the identical foreign-shared setup the fixed dance blocks behind the holder (200 ticks) and acquires exclusively - the bad do_unlock=0 decision is gone (fix_run.log). Driver-path runtime test impossible on this guest (no USB audio hardware); module-level validation is the strongest available evidence class per the family standard.", "fix_evidence": "fix_build.log (clean -Werror build of patched uaudio_pcm.c); fix_run.log (DF5605FIX P3: do_unlock=1, took 200 ticks)" } |