DF-2942 / verdict.json
{ "finding_id": "DF-2942", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "likely", "verdict": "Mechanism reproduced on the stock INVARIANTS guest via a KLD probe with a synthetic sysref_class. sysref_activate()'s only gate, the KASSERT at kern_sysref.c:280, accepts count == -0x40000000 -- the exact termination-in-progress state entered by _sysref_put's 1 -> -0x40000000 cmpset (:323). Calling sysref_activate() on a terminating object resurrected it to refcnt +1 with zero layer diagnostics on the INVARIANTS kernel, and the protocol then invoked the class terminate callback a SECOND time (run.log: term_count=2, 'CONFIRMED DOUBLE TERMINATION'); a probe variant re-activating on every termination produced 292 consecutive re-terminations ending in a fatal double fault from kernel stack exhaustion (run.1.unbounded.log). For a real class a double terminate re-runs the teardown (cdev's devfs_cdev_terminate would double devfs_release_ops and double-unlock devfs_lock), and the unbounded variant is a guaranteed stack-exhaustion panic. Attacker reachability: none in-tree -- the only live sysref_activate caller is devfs_new_cdev (devfs_core.c:2443), invoked exactly once right after sysref_alloc; the finding is the layer's ambiguous negative space (latent hardening gap, no SRF_TERMINATING distinction).", "exploit_chain": "", "evidence": "findings/poc/DF-2942/run.log: 'DF-2942: after activate refcnt=1 (RESURRECTED; kern_sysref.c:280 KASSERT passed, no diagnostic)' followed by terminate#2 and 'A: CONFIRMED DOUBLE TERMINATION (terminate callback ran twice for one object)'.\nfindings/poc/DF-2942/run.1.unbounded.log: 292 consecutive terminate re-entries then 'Fatal double fault' / 'panic: double fault' (stack exhaustion via sysref_put -> _sysref_put -> ops.terminate recursion).\nfindings/poc/DF-2942/build.log: clean KLD build (cc 8.3, INVARIANTS kernel #0).\nsys/kern/kern_sysref.c:280-281 accepting KASSERT; :164 init sentinel; :323 termination transition; sys/sys/sysref.h:115-117 flag bits (no TERMINATING).", "kernel_refs": [ "sys/kern/kern_sysref.c:278", "sys/kern/kern_sysref.c:280", "sys/kern/kern_sysref.c:164", "sys/kern/kern_sysref.c:323", "sys/sys/sysref.h:115", "sys/vfs/devfs/devfs_core.c:2443", "sys/vfs/devfs/devfs_core.c:2487" ], "poc_changes": "Authored from scratch (no seed): synthetic sysref_class KLD mirroring devfs_cdev_terminate's lock/unlock/terminate protocol; the activate-during-termination call is made from inside the terminate callback (deterministic simulation of a racing misuser) with a one-shot flag; run 1 accidentally demonstrated the unbounded variant before the flag was added (kept as run.1.unbounded.log).", "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": 420, "guest_dirty": 0, "build_cmd": "ssh -F dfbsd-qemu/config dfbsd 'cd /root/sysref_probe && make' (after scp of sysref_probe.c + Makefile)", "run_cmd": "ssh -F dfbsd-qemu/config dfbsd 'kldload /root/sysref_probe/sysref_probe.ko'", "code_hash": "8e3ef23300267dbc68db2f94e6e462d035b87f6a8c76f1343ae27194d0ea81a7", "notes": "Guest reset (with-src) after the run; guest_dirty=0. Same probe module/run as DF-2941 (shared evidence). In-tree single-caller discipline verified by rg: sysref_activate appears only at devfs_core.c:2443.", "recommended_fix": "Add an SRF_TERMINATING flag set on the 1 -> -0x40000000 transition and cleared on (re)initialization, and extend sysref_activate's KASSERT to reject terminating objects so the initializing and terminating negative-space states are no longer ambiguous.", "fix_status": "not_testable", "fix_verdict": "Fix authored post-verification (fix.diff); not build-validated: Info hardening finding, the fix's observable effect is the new assert path itself; no corruption was reproduced to A/B test against." } |