DragonFlyBSD Kernel Audit
DF-2786 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2786",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Source-proven stale-state race in mtx_delete_link/mtx_abort_link: mtx_delete_link (sys/kern/kern_mutex.c:914-941) unlinks the victim but never terminates link->state \u2014 the MTX_LINK_LINKED_EX/SH value survives until mtx_wait_link resets it to MTX_LINK_IDLE at :1023 OUTSIDE MTX_LINKSPIN. An mtx_abort_link that acquires LINKSPIN in that window reads the stale LINKED state and executes the de-link writes (:1095-1096/:1126-1127) through the victim's dangling next/prev \u2014 a use-after-free write into former neighbors (freed/reused nfsreq r_link in the only in-tree caller) and live wait-queue poisoning. Runtime: NOT reproduced on the 6-vCPU KVM INVARIANTS guest despite ~16.2M mtx_abort_link calls, ~6.8M delete-path exits and 116k measured abort-vs-exit window overlaps across three harness geometries plus controls \u2014 on this guest the owner's 3-instruction head start from the LINKSPIN release (:939) to the IDLE store (:1023) always wins the cache-line race, so the misfire requires owner preemption inside that tail (plausible under heavier interrupt/preemption load on busier machines). Four earlier hard-freeze artifacts were forensically attributed (QEMU monitor + per-vCPU RIP symbolization) to harness self-starvation \u2014 my own bug, disclosed in VERDICT.md \u00a73, not kernel corruption. The finding stands on the airtight interleaving proof (no fence or lock excludes it) at Medium/likely; a 2-line fix (terminate state under LINKSPIN) was authored, built into a full kernel (nativekernel, -Werror), booted (kernel #1), and shown regression-free under the same storms.",
  "exploit_chain": "",
  "evidence": "findings/poc/DF-2786/VERDICT.md (full narrative incl. freeze forensics and honest negative); run.log (control SUMMARY CORRUPT=0 @ 4.66M scans; v5-real SUMMARY 16.06M aborts / 115,662 overlaps / CORRUPT=0; v6-real SUMMARY 134,726 delete-exits / CORRUPT=0; post-fix SUMMARY CORRUPT=0 on kernel #1); mtx_abuse.c (v6 harness with zero-false-positive retired-link scanner); fix.diff (applied cleanly, kern_mutex.c recompiled at build log line 7528, KERN_DONE); build.log, env.txt (both kernel unames)",
  "kernel_refs": [
    "sys/kern/kern_mutex.c:914",
    "sys/kern/kern_mutex.c:939",
    "sys/kern/kern_mutex.c:1010",
    "sys/kern/kern_mutex.c:1023",
    "sys/kern/kern_mutex.c:1082",
    "sys/kern/kern_mutex.c:1095",
    "sys/kern/kern_mutex.c:1113",
    "sys/kern/kern_mutex.c:1126",
    "sys/vfs/nfs/nfs_socket.c:1311",
    "sys/vfs/nfs/nfs_socket.c:2050",
    "sys/vfs/nfs/nfs_socket.c:2184"
  ],
  "poc_changes": "Five harness generations, all documented in VERDICT.md: v1/v2 (non-canonical then text-pointer poison + refcount + spinlock-protected target table) \u2014 their 4 'freezes' were proven by QEMU-monitor RIP forensics + a noabort control to be harness thread starvation (6 busy-spinning kthreads), not kernel bugs; v3 removed the starvation (yield/sleep discipline), control ran 90s stable; v5 removed all harness locking/allocation (static double-buffered links, retired forever, atomic publish) + scanner thread for zero-false-positive detection of writes into retired links; v6 added long-hold holders for batched-timeout delete geometry. Deterministic detection (kernel write into a retired link's next/prev) never fired: the misfire window is architecturally fortified on this guest.",
  "attempts": 7,
  "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: Tue Sep 1 08:01:25 UTC 2026 (patched, fix-validated)",
  "runtime_sec": 4200,
  "guest_dirty": 0,
  "build_cmd": "cd /usr/src/sys/modules/mtxabuse && env MAKESYSPATH=/usr/src/share/mk SYSDIR=/usr/src/sys make",
  "run_cmd": "kenv mtxabuse.duration=300; kldload /root/mtxabuse.ko (control: kenv mtxabuse.noabort=1)",
  "code_hash": "0ed94f9aad6a97b27e9c7cc6074b21ee3e5ee6424aae23d2c5337426f2d8b2b1",
  "notes": "Distinct from DF-0047 (owner-vs-grant lock leak in the same window; DF-2786 is aborter-vs-owner stale de-link writes). DF-0047 never fired either in these workloads (df47=0 everywhere) \u2014 both windows are narrow on this hardware. Recommended severity Medium (UAF-write race, NFS-reachable via nfs_rcvlock PCATCH exits vs nfs_hardterm aborts; realistic impact DoS/panic, theoretical escalation via M_NFSREQ reuse). Cross-check of every other kern_mutex.c interleaving (grant-vs-abort LINKSPIN serialization, EXWANTED/SHWANTED bit accounting, tsleep interlock protocol, chain_ex/sh count arithmetic, downgrade/upgrade, spinlock pairings, crit enter/exit balance) found no further defects; see finding negative notes.",
  "recommended_fix": "mtx_delete_link(): set link->state = MTX_LINK_IDLE in the MTX_LINK_LINKED_EX/SH cases before releasing MTX_LINKSPIN so a racing mtx_abort_link can never act on the stale LINKED state of an already-unlinked link",
  "fix_status": "inconclusive",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Tue Sep  1 08:01:25 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff (2-line state termination under LINKSPIN) applies cleanly to /usr/src, full nativekernel build succeeded (-Werror, kern_mutex.c recompiled), installed and booted as kernel #1, and the identical v6 storm ran 150s regression-free (58,784 aborts / 66,313 delete-exits / 75 overlaps / CORRUPT=0, mutex machinery fully functional). Inconclusive only because the baseline never manifested the corruption, so suppression cannot be diffed; correctness is by construction (state can no longer be stale-LINKED once unlinked).",
  "fix_evidence": "env.txt (both unames, kern_mutex.c compile line, 'Kernel install completed' + KERN_DONE); run.log tail (post-fix SUMMARY on kernel #1); fix.diff"
}