⬢ DragonFlyBSD Kernel Audit
DF-5698 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5698",
  "status": "reproduced",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Kernel inet_ntop (sys/libkern/inet_ntop.c) never sets errno on any failure path, breaking the contract its own doc-comment states (NULL (see errno), inet_ntop.c:38-39) and diverging from its algorithm-identical libc twin (lib/libc/inet/inet_ntop.c sets EAFNOSUPPORT at :62 and ENOSPC at :88,:169,:187). Demonstrated deterministically: rig P6 and fixcheck probes show errno=0 after both too-small-dst and bad-af failures on the baseline TU, and ENOSPC/EAFNOSUPPORT on the fixed TU. No security impact in-tree: all 12 kernel call sites (ip_icmp.c) pass correctly sized INET_ADDRSTRLEN buffers, none reads errno, and kprintf renders NULL %s as (null) (subr_prf.c:750-753). Alongside this divergence, the same rig proved the formatter memory-safe over ~200M comparisons: string output and accept/reject decisions identical to libc at every buffer size (0..16 v4, 0..46 v6), zero faults in 1.4M guard-page knife-edge calls with dst[size] on PROT_NONE pages (incl. zero-writable-byte size==0 dsts).",
  "exploit_chain": "",
  "evidence": "findings/poc/DF-5698/run.log decisive lines: P6: size-too-small kernel-returns=0x0 errno-after=0 and variant=BASELINE ... errno=0(NOT-SET) ... BASE_RC=1 vs variant=FIXED ... errno=28(ENOSPC) ... errno=47(EAFNOSUPPORT) FIXED_RC=0; memory-safety proof: P7: guardpage calls=500000 accepted=200000 (no SIGSEGV) + TOTAL=27889126 MISMATCH=0 (pack run) and run.2.log/run.3.log (MISMATCH=0, 61.4M/25.9M comparisons); fix validation fix_run.log + fix_build.log; VERDICT.md has the full boundary-math derivation (tp-tmp includes the NUL at :169 before the :174 gate).",
  "kernel_refs": [
    "sys/libkern/inet_ntop.c:38",
    "sys/libkern/inet_ntop.c:51-52",
    "sys/libkern/inet_ntop.c:76-78",
    "sys/libkern/inet_ntop.c:158-159",
    "sys/libkern/inet_ntop.c:169",
    "sys/libkern/inet_ntop.c:174-177",
    "lib/libc/inet/inet_ntop.c:62",
    "lib/libc/inet/inet_ntop.c:88",
    "lib/libc/inet/inet_ntop.c:169",
    "lib/libc/inet/inet_ntop.c:187",
    "sys/netinet/ip_icmp.c:295",
    "sys/kern/subr_prf.c:750-753"
  ],
  "poc_changes": "No seed PoC existed (pass-1 filed nothing). The whole rig was authored in this run: harness.c (7-phase differential vs DragonFly libc), fixcheck.c (errno probe), userland shims for the kernel TU, inet_ntop_fixed.c (fix validation TU generated from the audited sys/ copy). Rig bugs fixed during iteration: guest root shell is csh (all remote logic moved into sh scripts), scp transport replaced by base64-over-ssh after flaky connection closes, guard-page allocator initially leaked mappings (munmap added), P5 af-list initially assumed Linux AF values (DragonFly: AF_INET=2, AF_INET6=28) - assertion changed to kernel-vs-libc decision equality.",
  "attempts": 4,
  "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": 160,
  "guest_dirty": 0,
  "build_cmd": "sh findings/poc/DF-5698/build.sh",
  "run_cmd": "sh findings/poc/DF-5698/run.sh 3000000 991199",
  "code_hash": "c370111fc9d6004e5fceaef902a300f10d36b56010c6baad6ba1f34e5fc870e6",
  "notes": "Kernel TU sha256 6ddc914991203a5f4e54544a8d8c511790e0428e3400cf376d2ad49d87 verified identical between audited tree and guest /usr/src copy used for the build. Guest gcc 8.3 [DragonFly]; base gcc lacks -lasan/-lubsan (ASan build impossible on guest) - the guard-page canary provides equivalent deterministic overflow detection for this bounded-strcpy sink. Cumulative differential volume ~200M comparisons across 4 runs, 3 seeds: MISMATCH=0 everywhere; inet_pton round-trip clean. Only /tmp/ntop used on guest; no kernel changes; guest left up and clean.",
  "recommended_fix": "Add errno = EAFNOSUPPORT (default af case) and errno = ENOSPC (all three size-gate rejects) to sys/libkern/inet_ntop.c, matching the libc twin; see fix.diff.",
  "fix_status": "fixed",
  "fix_kernel_uname": "n/a (userland differential rig against the fixed TU; errno divergence requires no kernel rebuild to validate)",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff (git apply --check clean) implements the errno contract: baseline TU leaves errno=0 on both failure modes (fixcheck BASE_RC=1); patched TU sets ENOSPC/EAFNOSUPPORT (FIXED_RC=0) and re-passes the full differential with MISMATCH=0 (run.3.log FIXED_DIFF_RC=0), i.e. formatting behavior unchanged.",
  "fix_evidence": "findings/poc/DF-5698/fix_run.log: variant=BASELINE ... errno=0(NOT-SET) BASE_RC=1 vs variant=FIXED ... errno=28(ENOSPC) ... errno=47(EAFNOSUPPORT) FIXED_RC=0; run.3.log: FIXED_DIFF_RC=0 (23,889,126 comparisons, MISMATCH=0); fix.diff; fix_build.log (FIXED_TU_BUILD_OK)."
}