DF-2693 / verdict.json
{ "finding_id": "DF-2693", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "postsig() reads ps_sigact[] without p_token when the delivered signal was lwp-pending (haveptok==0, the common routing for kill() to multithreaded processes), racing a concurrent sigaction(SIG_IGN) from another thread; the KASSERT at kern_sig.c:2309 fires. Reproduced on the stock INVARIANTS kernel as an unprivileged 8-thread program: panic 'postsig action' within 150 s, stack postsig+0x3ae <- userret <- syscall2, symbolically confirmed via gdb to be exactly kern_sig.c:2309 (postsig+928..944). On non-INVARIANTS kernels the race degrades to the process jumping to SIG_IGN (address 1) - self-inflicted SIGSEGV, no cross-privilege impact.", "exploit_chain": "", "evidence": [ "run.log - stock-kernel run, panic: postsig action, gdb line confirmation", "panic.txt - console capture incl. interleaved 'should not hit signal 30!' (issignal's warning, same race)", "postsig_race.c - 4 sender threads + 4 flipper threads" ], "kernel_refs": [ "sys/kern/kern_sig.c:2281", "sys/kern/kern_sig.c:2309-2310", "sys/kern/kern_sig.c:281-375", "sys/platform/pc64/x86_64/trap.c:278-281" ], "poc_changes": "none - the sketch-level race program worked as designed on the first stock-kernel attempt.", "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": 170, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -pthread -o postsig_race postsig_race.c", "run_cmd": "su -l t1 -c /tmp/t1home/postsig_race 150", "code_hash": "70a1ea62d449fc5cf0a4e0bec5a03876c887f770d8276d1187d5a2b270b47dc1", "notes": "First reproduction happened on a kernel whose only delta was the (unrelated) DF-2691 fix; reproduced again on the pristine stock kernel. INVARIANTS-only DoS; POSIX leaves the racy outcome unspecified but the kernel must not KASSERT-panic.", "recommended_fix": "Replace the KASSERT with graceful handling: if action == SIG_IGN or the signal became masked between the CURSIG decision and now, simply return (the racing sigaction already cleared pending state)", "fix_status": "not_tested", "fix_kernel_uname": "", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored (KASSERT -> graceful return) and verified to apply cleanly, but no fixed kernel was built for this Low/DoS finding within this run.", "fix_evidence": [ "fix.diff" ] } |