{
 "finding_id": "DF-2873",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "dos",
 "confidence": "certain",
 "verdict": "Lost-wakeup race in taskqueue_drain()/drain_simple() reproduced by hammering: taskqueue_run() executes 'tq_running = NULL; wakeup(task);' OUTSIDE the queue spinlock (subr_taskqueue.c:411-412) while the drainer checks 'ta_pending != 0 || task == tq_running' under the spinlock (:493/:512) and then parks via ssleep() - because the waker never takes the spinlock, its wakeup can land between the drainer's check and its sleep-queue interlock enqueue (kern_synch.c _tsleep_interlock called from ssleep at :821) and is lost forever. Guest proof: 4 hammer threads loop enqueue+drain on 4 tasks of a 1-worker queue for ~3 minutes; watchdog reports 'LOST WAKEUP REPRODUCED: hammer 3 frozen (h3 15165->15165) with ta_pending=0 and task not running' and ps -axH shows lt_h3 permanently asleep on wchan '-' (the drain wmesg). A frozen drainer never returns - on a teardown path this is a permanent kernel-thread hang, reachable on ordinary busy queues without any taskqueue_free() (unlike DF-2870). Contrast: taskqueue_thread_enqueue (:629-642) is entered WITH the lock held, so its unlock->wakeup_one is interlock-ordered and that path cannot lose wakeups. Attempt 1 (2 hammers, 90 s) did not hit - window is tens of nanoseconds. fix.diff (runner clears per-task TASKQ_RUNNING under TQ_LOCK, wakeup after unlock; sleeper checks the flag under the same lock) validated by bounded negative re-run (4x4 hammer, 3 min): not hit, no frozen hammers.",
 "exploit_chain": "",
 "evidence": [
  "run.log: 'LOST WAKEUP REPRODUCED: hammer 3 frozen (h3 15165->15165) with ta_pending=0 and task not running'",
  "run.log ps: 'B2 - lt_h3' (permanently parked in drain)",
  "run.fixed.log: 'not hit in ~90s' + NO-FROZEN-HAMMERS + clean unload"
 ],
 "kernel_refs": [
  "sys/kern/subr_taskqueue.c:411",
  "sys/kern/subr_taskqueue.c:412",
  "sys/kern/subr_taskqueue.c:493",
  "sys/kern/subr_taskqueue.c:512",
  "sys/kern/subr_taskqueue.c:516",
  "sys/kern/kern_synch.c:821"
 ],
 "poc_changes": "watchdog loop condition originally used '!hit_thr' with hit_thr=-1 (no-op loop) - fixed to explicit 0/1/2 states before the recorded runs; first attempt (2 hammers/90 s) missed the window, second (4 tasks x 4 hammers/3 min) hit",
 "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": 6900,
 "guest_dirty": 0,
 "build_cmd": "cd /root/poc/tqlost && make -m /usr/share/mk SYSDIR=/usr/src/sys (see build.sh)",
 "run_cmd": "kldload /root/poc/tqlost/tqlost.ko; sleep 175; dmesg | grep tqlost; ps -axH -o stat,wchan,comm | grep lt_h (see run.sh)",
 "code_hash": "16d25065f58053efac9d1bae9716f02fff822de92ad5c6b3145086ad984f7228",
 "fix_status": "fixed",
 "fix_kernel_uname": "DragonFly 6.5-DEVELOPMENT #1: Wed Sep  2 17:34:00 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "Combined fix.diff (per-task TASKQ_RUNNING under TQ_LOCK + wakeup after unlock in taskqueue_run; ACTIVE re-check before worker park; tq_callouts wait in taskqueue_free; timeout_func freer wakeup) built as kernel #1 Wed Sep 2 17:34:00. Baseline bad behavior GONE on every PoC: DF-2869 cancel=EBUSY + drain blocks + no UAF/panic + clean unload; DF-2870 taskqueue_free returns, no wedged threads; DF-2872 timeout task no longer runs after free; DF-2873 hammer does not lose a wakeup (bounded negative). Guest left clean via vm.sh reset with-src.",
 "fix_evidence": [
  "run.fixed.log"
 ],
 "notes": "fixed-kernel validation is a bounded negative (race absence cannot be proven, only the interlock ordering argument in fix.diff + failure to hit under the same hammer that hit on stock)",
 "recommended_fix": "Same discipline as DF-2869: clear the running-state under the queue spinlock and issue wakeup(task) only after unlocking, so the sleeper's check-then-interlock (ssleep) is fully ordered against the waker."
}