⬢ DragonFlyBSD Kernel Audit
DF-3519 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3519",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "NOT REPRODUCED (vector-blocked), code-certain: ng_pptpgre_start_recv_ack_timer() and ng_pptpgre_start_send_ack_timer() do plain non-atomic node->refs++ (ng_pptpgre.c:768, :871) racing ng_unref()s plain --node->refs (ng_base.c:474-485, crit-enter protects the current CPU only) and plain priv->timers++/-- across contexts. A lost RMW update undercounts refs, freeing struct ng_node while the armed timers callback still dereferences it (recv/send_ack_timeout :802/:906) and while ng_unrefs LIST_REMOVE corrupts the global node hash lists - UAF on the node object. DF-0492s refcount also racy instantiated for ng_pptpgre; not covered by DF-0596 (xmitWin/timeSent scope). Instruction-level window requires concurrent timer start/stop on multiple CPUs, unreachable from userspace ng_socket (CPU-0 netisr serialization, DF-0590 empirical).",
  "exploit_chain": "",
  "evidence": "VERDICT.md code trace (ng_pptpgre.c:768-769/:871-872 vs ng_base.c:474-485, callbacks :811/:915/:802/:906); no runnable vector on this guest - documented rather than burning a run that can only reproduce the known serialization negative",
  "kernel_refs": [
    "sys/netgraph/pptpgre/ng_pptpgre.c:768",
    "sys/netgraph/pptpgre/ng_pptpgre.c:769",
    "sys/netgraph/pptpgre/ng_pptpgre.c:871",
    "sys/netgraph/pptpgre/ng_pptpgre.c:872",
    "sys/netgraph/netgraph/ng_base.c:474",
    "sys/netgraph/pptpgre/ng_pptpgre.c:802"
  ],
  "poc_changes": "No binary PoC authored: the only userspace vector (ng_socket) is serialized on CPU 0 by construction; DF-3518s 52k-lifecycle hammer already re-confirmed the blocker on this node type this run.",
  "attempts": 0,
  "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": 0,
  "guest_dirty": 0,
  "build_cmd": "",
  "run_cmd": "",
  "code_hash": "",
  "notes": "Double-free direction analyzed and killed: priv cannot be double-freed via timers accounting because ng_pptpgre_rmnodes reset uses synchronous callout_stop before checking timers==0 (callbacks cannot still be in flight). Only the undercount direction (premature node free) survives analysis.",
  "recommended_fix": "Use NG_NODE_REF(node) (atomic_add_int, netgraph.h:132) at both start sites and atomic_add_int for priv->timers; better, add the per-node serialization lock (also fixes DF-0590/DF-3518 class).",
  "fix_status": "not_testable"
}