DF-4365 / verdict.json
{ "finding_id": "DF-4365", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "pcn(4) instance of the DF-3715 AB-BA callout family. Mechanism PROVEN on the guest on the first attempt by deterministic replica of if_pcn.cs exact callout/serializer protocol; pcn-specific runtime hardware-gated (inconclusive per family convention). pcn_tick (sys/dev/netif/pcn/if_pcn.c:873-899) is the callback of a PLAIN non-MPSAFE callout (callout_init at :577 -> callback executes under the Giant MP lock, kern_timeout.c:583) and does a BLOCKING lwkt_serialize_enter(ifp->if_serializer) at :879 with unconditional self re-arm at :896; pcn_stop() tears it down with callout_stop() at :1329 while holding that same serializer (callers: pcn_detach :641-643, pcn_shutdown :1374-1376, pcn_init :1106 via pcn_ioctl SIOCSIFFLAGS :1273/:1276 + pcn_watchdog :1306-1310 + pcn_intr ERR :929, and pcn_intr direct :912-914). DragonFly callout_stop synchronously waits for an INPROG callback (kern_timeout.c:1091/920 costp, INPROG at :567). Kernel-module replica on the guest: with the pcn-shaped tick parked, callout_stop NEVER returned - stopper observed D0/wchan costp (pid 1131), softclock 2 observed B2/wchan slize holding the Giant MP lock (non-MPSAFE callout), serial console shows fired=2 ran=1 then the terminal marker line. The wedge survived a clean shutdown attempt (guest could not power off; qemu SIGKILL + snapshot revert required). Fix-shape validation on a fresh guest with the exact fix.diff protocol (lwkt_serialize_try + 1-tick retry): callout_stop RETURNED with callout_pending()==0 after 308 try-enter retries over a 3s serializer hold (fires=309 ran=1 retries=308) and zero parks - deadlock eliminated at protocol level. On PCnet hardware the trigger is any ifconfig pcnX down/up cycle, flags/MTU change, watchdog reinit, detach, suspend/resume or system shutdown racing the 1 Hz tick: permanent two-thread kernel wedge + CPU callout blackout + unclean-shutdown hang.", "exploit_chain": "", "evidence": "findings/poc/DF-4365/VERDICT.md; run.log (session transcript: D0 costp stopper pid 1131 + B2 slize softclock 2 + shutdown-wedge note); fix_validation.log (fixed-shape: fires=309 retries=308, callout_stop RETURNED pending=0, guest healthy); build.log (both modules built clean under -Werror); boot.log.wedge (serial console with both marker lines); fix.diff (lwkt_serialize_try + 1-tick retry for pcn_tick, git apply --check clean)", "kernel_refs": [ "sys/dev/netif/pcn/if_pcn.c:577", "sys/dev/netif/pcn/if_pcn.c:879", "sys/dev/netif/pcn/if_pcn.c:896", "sys/dev/netif/pcn/if_pcn.c:1329", "sys/dev/netif/pcn/if_pcn.c:641", "sys/dev/netif/pcn/if_pcn.c:1106", "sys/dev/netif/pcn/if_pcn.c:1374", "sys/dev/netif/pcn/if_pcn.c:912", "sys/kern/kern_timeout.c:567", "sys/kern/kern_timeout.c:920", "sys/kern/lwkt_serialize.c:105" ], "poc_changes": "No seed PoC. Authored pcn_callout_replica.ko (out-of-tree kmodule replicating the pcn callout protocol verbatim, including the plain/non-MPSAFE callout_init and 1 Hz re-arm) because the guest has no PCnet hardware; the deadlock is in the generic protocol pcn uses, so the replica exercises the identical kernel paths (same methodology as DF-3715/3850 family). pcn_callout_replica_fixed.ko validates the fix shape live. Replica MOD_UNLOAD originally forgot callout_stop and crashed the guest with softclock_handler executing unmapped module text - itself a live corroboration of the familys post-detach UAF mode; fixed in the shipped source.", "attempts": 3, "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": 1500, "guest_dirty": 0, "build_cmd": "cd findings/poc/DF-4365 && ./build.sh (KMOD=pcn_callout_replica[_fixed] SRCS=... out-of-tree under bsd.kmod.mk, -Werror)", "run_cmd": "vm.sh run_root kldload /root/kmod/pcn_callout_replica.ko; sysctl kern.pcnreplica_arm=1; sleep 1; (sysctl kern.pcnreplica_stop=1 >/dev/null 2>&1 &); sleep 6; ps -o pid,stat,wchan,command -ax | grep pcnreplica_stop", "code_hash": "4e0fb1148c32bc9d5d1c0930cf1b38682cabef81dc5c064873bf3e2cc92cd18c", "notes": "pcn(4) instance, 15th member of the DF-3715/3738/3760/3776/3806/3850/3903/3906/3935/3991/4025/4046 family. Guest md5(/usr/src/sys/dev/netif/pcn/if_pcn.c)==c71b870d9bb85254532bcd477907eb57 == audited tree. Guest reset to with-src snapshot after verification.", "recommended_fix": "Make pcn_tick() non-blocking: lwkt_serialize_try() with a 1-tick callout_reset retry (fix.diff, protocol-validated live).", "fix_status": "inconclusive", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree (git apply --check clean): pcn_tick uses lwkt_serialize_try + 1-tick retry. Validated at protocol level on the guest with pcn_callout_replica_fixed.ko (callout_stop returns, pending==0, 308 retries / 0 parks over a 3s serializer hold). Driver-level validation impossible on this guest (no PCnet NIC).", "fix_evidence": "findings/poc/DF-4365/fix.diff; findings/poc/DF-4365/fix_validation.log" } |