DF-3715 / verdict.json
{ "finding_id": "DF-3715", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Mechanism PROVEN on the guest kernel by deterministic replica of if_em.cs exact callout/serializer protocol; em-specific runtime hardware-gated (inconclusive per family convention). em_timer (sys/dev/netif/em/if_em.c:2216-2239) and em_82547_move_tail (:2027-2036) are MP callouts whose callbacks BLOCK in lwkt_serialize_enter (:2222/:2033) on the driver serializer; em_stop tears them down with callout_stop (:2343-2344) while holding that same serializer; DragonFly callout_stop synchronously waits for an in-progress callback (sys/kern/kern_timeout.c:859-932, ssleep costp at :923). A callback dequeued and parked on the serializer therefore deadlocks against the stopper (AB-BA): both threads wedge permanently, the interface serializer is never released and the affected CPUs softclock thread stops delivering all callouts. Kernel-module replica on the guest: stop under a held serializer with the em_timer-shaped handler parked -> callout_stop NEVER returns (caller D3 wchan costp); negative control: the try-based em_txgc_timer shape is fully unloaded by callout_stop (pending=0) - which also shows the DF-3669/DF-3681 re-arm survives callout_stop premise does not hold on this kern_timeout.c, so for em the defect is the deadlock, not a post-stop re-arm UAF.", "exploit_chain": "", "evidence": "findings/poc/DF-3715/VERDICT.md; run.log (replica session transcript + raw dmesg/ps captures: IF THIS IS THE LAST replica LINE then silence; ps 1051 D3 costp sysctl kern.emreplica.stop_blk=1); build.log (module built on guest, BUILD_RC=0); fix.diff (try-enter + 1-tick retry for em_timer/em_82547_move_tail)", "kernel_refs": [ "sys/dev/netif/em/if_em.c:2222", "sys/dev/netif/em/if_em.c:2236", "sys/dev/netif/em/if_em.c:2033", "sys/dev/netif/em/if_em.c:2016", "sys/dev/netif/em/if_em.c:2343", "sys/dev/netif/em/if_em.c:2350", "sys/dev/netif/em/if_em.c:1049", "sys/kern/kern_timeout.c:859", "sys/kern/kern_timeout.c:923", "sys/kern/kern_timeout.c:1091" ], "poc_changes": "No seed PoC. Authored callout_replica.ko (out-of-tree kmodule replicating the em callout protocol) because the guest has no em hardware; the deadlock is in the generic protocol em uses, so the replica exercises the identical kernel paths.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64", "runtime_sec": 240, "guest_dirty": 0, "build_cmd": "cd /root/kmod && make", "run_cmd": "vm.sh run_root kldload /root/kmod/callout_replica.ko; sysctl kern.emreplica.arm=1; sysctl kern.emreplica.stop_gc=1; (sysctl kern.emreplica.stop_blk=1 &)", "code_hash": "6c8ac128db5d02d977f1815a072002c62a81721023acc990044688fd2ee81f0a", "notes": "Triggers on em hardware: ifconfig em0 down/up, SIOCSIFMTU on running interface, detach/kldunload, suspend/resume, watchdog reinit - any em_stop while em_timer is INPROG-parked. Narrow per-call race window but repeatable; impact is permanent system degradation (two wedged threads + CPU-wide callout starvation). Environment note: first guest instance had kldload wedged guest-wide by a PRE-EXISTING stuck kldload arcms (since 7:21PM, before this session); after vm.sh reset with-src, kldload works - the wedge is not driver-related.", "recommended_fix": "Make em_timer() and em_82547_move_tail() non-blocking: lwkt_serialize_try() with a 1-tick callout_reset retry (em_txgc_timer pattern).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree (patch --dry-run clean); cannot be validated on a guest without em hardware.", "fix_evidence": "findings/poc/DF-3715/fix.diff" } |