DF-4275 / verdict.json
{ "finding_id": "DF-4275", "status": "reproduced", "reproduced": 1, "impact": "dos", "confidence": "certain", "verdict": "REPRODUCED (mechanism): epic_stop() (if_tx.c:1341) calls the synchronous callout_stop() while holding ifp->if_serializer; epic_stats_update() (if_tx.c:803) must first enter that same serializer. A dequeued (CALLOUT_INPROG) tick parked on the serializer makes callout_stop() sleep forever in costp while the callback waits forever for the serializer the stopper holds. Protocol-replica KLD on the guest (kernel rebuilt from the audit tree) shows both sides stuck in ps: df4275stop wchan=costp, softclock 5 wchan=slize (callback inside lwkt_serialize_enter), permanent. Same proven mechanism as DF-3715 (em(4)); if_tx.c was missed in pass 1. Driver-level triggers are source-traced (SIOCSIFMTU/SIOCSIFFLAGS if_tx.c:370-391, watchdog if_tx.c:781-782 under ifnet_tryserialize_all -> also wedges netisr0, PCI-fatal if_tx.c:702-703, detach if_tx.c:300-304); the SMC83C170 NIC itself is not emulated by QEMU, so the trigger could not be exercised with the real device.", "exploit_chain": "ifconfig tx0 down/mtu (root) or a TX-stall watchdog timeout (no root) while the 1s mii tick is parked on ifp->if_serializer -> epic_stop() under the serializer -> callout_stop() waits costp for the parked callback -> two threads (plus the non-MPSAFE softclock holding the MP lock) wedge permanently; watchdog path additionally wedges netisr0.", "evidence": "run.log: lines wmesg=\"costp\" x5 + RESULT DEADLOCK; ps lines df4275stop wchan=costp and softclock 5 wchan=slize; VERDICT.md full narrative incl. two earlier honest iterations; env.txt kernel + toolchain.", "kernel_refs": [ "sys/dev/netif/tx/if_tx.c:200", "sys/dev/netif/tx/if_tx.c:803", "sys/dev/netif/tx/if_tx.c:808", "sys/dev/netif/tx/if_tx.c:1341", "sys/dev/netif/tx/if_tx.c:370", "sys/dev/netif/tx/if_tx.c:389", "sys/dev/netif/tx/if_tx.c:781", "sys/dev/netif/tx/if_tx.c:702", "sys/dev/netif/tx/if_tx.c:300", "sys/kern/kern_timeout.c:920", "sys/kern/kern_timeout.c:1091", "sys/kern/kern_timeout.c:567", "sys/kern/lwkt_serialize.c:110" ], "poc_changes": "Protocol-replica authored from scratch (no seed). Three iterations: (1) tsleep-based wait demonstrated the wedge one step early (timeout delivered by the wedged wheel); (2) DELAY busy-wait starved softclock on the same CPU (LWKT no-preempt among equals) \u2014 replaced with lwkt_yield(); (3) final replica yields, then parks in callout_stop -> canonical costp. Also: DECLARE_MODULE on current DFly requires a moduledata_t variable (passing the handler makes module_register cast machine code as moduledata_t* and GPFs) \u2014 first build GPFd until fixed; guest kernel rebuilt from the audit tree with nativekernel because the shipped #0 kernel predates the source snapshot.", "attempts": 6, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Sat Sep 19 02:43:14 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 480, "guest_dirty": 0, "build_cmd": "cd /usr/src/df4275 && make", "run_cmd": "kldload /usr/src/df4275/df4275rep.ko; sleep 8; dmesg | grep df4275; ps -axo pid,tdo,stat,wchan,comm | grep -E df4275|softclock", "code_hash": "205e791d8df75a738b6e8485ca34c5116fc1d407bc54706f543224d84c46c0c7", "notes": "DoS, not memory corruption, so no uid0 chain applicable; fix validation not run (would need the tx(4) NIC for a driver-level retrigger; the replica cannot validate the if_tx.c diff). Guest was reset (with-src snapshot) after the wedge; clean for the next spawn. Guest hardware check: no SMC83C170/CardBus present (pciconf).", "recommended_fix": "Make the tick lock-aided: callout_init_lk(&sc->tx_stat_timer, ifp->if_serializer) after ether_ifattach and drop the lwkt_serialize_enter/exit from epic_stats_update (see fix.diff).", "fix_status": "untested", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against sys/dev/netif/tx/if_tx.c (never applied to sys/). Not built/booted: the tx(4) NIC is absent from the guest so a patched kernel cannot be retriggered at driver level; a replica-level re-run would only re-test kern_timeout.c, not this diff. Baseline (unfixed) deadlock is reproduced and documented in run.log.", "fix_evidence": "findings/poc/DF-4275/fix.diff (unified diff); baseline reproduction in findings/poc/DF-4275/run.log" } |