DF-2929 / verdict.json
{ "finding_id": "DF-2929", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Reproduced on the stock INVARIANTS guest: the in-tree DRM wrapper hrtimer_start_range_ns() (sys/dev/drm/linux_hrtimer.c:88-119), when called on an already-armed timer โ exactly what intel_uncore.c:___force_wake_auto() does on every auto-forcewake i915 register access โ re-runs systimer_init_oneshot() on a SYSTF_ONQUEUE-linked timer; the bzero() at sys/kern/kern_systimer.c:363 erases the node links while neighbours still point at it and also clears the ONQUEUE flag that would make systimer_add()'s KKASSERT (:148) catch it, so the queue silently gains ghost links/cycles and the dispatcher then unlinks through stale pointers: panic 'Bad link elm ... prev->next != elm' in systimer_intr() (via pcpu_timer_process_oncpu/splz_timer) and in systimer_del(). Raw engine sequence (harness mode 2) shows the corruption structurally (st<->P cycle, 8 revisits in 24 hops). On production kernels the same unlink is a wild write through a stale tqe_prev plus double-dispatch of one-shot callbacks. fix.diff (wrapper deletes the pending systimer on its owning cpu before re-init) validated: 8/8 clean runs, no panic, one fire per cycle.", "exploit_chain": "hrtimer_start_range_ns on armed timer -> bzero of queued struct systimer -> ghost links + cycle in gd_systimerq -> systimer_intr/TAILQ_REMOVE through stale tqe_prev (wild write; INVARIANTS catches as 'Bad link elm') -> panic / clock corruption. Production-kernel escalation beyond DoS additionally requires controlling the reused node contents (node lives in driver-owned memory) โ not demonstrated, recorded as hardening blocker.", "evidence": [ "run.log: 'DF2929 mode=2: forward hops=24 seen_st=8 seen_p=8 ... => QUEUE CORRUPT'", "panic.txt: panic 'Bad link elm' traces through systimer_del+0xd4 (mode 2) and systimer_intr+0x235 <- pcpu_timer_process_oncpu+0x82 <- splz_timer+0x13 cpuid=4 (mode 5, real drm.ko path)", "run.fix.log: 8x 'queue ok' + dht_fires=+1/run, guest stays up with patched drm.ko", "VERDICT.md: line-accurate root cause and the killed cross-cpu-del reachability hypothesis" ], "kernel_refs": [ "sys/kern/kern_systimer.c:363", "sys/kern/kern_systimer.c:148", "sys/kern/kern_systimer.c:359-371", "sys/dev/drm/linux_hrtimer.c:88-119", "sys/dev/drm/i915/intel_uncore.c:74-78", "sys/dev/drm/i915/intel_uncore.c:1165-1176" ], "poc_changes": "No prior seed โ pack authored fresh. PoC iterated during verification: (1) unprivileged ppoll/nanosleep precise-sleep racer (reachability probe; hypothesis killed: wakeups are cpu-local, 1.2M iterations zero asserts โ kept as run.2.log/df2929_ppollrace.c); (2) KLD harness modes 1/2 (raw engine sequence, structural corruption detector); (3) mode 5 driving the real in-tree hrtimer_start_range_ns via MODULE_DEPEND(drm). Removed an initial lwkt_setcpu_self() from the sysctl handler that caused an unrelated lockmgr artifact-panic.", "attempts": 4, "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": 3300, "guest_dirty": 0, "build_cmd": "cd /root/df2929 && make (KMOD df2929, COPTS+=-I/usr/src/sys/dev/drm/include) && kldload ./df2929.ko", "run_cmd": "sysctl kern.df2929_run=5", "code_hash": "9dc75f3cb9c8d538341cd8e90b31a0d5701ae4ba5c62ff2a455ac40c236c6496", "notes": "Guest: 6 vCPU KVM, INVARIANTS kernel #0 (X86_64_GENERIC), no i915 hardware โ wrapper driven directly by the KLD (root-loaded; the executed kernel path hrtimer_start_range_ns->systimer_init_oneshot->systimer_add is the production path, driven unprivileged-ly via GPU ioctls on i915 hardware). QMD queue checks make INVARIANTS kernels panic; production kernels perform the wild unlink silently. Related: DF-0154 (KKASSERT-only invariants) โ this finding supplies the concrete in-tree violator pass 1 said did not exist.", "recommended_fix": "linux_hrtimer.c: hrtimer_start_range_ns() must delete the pending systimer on its owning cpu (mirror hrtimer_cancel()'s lwkt_setcpu_self dance) before systimer_init_oneshot(); see fix.diff", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (kernel unchanged; drm.ko rebuilt from patched /usr/src/sys/dev/drm/linux_hrtimer.c)", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Applied fix.diff to guest /usr/src/sys/dev/drm/linux_hrtimer.c, rebuilt drm.ko (make obj && make in sys/dev/drm/drm), installed, rebooted, re-ran the identical PoC (kern.df2929_run=5) 8 times: queue integrity 'ok' every run, dht_fires increments by exactly 1 per run, no panic, guest stays up. Baseline with stock drm.ko panicked in systimer_intr on the first run. Bad behavior gone.", "fix_evidence": [ "run.fix.log: 8x 'DF2929 mode=5: ... => queue ok' + 'cancelled, dht_fires=1..4' + uptime output", "env.txt: running drm.ko MD5 == patched build MD5 (52965c2c7a18026a7d9089264ab796b7)", "fix.diff: git-apply-able unified diff against sys/dev/drm/linux_hrtimer.c" ] } |