DF-2729 / verdict.json
{ "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"] } |