DragonFlyBSD Kernel Audit
DF-2729 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2729",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Reproduced on the stock INVARIANTS guest: with TDF_MIGRATING set on a thread homed on cpu1 (exactly the state a racing wakeup observes during the lwkt_setcpu_self() push window or the lwkt_giveaway()/lwkt_acquire() pull window), lwkt_schedule() panics at lwkt_thread.c:1293 'assertion \"(td->td_flags & TDF_MIGRATING) == 0\" failed in _lwkt_schedule'. The panic fired at the sender-side entry of the inlined _lwkt_schedule (cpuid=0); the wakeup-IPI re-entry on the old home cpu (lwkt_schedule_remote -> _lwkt_schedule) executes the identical inlined check. On stock kernels the same call falls through to _lwkt_enqueue(), whose TDF_MIGRATING guard at lwkt_thread.c:188 makes the schedule a safe no-op by design, and the migration completion path (lwkt_setcpu_remote / post-lwkt_acquire schedule) enqueues the thread. INVARIANTS builds only; no stock-kernel impact; no escalation primitive.",
  "exploit_chain": "",
  "evidence": [
    "panic.txt: 'panic: assertion \"(td->td_flags & TDF_MIGRATING) == 0\" failed in _lwkt_schedule at /usr/src/sys/kern/lwkt_thread.c:1293', 'cpuid = 0', trace df2728_mode_sysctl -> lwkt_schedule (x2, inlined _lwkt_schedule)",
    "VERDICT.md: derivation that _lwkt_enqueue()'s line-188 guard exists precisely for this state, making the assert contradict the designed handling",
    "sys/kern/lwkt_thread.c:188 (guard), :1293 (assert), :1562-1594 (push window), :1363-1420 (pull window)"
  ],
  "kernel_refs": [
    "sys/kern/lwkt_thread.c:1293",
    "sys/kern/lwkt_thread.c:188",
    "sys/kern/lwkt_thread.c:1562-1594",
    "sys/kern/lwkt_thread.c:862-868",
    "sys/kern/lwkt_thread.c:1363-1420",
    "sys/kern/lwkt_thread.c:1616-1629"
  ],
  "poc_changes": "Trigger authored from scratch (no seed PoC): mode 2 of the shared df2728.c KLD sets TDF_MIGRATING on a never-started cpu1-homed thread and calls lwkt_schedule() from cpu0 - deterministic simulation of the wakeup-races-migration state. Deterministic on first attempt.",
  "attempts": 1,
  "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": 300,
  "guest_dirty": 0,
  "build_cmd": "cd /tmp/df2728 && make obj && make",
  "run_cmd": "usched :1 kldload /usr/obj/tmp/df2728/df2728.ko && usched :1 sysctl -n debug.df2728=2",
  "code_hash": "03fe02857aec78f1a20c4fa82ee471de2fad6cc6db04d42cb46fc4240a10e2d5",
  "notes": "INVARIANTS-only panic (Low). In-tree usched protocols interlock their own scheduling so unprivileged userland cannot hit the race on a stock configuration; the assert forbids a state the core scheduler explicitly supports (foreign schedulers in KLDs, driver-held threads across migration). Guest reset with-src (clean) after verification.",
  "recommended_fix": "Remove the KKASSERT((td->td_flags & TDF_MIGRATING) == 0) from _lwkt_schedule() (lwkt_thread.c:1293); _lwkt_enqueue() already handles TDF_MIGRATING schedules as safe no-ops by design.",
  "fix_status": "not_testable",
  "fix_kernel_uname": "",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff removes the contradicting assert (git apply --check clean against sys/). Kernel rebuild validation not performed: Low / INVARIANTS-only finding with no stock-kernel effect; the designed no-op semantics are visible in the same source (_lwkt_enqueue line 188) and the shared module's control mode exercised the non-migrating remote schedule cleanly.",
  "fix_evidence": ["fix.diff (git-apply clean)", "sys/kern/lwkt_thread.c:188 guard implementing the designed semantics"]
}