⬢ DragonFlyBSD Kernel Audit
DF-5718 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5718",
  "status": "reproduced",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Info/hardening finding from the pass-2 census of sys/libkern/strcpy.c: the netgraph text parser calls strcpy() on overlapping src/dst (ng_parse.c:1572 strcpy(p,p+1), :1621 strcpy(p,v); netgraph7 ng_parse.c:1764/1813), violating the __restrict contract both prototypes declare (sys/sys/libkern.h:131). Runtime proof: the verbatim kernel algorithm executed with the verbatim in-tree strcpy counts 5 overlapping invocations in a single parse and parses correctly (rig_intree). A block-store strcpy model (vectorized implementations store the final partial block whole, i.e. write past the NUL) applied to the exact kernel allocation (kmalloc(strlen(s+start)) with no +1, ng_parse.c:1559) SIGSEGVs on a guard page - i.e. an implementation-plausible strcpy swap turns this into a kernel heap OOB write (rig_block). DFlys own libc strcpy is byte-forward, so rig_libc (the swap control) shows no divergence on this platform, and the input path is root-gated (caps_priv_check SYSCAP_RESTRICTEDROOT, ng_socket.c:171-175): no unprivileged-reachable bug exists in the shipped kernel. The memmove treatment (fix.diff) is byte-identical (rig_fixed). gcc 8.3 -Wrestrict does not diagnose the call sites (wrestrict_shim.c).",
  "exploit_chain": "",
  "evidence": "findings/poc/DF-5718/run.log: INTREE: overlapping strcpy invocations ... : 5; BLOCK : child killed by SIGSEGV ... => equivalent to a kernel heap OOB write; FIXED : memmove treatment output identical to in-tree semantics: YES; env.txt for guest/toolchain; VERDICT.md for the full narrative",
  "kernel_refs": [
    "sys/libkern/strcpy.c:36",
    "sys/sys/libkern.h:131",
    "sys/netgraph/netgraph/ng_parse.c:1559",
    "sys/netgraph/netgraph/ng_parse.c:1572",
    "sys/netgraph/netgraph/ng_parse.c:1621",
    "sys/netgraph7/netgraph/ng_parse.c:1764",
    "sys/netgraph7/netgraph/ng_parse.c:1813",
    "sys/netgraph/socket/ng_socket.c:171",
    "sys/dev/raid/hptrr/osm.h:168"
  ],
  "poc_changes": "The seed had no PoC; authored from scratch. The rig embeds the VERBATIM ng_get_string_token algorithm and the VERBATIM in-tree strcpy; three iterations were needed: (1) nested block-comment syntax error; (2) non-numeric MODE preprocessor tokens enabled all arms at once; (3) initial expected string was wrong because the kernels hex-escape loop never increments k (consumes ALL consecutive hex digits, ng_parse.c:1601-1616) - fixed expected to the real kernel semantics and fixed the overlap counters range check. Added MODE_FIXED (fix.diff treatment) and a hexdump printer so invisible bytes are visible.",
  "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": 640,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh  (cc -O2 -fno-builtin -DMODE=1 -o rig_intree overlap_rig.c; cc -O2 -DMODE=2 -o rig_libc overlap_rig.c; cc -O2 -DMODE=3 -o rig_block overlap_rig.c; cc -O2 -DMODE=4 -o rig_fixed overlap_rig.c; cc -O2 -Wall -Wrestrict -c wrestrict_shim.c)",
  "run_cmd": "sh run.sh  (./rig_intree; ./rig_libc; ./rig_block; ./rig_fixed)",
  "code_hash": "958cb664b43bb039f0319e2132f30f1df27b666cda02ed6884de452211e658e6",
  "notes": "Batch pass-2 audit of sys/libkern/{skpc,strcat,strcpy}.c; this is the sole finding of the batch (Info). skpc.c verified byte-identical to FreeBSDs reference implementation (freebsd-src release/9.3.0 sys/libkern/skpc.c, fetched during this run) with zero in-tree callers; strcat.c census found all consumers literal/bounded/root-gated. Adjacent non-finding observations recorded in VERDICT.md: ng_parse hex/octal escape loops never increment k (semantics quirk, bounded, FreeBSD-inherited); ng_parse.c:1559 alloc has zero slack for past-NUL-writing strcpy variants (demonstrated by rig_block). Guest untouched except /tmp scratch (cleaned); no panic; no kernel rebuild needed for an Info finding.",
  "recommended_fix": "Replace the four overlapping strcpy calls with overlap-safe memmove in both netgraph stacks (see fix.diff): memmove(p, p+1, strlen(p+1)+1) and memmove(p, v, strlen(v)+1).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": null,
  "fix_verdict": "fix.diff authored (netgraph + netgraph7, strcpy->memmove at the four overlap sites) and validated at the algorithm level: rig_fixed produces byte-identical parser output to the in-tree semantics (run.log). A full patched-kernel build/reboot validation was not performed because the finding is Info/hardening with no kernel-reachable defect to baseline (input path is root-gated by caps_priv_check SYSCAP_RESTRICTEDROOT); recorded as not_testable at the kernel level.",
  "fix_evidence": "findings/poc/DF-5718/run.log line FIXED  : memmove treatment output identical to in-tree semantics: YES; fix.diff"
}