DF-4056 / verdict.json
{ "finding_id": "DF-4056", "status": "reproduced", "reproduced": true, "impact": "panic", "confidence": "certain", "verdict": "REPRODUCED, BOTH HALVES, via production-handler KLD dispatch (DF-4106 vge / DF-4266 wb class). TX half: dispatched the real et_txeof(sc,0) (et_start:1223 call shape) with ET_TX_DONE_POS index 600 - representable by the 10-bit register field (if_etreg.h:139) but unreachable by tbd_start_index which wraps at ET_TX_NDESC=512 - with tbd_used=1: the walk (if_et.c:2029) decrements tbd_used past zero and the kernel panicked exactly as predicted: panic: assertion tbd->tbd_used > 0 failed in et_txeof at if_et.c:2050, backtrace et_txeof+0x1cb (panic_tx.txt). RX half: dispatched the real et_intr (inlined et_rxeof) with rxs_stat_ring index 2000 - representable by the 12-bit field (if_etvar.h:107) but unreachable by rsr_index which wraps at ET_RX_NSTAT=1024: the completion walk (if_et.c:1851) never terminates, spinning ~11.5 MILLION iterations/s under the interface serializer (ierrors 4.23e9 -> 4.25e9 in ~2s, still linear 9 min later), serializer capture proven (second threads lwkt_serialize_enter blocked forever), caller unkillable, ps -ax itself hangs, guest unshutdownable afterwards. FIX VALIDATED: kernel #1 rebuilt with fix.diff (index-vs-ring-geometry validation before both walks): identical rig - TX: invalid TX done index 600, et_txeof RETURNED, no panic; RX: invalid RX stat ring index 2000, et_intr RETURNED, no livelock.", "exploit_chain": "Device/DMA attacker writes one status word: TX -> deterministic KKASSERT panic on the next TX interrupt; RX -> permanent livelock of one CPU holding the interface serializer (every later ioctl/if_start blocks) plus that contexts callout starvation. DoS class; no memory-corruption primitive.", "evidence": "panic_tx.txt (KKASSERT panic backtrace); run_rx_livelock.log (ierrors growth ~11.5M/s across two sessions, grab-probe serializer capture, ps hang, forced shutdown); fix_run_s2.log + fix_run_s2_dmesg.txt + fix_run_s3.log (patched kernel: both walks return with validation messages, no panic/livelock); VERDICT.md; env.txt", "kernel_refs": [ "sys/dev/netif/et/if_et.c:1851", "sys/dev/netif/et/if_et.c:2029", "sys/dev/netif/et/if_et.c:2050", "sys/dev/netif/et/if_etreg.h:139", "sys/dev/netif/et/if_etvar.h:107", "sys/dev/netif/et/if_etvar.h:42", "sys/dev/netif/et/if_etvar.h:45" ], "poc_changes": "Authored the production-dispatch rig fresh (pack was untested/hardware-gated). et_rxeof has no standalone symbol - RX half dispatched through the real et_intr with ET_INTR_STATUS=ET_INTR_RXEOF. S3 observation via sysctl probes (kern.dfet.stats / kern.dfet.grab) after ps -ax proved to hang against the spinner.", "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 (baseline) / #1: Wed Oct 14 21:12:27 UTC 2026 (fix-validated)", "runtime_sec": 1200, "guest_dirty": 0, "build_cmd": "vm.sh run_root sh /root/dfet/build.sh (bsd.kmod.mk, -Werror clean KLD)", "run_cmd": "TX: vm.sh run_root sh /root/dfet/run.sh 2 (panics). RX: background sh /root/dfet/run.sh 3 & then observe: sysctl kern.dfet.stats; (sysctl -w kern.dfet.grab=1 &)", "code_hash": "3b4bd9f30b6569fd3e8e1fc571c53fe7953911fdfb17e15a97f78ad8bb12c69c", "notes": "impact=panic (TX half, deterministic KKASSERT) with the RX half a permanent livelock DoS - both observed; impact field carries the more severe deterministic outcome. Combined rig shared with DF-4055/DF-4057 packs. Hardware-mediated trigger (faulty/hostile NIC register write) - Medium severity stands.", "recommended_fix": "Validate device-supplied indices against ring geometry before the completion walks: reject rxst_index >= ET_RX_NSTAT and TX DONE end >= ET_TX_NDESC (error counter + return); optionally add loop work budgets", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Kernel #1 (same tree + fix.diff) A/B with the identical rig: TX - baseline panic tbd_used > 0 at if_et.c:2050 vs patched invalid TX done index 600 + et_txeof returned (tbd_used=1, no panic); RX - baseline 11.5M-iter/s unbounded livelock vs patched invalid RX stat ring index 2000 + et_intr returned (ierrors flat). Defective behaviors gone.", "fix_evidence": "findings/poc/DF-4056/fix.diff; fix_run_s2.log; fix_run_s2_dmesg.txt; fix_run_s3.log; fix_build.log" } |