⬢ DragonFlyBSD Kernel Audit
DF-5814 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5814",
  "status": "untested",
  "reproduced": 0,
  "impact": "none",
  "confidence": "speculative",
  "verdict": "Analytical lifetime hole: on the failed-vget error path of vm_pageout_page()s OBJT_VNODE laundering branch (sys/vm/vm_pageout.c:1262-1266), the daemon holds only a page hold (which parks the vm_page on PQ_HOLD at teardown, sys/vm/vm_page.c:3199-3205) and \u2014 because the vget FAILED \u2014 no vnode reference. A concurrent vgone/vclean of that vnode (precisely the lock-holder that makes vgets LK_NOWAIT/LK_TIMELOCK fail) can complete object termination and free the vm_object before the object->flags & OBJ_MIGHTBEDIRTY load at :1265, making it a use-after-free READ of freed objcache memory. Impact is bounded to a possibly-wrong vnodes_skipped counter increment \u2014 no write primitive, no data returned to userspace \u2014 hence Low/speculative. Not run on the guest: the window is a few instructions and would require orchestrating a vnode reclaim inside it; per contract this Low-severity race is outside the mandatory verification set and a negative run would prove nothing.",
  "exploit_chain": "",
  "evidence": [
    "sys/vm/vm_pageout.c:1245-1268 \u2014 hold/wakeup/vget window and the unprotected object->flags read at :1265",
    "sys/vm/vm_object.c:746-866 \u2014 vm_object_terminate busy-waits pages, frees object after ref_count==0",
    "sys/vm/vm_page.c:3199-3205 \u2014 free_toq parks held pages on PQ_HOLD (page struct pinned, object NOT)",
    "findings/poc/DF-5814/README.md \u2014 full lifetime trace and why the successful-vget path at :1281 is safe",
    "findings/poc/DF-5814/fix.diff \u2014 sample OBJ_MIGHTBEDIRTY before the unbusy window (applies clean)"
  ],
  "kernel_refs": [
    "sys/vm/vm_pageout.c:1262",
    "sys/vm/vm_pageout.c:1265",
    "sys/vm/vm_object.c:746",
    "sys/vm/vm_page.c:3199"
  ],
  "poc_changes": "No runnable PoC authored: race window (instruction-level) x required interleaving (complete vnode reclaim) is not demonstrable on the single-tenant guest within budget; finding documented by source trace instead.",
  "attempts": 0,
  "guest_uname": "",
  "runtime_sec": 0,
  "guest_dirty": 0,
  "build_cmd": "",
  "run_cmd": "",
  "code_hash": "",
  "notes": "Sibling discipline note: vm_pageout_scan_holds documented vm_page_free/vm_page_unhold residue (the PQ_HOLD parking lot) is what makes the page-hold half of this window safe \u2014 the object half is the gap. Guest left clean.",
  "recommended_fix": "Hoist the OBJ_MIGHTBEDIRTY test above vm_page_wakeup(m) while the page busy still pins the object (fix.diff).",
  "fix_status": "not_applicable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Fix is a two-line hoist of a flags sample before the unbusy/vget window; validated by construction (no kernel rebuild for a speculative Low read-only race).",
  "fix_evidence": "findings/poc/DF-5814/fix.diff (git apply --check clean)."
}