⬢ DragonFlyBSD Kernel Audit
DF-5057 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5057",
  "status": "untested",
  "verdict": "Genuine DF-5025/DF-5013/DF-5046-family detach lifetime TOCTOU, mlx instance: MLX_DETACH_DRIVE (mlx.c:774-804) checks mlxd_flags & MLXD_OPEN at mlx.c:782, then SLEEPS in mlx_flush (mlx.c:788 -> mlx_poll_command spinning up to 15M MMIO polls, mlx.c:1690-1694) before device_delete_child (mlx.c:794) \u2014 and MLX_STATE_SHUTDOWN (mlxd_opens only gate, mlx_disk.c:98) is never raised on this path, so a concurrent mlxd_open succeeds inside the window and sets MLXD_OPEN (mlx_disk.c:113) after the check passed. mlxd_detach (mlx_disk.c:290-301) has no recheck and no drain: devstat_remove_entry + disk_destroy free path runs while the racing fd (si_drv1 = sc set at mlx_disk.c:259-260) and any bios already queued on the controller are alive; disk_destroy only interlocks disk-enumeration refs (subr_disk.c:875-881), cdev teardown keeps the open cdev with si_drv1 dangling (DF-5046 mechanism), and a late completion runs mlx_completeio (mlx.c:1811-1841) -> mlxd_intr -> devstat_end_transaction_buf(&sc->mlxd_stats) (mlx_disk.c:204) writing freed memory; mlxd_close (mlx_disk.c:127) and mlxd_strategy (mlx_disk.c:161,173,179-180) likewise touch the freed softc. Second leg: mlx_shutdown (mlx.c:611-617) deletes ALL children with no open-check of its own (pre-check only in mlx_detach, mlx.c:558-566) and is wired to device_shutdown (mlx_pci.c:54), so reboot deletes children under open descriptors and in-flight bios. Untested solely because the guest has no Mylex DAC960 PCI function (env.txt: no 0x1069/0x1011:1065 device, no /dev/mlx*) although the driver is compiled into the running X86_64_GENERIC. Severity Low matching DF-5025: trigger requires root (MLX_DETACH_DRIVE on the 0600 root:operator control node mlx.c:466-468, or reboot); mlx has no mfi-style unprivileged event-driven delete (periodic enquiry only prints, mlx.c:1126-1154).",
  "reproduced": false,
  "impact": "none",
  "confidence": "certain",
  "exploit_chain": "root ioctl(MLX_DETACH_DRIVE) on /dev/mlxN + racing open(/dev/mlxdN) landing inside the mlx_flush window -> device_delete_child -> mlxd_detach frees softc under the open fd -> mlxd_close/mlxd_strategy write freed memory (mlxd_flags clear, devstat_start_transaction, submit) and late completions write via devstat_end_transaction_buf. Not an escalation primitive: the initiating side is root-only; on hardware this is a root-triggerable kernel UAF write with heap-groom potential.",
  "evidence": "env.txt (live guest: no Mylex PCI function, no /dev/mlx*, driver in kernel); VERDICT.md full path:line trace of both legs; fix.diff (git apply --check: APPLIES_CLEAN)",
  "kernel_refs": [
    "sys/dev/raid/mlx/mlx_disk.c:86-115",
    "sys/dev/raid/mlx/mlx_disk.c:290-301",
    "sys/dev/raid/mlx/mlx_disk.c:192-206",
    "sys/dev/raid/mlx/mlx.c:774-804",
    "sys/dev/raid/mlx/mlx.c:1516-1549",
    "sys/dev/raid/mlx/mlx.c:1677-1703",
    "sys/dev/raid/mlx/mlx.c:589-622",
    "sys/dev/raid/mlx/mlx.c:545-576",
    "sys/dev/raid/mlx/mlx_pci.c:54",
    "sys/dev/raid/mlx/mlx.c:466-468",
    "sys/kern/subr_disk.c:873-897"
  ],
  "poc_changes": "No runnable PoC exists (hardware-gated). Pack contains hardware-absence evidence and the line-accurate code trace; fix.diff generated via edited copies + diff -u and validated with git apply --check.",
  "attempts": 1,
  "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": 150,
  "guest_dirty": 0,
  "build_cmd": "n/a \u2014 hardware-gated, no PoC build possible",
  "run_cmd": "vm.sh run_root pciconf -l | grep -iE \"1069|1011\"; ls /dev/mlxd* /dev/mlx*; kldload mlx; grep -n \"device.*mlx\" /usr/src/sys/config/X86_64_GENERIC (result: no Mylex function, no devices, module already in kernel)",
  "code_hash": "fd18b5602bfb961a022834fb04aacc82b691a201d7aef72f7ceab2b2b08a2d63",
  "notes": "Family: DF-5013 (mfi, High \u2014 unprivileged AEN delete) / DF-5049 (mfi syspd, High) / DF-5025 (ips, Low) / DF-5046 (ida, Low). mlx is the last LD sibling and sits with ips/ida in the Low tier: the open-check EXISTS but is check-then-sleep-then-act. Not a duplicate of DF-2074 (bio_driver_info), DF-1303/1304/3949-3952 (mlx.c pass-2 set). Guest left clean (read-only probes + a no-op kldload).",
  "recommended_fix": "Raise MLX_STATE_SHUTDOWN for the whole MLX_DETACH_DRIVE flush+delete window (closes the open race via mlxd_opens existing gate) and recheck MLXD_OPEN in mlxd_detach returning EBUSY; full fix also drains in-flight bios before disk_destroy.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff closes the open-race leg (SHUTDOWN flag raised across the sleeping flush so mlxd_open fails with ENXIO inside the window; flag cleared at detach_out since the controller keeps running) and adds an EBUSY recheck in mlxd_detach. The in-flight-bio leg additionally needs a drain (wait on mlx_waitbufs / outstanding commands) before disk_destroy \u2014 flagged in the diff comment as the complete fix. Cannot be build/boot validated: no Mylex hardware on the guest. Diff is git-apply-clean against sys/.",
  "fix_evidence": "fix.diff (git apply --check: APPLIES_CLEAN); hunks at mlx.c MLX_DETACH_DRIVE (SHUTDOWN set/clear) and mlx_disk.c mlxd_detach (thread2.h include + EBUSY recheck)"
}