DragonFlyBSD Kernel Audit
DF-2884 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2884",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "none",
  "confidence": "certain",
  "verdict": "kvsscanf's conversion switch (sys/kern/subr_scanf.c:148-253) has no default case, so an unsupported specifier (%f/%e/%g/%a/%z/typo) silently falls through: leading whitespace is consumed as a side effect, NO varargument is taken, and every subsequent conversion binds to a shifted argument -- %d then stores through the pointer meant for %f, and a following %s would write a string through a scalar pointer (caller-object overflow hazard). Proven in-kernel on the stock kernel via kvsscanf (E5: ksscanf-style '5' with '%f%d' returns ret=1, a=5, b=-1 -- %d wrote through &a, &b untouched); cc's own __scanflike(2,3) annotation on ksscanf rejects such formats at compile time (the PoC had to bypass it), confirming the specifier is unsanctioned, but runtime-built formats and unannotated wrappers reach the defect. No in-tree caller uses an unsupported specifier (21 sites surveyed) -- Info/hardening. fix.diff hunk 1 (default: goto match_failure, mirroring userland vfscanf) validated on kernel #1: ret=0, nothing written.",
  "exploit_chain": "none in-tree; for a hypothetical caller with a runtime-built fmt containing an unsupported specifier, later %s writes a NUL-terminated string through a non-buffer argument pointer",
  "evidence": [
    "run.log: \"dfpoc: E5 '5' %f%d: ret=1 a=5 b=-1\" + RESULT varargument list desynchronized REPRODUCED",
    "run.2.log: identical on second load",
    "run_patched.log: kernel #1 with fix.diff hunk 1 -- \"E5 '5' %f%d: ret=0 a=-1 b=-1\"",
    "build attempt record: cc rejects ksscanf(..., \"%f%d\", int*, int*) via __scanflike -- %f is not a supported kernel conversion"
  ],
  "kernel_refs": [
    "sys/kern/subr_scanf.c:148",
    "sys/kern/subr_scanf.c:253",
    "sys/kern/subr_scanf.c:258",
    "sys/kern/subr_scanf.c:283",
    "sys/sys/systm.h:240"
  ],
  "poc_changes": "authored fresh (no seed): experiment E5 of the shared dfpoc.ko KLD harness; called through an unannotated kvsscanf wrapper because the __scanflike(2,3) annotation on ksscanf rejects '%f' at compile time",
  "attempts": 2,
  "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": 2400,
  "guest_dirty": 0,
  "build_cmd": "cd /root/dfscanf && make   (fix validation: cd /usr/src && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC)",
  "run_cmd": "kldload /root/dfscanf/dfpoc.ko && sleep 1 && dmesg | tail -4",
  "code_hash": "0c3b123fc9ff001261befd22c3cdba2bce64a21495883ef913e4ab55413b5b3e",
  "notes": "hardening finding; userland vfscanf rejects unknown conversions (default: goto match_failure) -- hunk 1 aligns the kernel engine. In-tree callers all use supported specifiers only.",
  "recommended_fix": "add 'default: goto match_failure;' to the conversion switch at sys/kern/subr_scanf.c:252 (fix.diff hunk 1)",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Wed Sep  2 21:17:17 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff hunk 1 (default: goto match_failure) validated on kernel #1: the unknown-specifier format is rejected (ret=0) and no argument is written; all other experiments behave per their own fixes/controls.",
  "fix_evidence": [
    "run_patched.log: \"dfpoc: E5 '5' %f%d: ret=0 a=-1 b=-1\"",
    "run.log (baseline kernel #0): ret=1 a=5 b=-1",
    "fix.diff hunk 1"
  ]
}