⬢ DragonFlyBSD Kernel Audit
DF-3747 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3747",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "sccngetch() (sys/dev/misc/syscons/syscons.c:2004-2057) passes (size_t *)&fkeycp to kbd_get_fkeystr; genkbd_get_fkeystr (kbd.c:1123) executes an 8-byte size_t store into the 4-byte static int \u2014 a genuine 4-byte OOB write proven emitted in the shipped kernel binary (genkbd_get_fkeystr+0x4c mov %rax,(%r12); nm: fkeycp.13185 @0xffffffff817a6da0, next symbol fkey.13184 @+0x10, so the stray bytes land in alignment padding on this build). The same code then copies kb_fkeytab[].len bytes into the 17-byte static fkey without clamping (sccngetch+0x228 callq memmove(&fkey.str,p,len)) \u2014 with DF-1503s corruptible len (up to 255) that is up to 238 bytes of overflow past a kernel .bss static. Runtime path is the kernel-console cngetc function-key read (DDB/boot prompt); the guests active console is sio0 (serial) with no keyboard, so the kernel sink cannot be triggered here \u2014 defect/codegen/layout are instead proven from /boot/kernel/kernel plus an executed verbatim userland replica (build.log/run.log; GCC itself flags the replicated OOB copy).",
  "exploit_chain": "physical-console user enters DDB via Ctrl-Alt-Esc (no privilege) and presses a function key -> genkbd_get_fkeystr 8-byte store at &fkeycp (4 OOB zero bytes, layout-dependent victim); combined with DF-1503 (SETFKEY-corrupted len=255 via inherited tty fd): bcopy of up to 255 attacker bytes into static fkey.str[16] -> up to 238-byte overflow of adjacent kernel .bss statics -> best-case panic-on-next-use; weaponization marginal given DDB/boot context",
  "evidence": "disasm.txt (objdump of genkbd_get_fkeystr+0x4c and sccngetch+0x228 from the shipped kernel), run.log (nm layout fkeycp.13185/fkey.13184 + harness sections [1] OOB-zero bytes and [2] 239-byte overflow), build.log (GCC -Warray-bounds on the replica), VERDICT.md",
  "kernel_refs": [
    "sys/dev/misc/syscons/syscons.c:2004",
    "sys/dev/misc/syscons/syscons.c:2005",
    "sys/dev/misc/syscons/syscons.c:2054",
    "sys/dev/misc/syscons/syscons.c:2055",
    "sys/dev/misc/syscons/syscons.c:2057",
    "sys/dev/misc/kbd/kbd.c:1110",
    "sys/dev/misc/kbd/kbd.c:1123",
    "sys/sys/kbio.h:219"
  ],
  "poc_changes": "no seed PoC; harness written from scratch: canary-guarded static-layout model of sccngetchs statics performing the exact stores. Initial pun demo was optimized to 32 bits in-TU (matching no byte changes); fixed with a volatile pun to reproduce the kernels cross-TU 8-byte codegen, and fixed the [1] probe to scan &fkeycp+4..+8",
  "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": 40,
  "guest_dirty": 0,
  "build_cmd": "./build.sh (cc -O -Wall -o pun_harness pun_harness.c)",
  "run_cmd": "./run.sh (harness + nm/objdump of /boot/kernel/kernel)",
  "code_hash": "e6289a91d6836d24135b695e03ebfbbad5d29a67f0b30eb4da55d4e1aff5b7ff",
  "notes": "Negative-control work this run: VT_WAITACTIVE wedge hypothesis (tsleep at syscons.c:1355 holding vga_token) was REFUTED live on this guest \u2014 a VT_GETACTIVE probe from a second process completed instantly while the sleeper sat in wchan waitvt, because DragonFly LWKT releases a threads tokens when it blocks (sys/kern/lwkt_token.c:40). Guest cleaned (/tmp files removed, wedge process killed).",
  "recommended_fix": "make fkeycp a size_t and clamp the fkeytab length to sizeof(fkey.str) before bcopy (fix.diff)",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff authored after binary-level verification (size_t fkeycp + clamp); cannot be kernel-build-validated on this guest because the sink (kernel-console cngetc with a function key) cannot be exercised at runtime (active console is sio0, no keyboard, enable_panic_key=0)",
  "fix_evidence": "fix.diff (unified, against read-only sys/ tree; never applied)"
}