⬢ DragonFlyBSD Kernel Audit
DF-4271 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4271",
  "status": "untested",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Race established from the DragonFly callout API contract. wb_tick (if_wb.c:1191-1201) self-serializes (:1197) and self-re-arms (:1199); wb_stop() only issues callout_stop() (:1590), which kern_timeout.c documents for non-lock-aided callouts (wb uses plain callout_init, :715) as does not block... does not interlock against a callout that is in-progress. During detach (:839-846) a wb_tick blocked on the serializer proceeds after :843s release, post-teardown: mii_tick against the miibus child deleted at :848-849, and callout_reset re-arming a timer inside the softc that newbus frees when detach returns - a repeating use-after-free every hz until the freed callout state is overwritten. Privileged trigger (kldunload / device removal) on hardware-bearing systems; window is one tick. Not kernel-reproduced: no W89C840F NIC in the guest (env.txt).",
  "exploit_chain": "kldunload if_wb.ko with interface up while wb_tick is blocked on if_serializer -> teardown completes -> wb_tick runs on deleted miibus and re-arms timer in freed softc -> callout fires into freed memory every hz (repeating UAF: reads sc->wb_miibus from freed softc, dereferences it, writes callout state).",
  "evidence": "VERDICT.md (API-contract citation + interleaving); sys/kern/kern_timeout.c callout_stop doc block; env.txt",
  "kernel_refs": [
    "sys/dev/netif/wb/if_wb.c:1590",
    "sys/dev/netif/wb/if_wb.c:715",
    "sys/dev/netif/wb/if_wb.c:839",
    "sys/dev/netif/wb/if_wb.c:843",
    "sys/dev/netif/wb/if_wb.c:1197",
    "sys/dev/netif/wb/if_wb.c:1199",
    "sys/kern/kern_timeout.c:1085"
  ],
  "poc_changes": "No runnable PoC (hardware-gated race); analysis pack.",
  "attempts": 0,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 02:54:00 UTC 2026  root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "runtime_sec": 0,
  "guest_dirty": 0,
  "build_cmd": "",
  "run_cmd": "",
  "code_hash": "",
  "notes": "Matches the tree-wide blocking serialize vs sync callout_stop discipline question: re and bge share the plain callout_stop idiom, but wb_ticks self-re-arm makes the post-detach window persistent rather than one-shot.",
  "recommended_fix": "Add callout_drain(&sc->wb_stat_timer) in wb_detach after lwkt_serialize_exit (draining while holding the serializer would deadlock).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Fix validation requires the NIC; the guest has none.",
  "fix_evidence": "fix.diff; VERDICT.md"
}