{
  "finding_id": "DF-3880",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Source-certain use-after-free race in dsp_oss_syncstart (sys/dev/sound/pcm/dsp.c:2992-3082), the SNDCTL_DSP_SYNCSTART handler, triggerable by any unprivileged user on machines with a PCM sound device (/dev/dsp* 0666). The member-walk retry loop calls lksleep(sm, &snd_pcm_syncgroups_mtx, PCATCH, \"pcmsg\", 5ms) at dsp.c:3042-3043 when CHN_TRYLOCK(sm->ch) fails; lksleep DROPS the syncgroup lock while asleep, so a concurrent successful SYNCSTART of the same sg_id on another thread can complete the whole teardown - start every member, SLIST_REMOVE_HEAD + kfree() each sm and SLIST_REMOVE + kfree() the sg itself (dsp.c:3056-3069) - inside the 5ms window. The plain timeout wake (lksleep returns 0, no signal) executes needlocks = 1; ret = 0; (:3047-3048) and the inner SLIST_FOREACH then CONTINUES from the freed sm: SLIST_NEXT(sm, link) reads freed M_DEVBUF memory and CHN_TRYLOCK(sm->ch) loads and locks a channel pointer read out of freed memory - kernel UAF (panic or exploitable corruption via heap re-spray). Only the EINTR/ERESTART signal path breaks out safely. The trylock failure that forces the sleep is attacker-arranged by keeping the member channels lock contended (a looping/blocking write(2) on the same channel, as in the PoCs writer thread). Distinct from known DF-1263 (syncgroup error-path free without unlink - M_WAITOK-unreachable); this is the sleep-path lifetime bug on the START side. Kernel-path reproduction impossible on this guest: no audio PCI class, no hw.snd, no /dev/dsp* (env.txt), open() returns ENOENT (run.log) - hence not_reproduced; the PoC (100k re-armed iterations with two SYNCSTART racers + a lock-contention writer) is complete and would run verbatim on sound-equipped hardware. Confidence likely rather than certain only because the race window is timing-dependent; the code path mechanics are certain from source.",
  "exploit_chain": "unpriv user on sound-equipped box -> open /dev/dsp (0666) -> thread W loops write(2) on the fd (contends the member channel CHN lock) -> SNDCTL_DSP_SYNCGROUP (create group with that channel, dsp.c:2832-2977) -> thread T1: SNDCTL_DSP_SYNCSTART -> SG lock, walks members, CHN_TRYLOCK fails on the contended channel, releases earlier members, lksleep 5ms (drops SG lock, dsp.c:3034-3049) -> thread T2: SNDCTL_DSP_SYNCSTART same id -> SG lock free -> locks all members, starts them, kfrees all sm + sg (dsp.c:3056-3069) -> T1 5ms timeout fires, lksleep returns 0, walk resumes at freed sm -> SLIST_NEXT on freed chunk + CHN_TRYLOCK(freed->ch) -> UAF read / lock on wild pointer -> panic, or controlled corruption after M_DEVBUF re-spray (kmalloc-128-class grooming between teardown and wake).",
  "evidence": "run.log (open /dev/dsp ENOENT - device gate on this guest); VERDICT.md (annotated race timeline with dsp.c line refs, lksleep lock-drop semantics, teardown window, safe-EINTR vs buggy-timeout paths); syncstart_race.c (complete two-racer + contention-writer harness); env.txt (no PCM device); fix.diff (git-apply-clean: break the stale walk after any sleep, rescan from list head)",
  "kernel_refs": [
    "sys/dev/sound/pcm/dsp.c:3027",
    "sys/dev/sound/pcm/dsp.c:3042",
    "sys/dev/sound/pcm/dsp.c:3047",
    "sys/dev/sound/pcm/dsp.c:3050",
    "sys/dev/sound/pcm/dsp.c:3056",
    "sys/dev/sound/pcm/dsp.c:3068",
    "sys/dev/sound/pcm/dsp.c:2056"
  ],
  "poc_changes": "Authored from scratch (no seed). Two SYNCSTART racers re-armed with a fresh SYNCGROUP per iteration (the group is consumed by a successful start), plus a writer thread for deterministic CHN lock contention; documented device gate for this guest.",
  "attempts": 2,
  "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": 90,
  "guest_dirty": 0,
  "build_cmd": "vm.sh run_root cc -O2 -Wall -o /tmp/syncrace /tmp/syncstart_race.c -lpthread",
  "run_cmd": "vm.sh run_user /tmp/syncrace; echo exit=$? (/tmp cleaned)",
  "code_hash": "c70d2175db0be32f4b0fe652ff0409f243f570c179a61260c0b22511753e4f4c",
  "notes": "Pass-2 depth item (multi-call state machine / lock lifetime): SYNCGROUP->SYNCSTART interaction across threads. SG-before-CHN lock order is consistent across dsp.c (syncgroup :2850/:2862, syncstart :3001/:3028, dsp_close :765/:771) - no inversion found. Known DF-1263 not re-reported (M_WAITOK branch unreachable).",
  "recommended_fix": "After lksleep() returns in dsp_oss_syncstart, break out of the stale SLIST_FOREACH and let the do-while rescan the syncgroup list from the head (the lock was dropped during the sleep, so sg/sm may be freed)",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff adds the post-sleep break so the walk restarts from the live list head and is git-apply-clean against the read-only sys/ tree; a patched-kernel build cannot be exercised on this guest (no PCM device, the racing ioctls cannot run), so fix validation is not_testable here",
  "fix_evidence": "fix.diff; VERDICT.md; env.txt (hardware gate)"
}