⬢ DragonFlyBSD Kernel Audit
DF-3360 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3360",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "The OOB access is real, remotely triggerable, and compiled into the shipped pf.ko (objdump: movzwl 0x2(%r15)/mov %ax,0x2(%r15) with %r15==opts+38 possible and no guard), and 300,000 crafted malformed-MSS packets demonstrably executed the path (scrub rule evaluations climbed, guest stable). However, on this gcc80 -O2 INVARIANTS build opts[40..41] is an 8-byte alignment-padding slot at rbp-0x30 (no live local or saved register adjacent), so the 2-byte read/write cannot corrupt live state on the shipped binary. Defect: certain (disassembly + source proof). Runtime manifestation: none on this build; impact becomes live if a different compiler/-O level/KASAN-style layout places data at opts+40. Secondary oracle: th->th_sum is fixupd with stale-stack bytes and copied back, a 2-byte stale-stack oracle in transit packets.",
  "exploit_chain": "",
  "evidence": [
    "findings/poc/DF-3360/pf_normalize_tcpopt.dis (shipped pf.ko disassembly; opts at rbp-0x58, access at opts+40)",
    "findings/poc/DF-3360/disassembly-analysis.txt (frame layout proof)",
    "findings/poc/DF-3360/mss_oob.c (trigger: SYN, th_off=15, [38xNOP][0x02 0x02])",
    "rule evaluation counters 416k+ after 100k packets with scrub max-mss 64; 200k more with max-mss 1; guest stable both runs"
  ],
  "kernel_refs": [
    "sys/net/pf/pf_norm.c:1915",
    "sys/net/pf/pf_norm.c:1938-1946",
    "sys/netinet/tcp.h:148-149"
  ],
  "poc_changes": "Rewrote the seed-style sketch into a standalone raw-socket injector: fixed DFly-specific bits (ip_len must be in network order for raw IP, source must be a locally assigned address or sendto returns EADDRNOTAVAIL, pseudo-header checksum built manually for C89 declarations), options tile = 38xNOP + [TCPOPT_MAXSEG, len=2].",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64 (X86_64_GENERIC, INVARIANTS)",
  "runtime_sec": 240,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -o mss_oob mss_oob.c",
  "run_cmd": "pfctl -f mss.conf && pfctl -e && /root/poc/mss_oob 100000",
  "code_hash": "32b843a5b1352721ae1388f876ee0d85450e709345096b1279e18c34af133a7f",
  "notes": "scrub max-mss rule is a precondition (non-default config, common in practice). No uid0 path: this is a 2-byte stack OOB write whose value is rule-derived (htons(max_mss)) and whose position is fixed; on the shipped build it lands in padding. Recommended fix is a one-line optlen check.",
  "recommended_fix": "In pf_normalize_tcpopt() TCPOPT_MAXSEG case: if (optlen != TCPOLEN_MAXSEG) break;"
}