DF-4310 / verdict.json
{ "finding_id": "DF-4310", "status": "inconclusive", "reproduced": 0, "impact": "dos", "confidence": "certain", "verdict": "Mechanism PROVEN on the guest kernel by deterministic replica of if_ste.cs exact callout/serializer protocol; ste-specific runtime hardware-gated (inconclusive per DF-3715 family convention). ste_stats_update (sys/dev/netif/ste/if_ste.c:780-813) is a NON-MP callout (callout_init :914, armed hz :1220) whose FIRST action is the blocking lwkt_serialize_enter(ifp->if_serializer) (:790) and which re-arms itself INSIDE that serializer (:811); ste_stop (:1231) and ste_intrs STATS_OFLOW path (:607-610) tear it down with the SYNC callout_stop() while holding that same serializer. DragonFly callout_stop synchronously waits for an in-progress callback (sys/kern/kern_timeout.c:1091 -> :859-930, ssleep costp at :920). A dequeued callback parked on the serializer therefore deadlocks against the stopper (AB-BA): stopper sleeps forever holding if_serializer; the softclock thread sleeps forever on the serializer WITH THE MP LOCK HELD (non-MP callback, kern_timeout.c:580-585) -> legacy (non-MPSAFE) system paths stall system-wide. ste_stop is reached under the serializer from ste_detach (:997-998), ste_init (:1130; from ste_ioctl SIOCSIFFLAGS :1322/:1326, ste_intr HOSTERR :617, ste_txeoc :723/:736, and ste_watchdog :1494 which itself runs serialized on netisr0 via sys/net/if.c if_slowtimo_dispatch), and ste_shutdown (:1507); the STATS_OFLOW callout_stop runs in interrupt-thread context. Kernel-module replica on the guest: stop under a held serializer with the ste_stats_update-shaped handler parked -> callout_stop NEVER returns (sterplica[blk]: ste_stats_update handler BLOCKED on our serializer (fired=14 ran=13) - entering callout_stop() then silence; ps 1076 D4 costp sysctl kern.sterplica.stop_blk=1); the wedged guest subsequently failed clean shutdown (MP lock parked) and had to be force-reset. Positive control: the try-enter fixed shape is fully unloaded by callout_stop under the serializer (returns, pending=0), validating the fix mechanism. Secondary source-level outcome of the same root cause: the ticks in-body callout_reset (:811) is processed recursively and overrides a racing STOP (kern_timeout.c RESET beats STOP), so ste_stop can return with the timer re-armed; at detach the resurrected tick dereferences the freed softc/miibus/ste_ldata one second later (post-detach UAF).", "exploit_chain": "Local user (no privileges needed for the TX path): send traffic through a running ste(4) interface -> ste_start sets if_timer=5 (:1475) -> if_slowtimo on netisr0 serializes into if_serializer and calls ste_watchdog (:1481) -> ste_init -> ste_stop -> sync callout_stop under the serializer while the 1 Hz ste_stats_update tick is parked in lwkt_serialize_enter on it -> both threads sleep forever, MP lock held: interface permanently wedged, one CPUs softclock callout pipeline dead, non-MPSAFE system paths (incl. shutdown) stall. Admin path: ifconfig ste0 down (SIOCSIFFLAGS :1326) or kldunload/if_detach races the same tick. Availability only; no memory corruption, no uid=0 route.", "evidence": "findings/poc/DF-4310/VERDICT.md (path:line trace + interleaving + shutdown-failure corroboration); run.log (replica session: control sterplica[fixed]: callout_stop RETURNED (no deadlock), pending=0; wedge sterplica[blk]: ... entering callout_stop() then silence; ps 1076 D4 costp sysctl kern.sterplica.stop_blk=1); build.log (module built on guest BUILD_RC=0, -Werror clean); env.txt (no Sundance/D-Link PCI on guest, clean post-reset state); fix.diff (try-enter + re-arm-outside, patch-apply verified against tree layout)", "kernel_refs": [ "sys/dev/netif/ste/if_ste.c:914", "sys/dev/netif/ste/if_ste.c:1220", "sys/dev/netif/ste/if_ste.c:790", "sys/dev/netif/ste/if_ste.c:811", "sys/dev/netif/ste/if_ste.c:1231", "sys/dev/netif/ste/if_ste.c:607", "sys/dev/netif/ste/if_ste.c:997", "sys/dev/netif/ste/if_ste.c:1130", "sys/dev/netif/ste/if_ste.c:1322", "sys/dev/netif/ste/if_ste.c:1494", "sys/dev/netif/ste/if_ste.c:1507", "sys/dev/netif/ste/if_ste.c:1475", "sys/dev/netif/ste/if_ste.c:974", "sys/kern/kern_timeout.c:1091", "sys/kern/kern_timeout.c:920", "sys/kern/kern_timeout.c:580", "sys/net/if.c:1900" ], "poc_changes": "No seed PoC (finding new in pass 2). Authored ste_callout_replica.ko (out-of-tree kmodule replicating stes EXACT protocol: non-MP callout_init at :914 flavor, hz self re-arm inside the serializer at :811 flavor, blocking lwkt_serialize_enter first-action at :790 flavor) because the guest has no Sundance ST201 hardware and QEMU cannot emulate one; the deadlock lives in the generic protocol ste uses, so the replica exercises the identical kernel paths (kern_timeout.c callout_stop sync wait vs lwkt_serialize_enter sleep), per the DF-3715 family methodology.", "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": "cd /root/kmod && make", "run_cmd": "vm.sh run_root kldload /root/kmod/ste_callout_replica.ko; sysctl kern.sterplica.arm=1; sysctl kern.sterplica.stop_fixed=1; (sysctl kern.sterplica.stop_blk=1 &); sleep 12; dmesg | grep sterplica | tail -8; ps -o pid,stat,wchan,command -ax | grep stop_blk", "code_hash": "3a0ea8c99ecb9ddd3955972ede955fe99147f72231db1eb35540cf42bb32dae7", "notes": "DF-3715 family instance (siblings: DF-4046 stge, DF-4051 nfe, DF-4057 et, DF-4064 fxp, DF-4109 tl, DF-4112 nge, DF-4218 ae, DF-4260 vr, DF-4275 epic, DF-4303 bfe). Guest was force-reset to the with-src snapshot after the wedge (the D4 costp thread + parked softclock thread + held MP lock are unsurvivable; clean shutdown failed, corroborating the MP-lock-hold analysis).", "recommended_fix": "ste_stats_update: replace the blocking lwkt_serialize_enter with lwkt_serialize_try (skip this ticks work on contention) and move the hz self re-arm outside the serializer \u2014 the fix shape merged for em(4) in DF-3715 and validated on this kernel by the stop_fixed positive control; see fix.diff.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree (patch -p1 apply-verified against the tree layout); the fixed try-enter shape IS the stop_fixed positive control, which returns cleanly with pending=0 on this guest kernel (mechanism validated); the driver-level diff cannot be runtime-tested without Sundance ST201 hardware.", "fix_evidence": "findings/poc/DF-4310/fix.diff; run.log sterplica[fixed]: callout_stop RETURNED (no deadlock), pending=0" } |