⬢ DragonFlyBSD Kernel Audit
DF-3444 / verdict.json
← back to finding ↓ download raw
{
 "finding_id": "DF-3444",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "panic",
 "confidence": "certain",
 "verdict": "REPRODUCED on stock 6.5-DEVELOPMENT #0 (INVARIANTS): an ipfw3 rule with an O_LAYER4_BPF instruction executes its embedded BPF program with zero validation (ip_fw3.c:655 verbatim bcopy; check_bpf ip_fw3_layer4.c:201 calls bpf_filter directly). Demonstrated: (1) zero-length program walks kernel memory as endless BPF_LD|BPF_IMM until unmapped page (panic bpf_filter+0x50); (2) BPF_ST with k=0x08000000 writes a controlled u32 at mem+512MB (panic exactly at the store, bpf_filter+0x4d3, mov %eax,-0x60(%rbp,%rdx,4), edx=pc->k unchecked); (3) BPF_ST k=26/27 overwrites bpf_filters saved return address -> CPU jumps to the exact attacker value 0x414142424343 (Stopped at 0x414142424343). FIX VALIDATED on single-fix kernel #1 (fix.diff: BPF_MEMWORDS runtime bounds in bpf_filter.c:365-379 + bpf_validate gate in check_bpf): identical ladder survives, no panic, networking healthy. Unpriv->uid0 is blocked by the entry gate (raw IP socket requires SYSCAP_NONET_RAW, sys/netinet/raw_ip.c:473) - same accepted hard blocker as DF-2580 on this surface; for a root attacker the demonstrated RIP control is full ring-0 code execution on this no-SMEP/no-KASLR guest.",
 "exploit_chain": "root: socket(AF_INET,SOCK_RAW,IPPROTO_RAW) -> setsockopt(IPPROTO_IP, IP_FW_X=49, {opcode=50 IP_FW_ADD, rule{cmd_len, cmd=ipfw_insn{module=3,opcode=4 O_LAYER4_BPF}+bf_str+bf_len+bf_insn[]}}) -> add_rule_dispatch bcopy (no validation) -> packet -> pfil -> ip_fw3_check -> filter_funcs[3][4]=check_bpf -> bpf_filter(bf_insn) -> BPF_LD|BPF_IMM (A=value) + BPF_ST k=26/27 -> saved RIP = value -> retq jumps to attacker address. Value fully controlled per 32-bit half; repeatable per packet; multiple STs per program (up to ~14 insns per bpf cmd, multiple cmds/rules). BPF_LD|BPF_MEM with arbitrary k is the matching read. uid0-from-unprivileged: blocked (no raw socket without SYSCAP_NONET_RAW).",
 "evidence": [
  "panic.txt: three deterministic panic signatures (bpf_filter+0x50 walk; bpf_filter+0x4d3 store with rip=ffffffff8072b0e3; Stopped at 0x414142424343)",
  "run.log: baseline ladder (safe survives; empty/store/riptake panic)",
  "fix_run.log: identical ladder on patched #1 kernel - all survive, ping 0.218ms",
  "fix_build.log: full nativekernel build log (BUILD-RC=0)",
  "VERDICT.md: full narrative incl. objdump frame math (mem at rbp-0x60 via rep stos at bpf_filter+0x1d; ST compiles to mov %eax,-0x60(%rbp,%rdx,4))"
 ],
 "kernel_refs": [
  "sys/net/bpf_filter.c:365",
  "sys/net/bpf_filter.c:366",
  "sys/net/bpf_filter.c:370",
  "sys/net/bpf_filter.c:374",
  "sys/net/bpf_filter.c:378",
  "sys/net/bpf_filter.c:498",
  "sys/net/ipfw3_layer4/ip_fw3_layer4.c:201",
  "sys/net/ipfw3/ip_fw3.c:655",
  "sys/net/ipfw3/ip_fw3.c:951",
  "sys/net/ipfw3/ip_fw3.c:506",
  "sys/net/bpf.c:1076",
  "sys/netgraph/bpf/ng_bpf.c:481",
  "sys/netinet/raw_ip.c:473"
 ],
 "poc_changes": "PoC authored fresh (no seed): raw-socket IP_FW_X=49/opcode-50 rule builder mirroring kernel structs (ipfw_ioc_rule, ipfw_insn{module=3,opcode=4}, ipfw_insn_bpf with bf_insn at +140). Fixed two self-inflicted PoC bugs found during bring-up: program was emitted before the payload memset (produced an accidental all-zeros program - itself a valid repro of the no-termination facet), and the empty mode initially still emitted a trailing RET.",
 "attempts": 6,
 "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": 5400,
 "guest_dirty": 0,
 "build_cmd": "cc -O -o poc3444 poc.c",
 "run_cmd": "./poc3444 empty; ./poc3444 store 0xcafebabe 0x08000000; ./poc3444 riptake 0x42424343 0x00004141",
 "code_hash": "9e70947456866bc26955b2f3f5b11c43623347c2e0650b6bda0ef03930f90aa5",
 "notes": "Also demonstrated in passing: unvalidated programs need not terminate (empty mode). ipfw3_layer4.ko must be loaded (kldload). Compliant bpf_validate callers (bpf.c:1076, ng_bpf) unaffected by the runtime guard. DF-0472/DF-0473 cover ip_fw3.c cmd_len/filter_funcs indexing separately; this finding is the unvalidated-execution path in bpf_filter.c itself.",
 "recommended_fix": "bpf_filter.c: runtime if (pc->k >= BPF_MEMWORDS) return 0; in LD|MEM/LDX|MEM/ST/STX; plus bpf_validate(bf_insn, bf_len) gate in ipfw3_layer4 check_bpf (see fix.diff)",
 "fix_status": "fixed",
 "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sat Sep 12 21:38:29 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "Patched kernel #1 built with fix.diff (nativekernel, fix_build.log BUILD-RC=0): all three panic modes gone, packets flow, ssh alive. Baseline #0 panicked deterministically on every mode.",
 "fix_evidence": "fix_run.log, fix_build.log"
}