DF-2928 / verdict.json
{ "finding_id": "DF-2928", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "The INVARIANTS test hook debug.spin_lock_test=1 sets the write-only static spin_lock_test_mode (kern_spinlock.c:91,420,424 โ no reader exists in sys/), while indefinite_check() honors only kern_lock.c's lock_test_mode (indefinite2.h:171-176); the deliberate recursive spin_lock therefore never breaks and hits the unconditional 60-second panic at indefinite2.h:183-186. Reproduced three times on the stock INVARIANTS guest: msgbuf shows the wait running unbroken 1..57+ secs with the handler's backtrace (sysctl_spin_lock_test+0x233), guest dies at exactly T0+60s. Unprivileged writes are denied by caps_priv_check_self(SYSCAP_RESTRICTEDROOT) (kern_spinlock.c:409, verified live), so impact is a root-gated kernel panic/DoS of debug kernels โ severity Low. Not fixed upstream (checked master 2026-09-03).", "exploit_chain": "", "evidence": [ "run.log: T0+22s msgbuf โ 'indefinite wait (1..18 secs)!' accumulating, handler backtrace, no break despite spin_lock_test_mode=1 being set at T0", "run.2.log: T0+57s msgbuf '(57 secs)!' then vm.sh status=down at T0+~80s (panic at T0+60s)", "run.3.log: two independent earlier runs dying at T0+60s; vm.sh 'likely DDB on panic'", "panic.txt: source-determined panic string 'panic: spin_lock_ex: sysctl_spin_lock_test, indefinite wait!' + full path", "env.txt: guest uname, INVARIANTS kernel, sysctl defaults, unpriv denial" ], "kernel_refs": [ "sys/kern/kern_spinlock.c:91", "sys/kern/kern_spinlock.c:409", "sys/kern/kern_spinlock.c:417", "sys/kern/kern_spinlock.c:419", "sys/kern/kern_spinlock.c:420", "sys/kern/kern_spinlock.c:424", "sys/kern/kern_spinlock.c:206", "sys/kern/kern_spinlock.c:238", "sys/kern/kern_spinlock.c:249", "sys/sys/indefinite2.h:171", "sys/sys/indefinite2.h:183", "sys/kern/kern_lock.c:71" ], "poc_changes": "Seed sketch replaced: no compilable PoC is needed (sysctl-only trigger); trigger.sh/run.sh encode the exact vm.sh session; panic signature recovered from source + live msgbuf because no crash dump completes (panicking thread holds 2 spinlocks + crit section).", "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": 1470, "guest_dirty": 0, "build_cmd": "none (sysctl-only PoC)", "run_cmd": "vm.sh run_root 'sysctl -w debug.spin_lock_test=1'", "code_hash": "a843d75690c9bcdcdca378a7da25f7043bfaf5afbb2c088a86df0de9c632f707", "notes": "Adjacent hazard documented in VERDICT.md: a working test-mode break returns without the lock and the handler's double spin_unlock leaves the lock word at 0x0FFFFF (harmless on the stack-local test lock, but shows why break-without-acquire is dangerous; production reachability of that break is panicstr!=NULL only, indefinite2.h:169-170). Guest reset to clean with-src snapshot after the runs.", "recommended_fix": "Make indefinite_check() honor spin_lock_test_mode for spinlock wait types ('S'/'s') โ de-staticize the variable, extern it in sys/indefinite.h, add a type-gated break beside the lock_test_mode check (see fix.diff); alternatively delete the value==1 test branch.", "fix_status": "not_testable", "fix_kernel_uname": "", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree (restores pre-2017 semantics); kernel rebuild + patched rerun not performed for this Low, root-gated, non-corruption finding โ expected patched behavior: sysctl returns after ~1s with a single indefinite-wait report and a backtrace, guest stays up.", "fix_evidence": ["fix.diff"] } |