⬢ DragonFlyBSD Kernel Audit
DF-3485 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3485",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Deterministic kernel panic on the first ng_iface (v1 netgraph) node creation: ng_iface_get_unit() passes the initially-NULL ng_iface_units pointer to bcopy(), which sys/sys/systm.h:257-265 maps onto __builtin_memmove() with the documented consequence that GCC assumes the pointer non-NULL and deletes the later if (ng_iface_units != NULL) guard, so the compiled module executes kfree(NULL) -> panic(\"trying to free NULL pointer\") (kern_slaballoc.c:1406-1407). Proven by live reproduction (3/3 boots, plain root ngctl mkpeer), by disassembly of both the shipped and freshly rebuilt modules (unguarded call, relocations identify _kfree/M_NETGRAPH), and by DWARF line mapping of the panic return address. Root-only reachability (ng_socket.c:172 caps_priv_check); no memory corruption; Low severity. fix.diff guards the bcopy itself; validated: machine-code guard present, the free-NULL panic disappears (creation then reaches the independent DF-3486 defect; with both fixes the full lifecycle works).",
  "exploit_chain": "",
  "evidence": "panic.txt (stock trace, ng_iface_constructor+0x3a2); disasm.stock.txt (unguarded kfree with relocations) vs disasm.fixed.txt (test/je guard); panic.after_fix.txt (panic signature changes -> defect eliminated); findings/poc/DF-3486/fix_run.log (full lifecycle with both fixes); unpriv_check.log (EPERM for uid 1001)",
  "kernel_refs": [
    "sys/netgraph/iface/ng_iface.c:290",
    "sys/netgraph/iface/ng_iface.c:294",
    "sys/netgraph/iface/ng_iface.c:295",
    "sys/sys/systm.h:257",
    "sys/kern/kern_slaballoc.c:1406",
    "sys/netgraph/netgraph/ng_base.c:371",
    "sys/netgraph/socket/ng_socket.c:172"
  ],
  "poc_changes": "none needed \u2014 plain ngctl reproduces on the stock kernel; trigger is 3 lines",
  "attempts": 3,
  "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": 420,
  "guest_dirty": 0,
  "build_cmd": "cd /usr/src && patch -p1 < fix.diff && cd sys/netgraph/iface && make",
  "run_cmd": "kldload ng_socket ng_iface && ngctl mkpeer . iface inet inet   (root)",
  "code_hash": "ef76ec1dcf65bba8d0f9e2f51d2d5e7c00eabd5c82196894bec6fb367a645c5e",
  "notes": "Root-only trigger (verified EPERM as uid 1001). Unconditional panic (not INVARIANTS-gated) \u2014 production kernels affected. The DF-3482 leads claim that ng_eiface panics with the same free-NULL signature was a truncation artifact; ng_eifaces real panic is DF-3486. Residual: ng_iface_units bitmap remains unsynchronized (creation is serialized on the netisr control path today).",
  "recommended_fix": "Guard the bcopy itself: move it (and the kfree) inside the existing if (ng_iface_units != NULL) so no potentially-NULL pointer is ever passed to __builtin_memmove (see fix.diff).",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 (stock kernel; fix applied as module rebuild only)",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Single-fix module validated: disasm.fixed.txt shows a real test/je guarding bcopy+kfree, and the trying to free NULL pointer panic no longer occurs on the trigger. The remaining panic seen with only this fix is the independent DF-3486 defect (if_attach from netisr, ng_iface.c:605), whose own fix is validated in findings/poc/DF-3486 (with both fixes: ng0 created/listed/shutdown cleanly, 22+ create-destroy cycles, no panic).",
  "fix_evidence": "disasm.fixed.txt; panic.after_fix.txt; findings/poc/DF-3486/fix_run.log"
}