⬢ DragonFlyBSD Kernel Audit
DF-3267 / verdict.json
← back to finding ↓ download raw
{
 "finding_id": "DF-3267",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "panic",
 "confidence": "certain",
 "verdict": "DIOCCHANGEADDR with PF_CHANGE_REMOVE of the only pool address of an active nat rule panics immediately: pool->cur = TAILQ_FIRST(&pool->list) is NULL after the removal and the very next PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, ...) dereferences it - live: Fatal user address access from kernel mode from rmpool, Fatal trap 12 page fault, fault virtual address 0x0, in the ioctl path. The same NULL rpool->cur would later be dereferenced unguarded on the packet path by pf_map_addr (pf.c:2693-2712) and pf_set_rt_ifp (pf.c:3642/3649) once the ioctl line is guarded, so the fix covers both sides (refuse to empty a live pool + NULL guard in pf_map_addr). Root-triggered panic today, defense-in-depth for the remote path.",
 "exploit_chain": "",
 "evidence": "panic.txt (trap 12, fault address 0x0, from rmpool), rmpool.c (DIOCGETRULES ticket + DIOCCHANGEADDR dance), run.log",
 "kernel_refs": [
  "sys/net/pf/pf_ioctl.c:2330-2333",
  "sys/net/pf/pf.c:2693-2712",
  "sys/net/pf/pf.c:3642-3649"
 ],
 "poc_changes": "include path is <net/pf/pfvar.h> on this tree and needs <net/if.h> first for IFNAMSIZ; PF_CHANGE_REMOVE = 5, PF_NAT = 4 per the pfvar enums",
 "attempts": 1,
 "guest_uname": "DragonFly dfbsd 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": 60,
 "guest_dirty": 0,
 "build_cmd": "guest: cc -O -o rmpool rmpool.c (uses <net/pf/pfvar.h>)",
 "run_cmd": "guest: kldload pf; pfctl -f nat.conf (nat on lo0 ... -> 1.2.3.4); ./rmpool",
 "code_hash": "e8b8a1c3f1506ea1dec9cf5f149a19fd3a2a2864b045209594eab763c434d590",
 "notes": "",
 "recommended_fix": "refuse removal of the last pool address + NULL guard in pf_map_addr; the ioctl-side guard makes the same call return EINVAL"
}