⬢ DragonFlyBSD Kernel Audit
DF-3981 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3981",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "sbp(4) arms sdev->login_callout (sbp.c:649-650, up to login_delay=1000ms, auto_login default on) but never stops it on the three sbp_dev free paths: sbp_alloc_lun stale-LUN invalidation (sbp.c:444-445), the trailing !VALID_LUN loop (sbp.c:534-541), and sbp_post_explore GC -> sbp_free_target -> sbp_free_sdev (sbp.c:776-786, 816-817, 1978-1990, kfree at 1989; the only stop in the whole driver is sbp_logout_all sbp.c:1959, shutdown-only). A hostile FireWire device controls its Config ROM LUN set and bus-reset timing, so it can free an sdev while the callout is armed; sbp_login_callout (sbp.c:625-629) then calls sbp_mgm_orb() on the kfreed sdev: freed-slab reads (sdev->target, free_ocbs head), writes into freed slab (ocb->flags/sdev) and into fwdma_freed ORB pages (orb[0..7]) plus a re-armed mgm_ocb_timeout on the dangling ocb - kernel heap use-after-free read+write, deterministic attacker timing. End-to-end inconclusive only because the audit guest has no FireWire OHCI controller (pciconf, env.txt); the core mechanism - the DragonFly callout subsystem firing a callback on a kfreed container - was PROVEN live on the guest kernel twice on two boots via mechanism replica A (run.log: login_callout FIRED on FREED object 0xfffff80117817880, arg == freed pointer: YES).",
  "exploit_chain": "crafted FireWire device: present LUN N (ROM CROM_LUN) -> probe arms login_callout (<=1s) -> device forces bus reset and re-presents ROM without LUN N -> sbp_post_explore/sbp_alloc_lun kfree(sdev) with callout armed -> softclock fires sbp_login_callout on freed slab -> sbp_mgm_orb UAF: slab-recycled reads drive pointer walks; orb writes land in freed (reusable) DMA pages; mgm timeout re-armed on dangling ocb -> subsequent status write by the attacker completes through freed state -> heap corruption / panic.",
  "evidence": "VERDICT.md (full path:line analysis); run.log (mechanism A output, two boots); build.log (module built on guest /usr/src); env.txt (no OHCI-1394 on guest); fix.diff (callout_stop in sbp_free_sdev + scan_callout/slot-release in sbp_free_target, applies cleanly)",
  "kernel_refs": [
    "sys/dev/disk/sbp/sbp.c:183",
    "sys/dev/disk/sbp/sbp.c:625",
    "sys/dev/disk/sbp/sbp.c:649",
    "sys/dev/disk/sbp/sbp.c:444",
    "sys/dev/disk/sbp/sbp.c:536",
    "sys/dev/disk/sbp/sbp.c:776",
    "sys/dev/disk/sbp/sbp.c:1978",
    "sys/dev/disk/sbp/sbp.c:1989",
    "sys/dev/disk/sbp/sbp.c:1993",
    "sys/dev/disk/sbp/sbp.c:1959"
  ],
  "poc_changes": "No runnable end-to-end PoC possible (no FireWire hardware in guest). Wrote a kernel mechanism replica instead: kmallocd container + armed callout + kfree, callback reports firing on the freed pointer without dereferencing (guest-safety); requires callout_init (not CALLOUT_INIT, which is a firewire-internal alias) and DFlys 10-arg SYSCTL_ADD_PROC.",
  "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": 240,
  "guest_dirty": 0,
  "build_cmd": "cd /root/kmod && make",
  "run_cmd": "kldload ./sbpprep.ko && sysctl kern.sbpprep_a=1 && sleep 4 && dmesg | grep sbpprep[A]",
  "code_hash": "c4245b4d7304e28974191235a02ccdcf60287b38fd2b76e8e7b2974689a8bda5",
  "notes": "Same-module mechanism B (blocking callout_stop) is filed as DF-3982 with its own evidence. Guest was reset with-src after the runs (clean hand-off).",
  "recommended_fix": "callout_stop(&sdev->login_callout) at the top of sbp_free_sdev; also stop scan_callout and clear fwdev in sbp_free_target even when luns==NULL (fix.diff in pack).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff authored from line-accurate source analysis; applies cleanly (patch --dry-run verified). Cannot be kernel-build validated on this guest: the trigger path needs FireWire hardware, so a patched-kernel run has no observable delta here.",
  "fix_evidence": "fix.diff (callout_stop additions; slot-release restructure of sbp_free_target)"
}