{
  "finding_id": "DF-5629",
  "status": "reproduced",
  "verdict": "Unprivileged local kernel heap info leak: extract_interpreter() (sys/kern/imgact_elf.c:1817-1863) never NUL-terminates the kmallocd PT_INTERP payload, so uprintf(\"ELF interpreter %s not found\", interp) at imgact_elf.c:844 walks past the chunk and prints adjacent kernel heap bytes to the executing users tty. Reproduced 3/3 runs (deterministic 23 bytes/run: stale kernel M_TEMP strings such as tmp/df5629/make_interp2 and /tmp/df5629), plus an ungroomed 2-byte sample (ff ff). Reachable by any user via execve of a self-owned crafted ELF (OSABI=0 brands DragonFly via the interp/brand config wired in sys/cpu/x86_64/misc/elf_machdep.c:58-68). Fix validated on a rebuilt kernel: binary now ENOEXEC, 0 leak lines, no regression.",
  "reproduced": true,
  "impact": "leak",
  "confidence": "certain",
  "exploit_chain": "execve(crafted ELF with 1000-byte non-NUL PT_INTERP, uid 1001) -> brand match via EI_OSABI==ELFOSABI_NONE (imgact_elf.c:569-573) -> kmalloc(1000) unterminated (imgact_elf.c:668, 1817-1863) -> load_file(interp) fails -> uprintf %s walks past chunk (imgact_elf.c:844) -> stale heap bytes of the recycled kmalloc-1024 chunk (bytes 1000..1023 + neighbor run until NUL) printed to the users controlling terminal; leak length heap-layout dependent and groomable (setsockopt kmalloc+copyin groomer in pack).",
  "evidence": "run.log (size matrix 8 execs/size: size=1000 8/8 runs leaked, 184 bytes total; final 3 samples: extra=23 bytes each); leak_sample.txt + fline1-3.txt (hex of leaked bytes: kernel path strings); tty1.txt (raw transcript); VERDICT.md fix-validation section (patched kernel: 0 leak lines, ENOEXEC).",
  "kernel_refs": [
    "sys/kern/imgact_elf.c:1817",
    "sys/kern/imgact_elf.c:1838",
    "sys/kern/imgact_elf.c:844",
    "sys/kern/imgact_elf.c:663",
    "sys/kern/imgact_elf.c:569",
    "sys/cpu/x86_64/misc/elf_machdep.c:58",
    "sys/cpu/x86_64/misc/elf_machdep.c:63"
  ],
  "poc_changes": "Seed concept only; authored full builder+trigger from scratch: make_interp2.c parameterizes PT_INTERP payload size (empirical matrix found size=1000 gives deterministic leak: kmalloc(1000) leaves 24 stale in-chunk bytes); run_leak.c execve trigger run under script(1) so uprintf lands on a capturable pty; groom.c (setsockopt kmalloc+copyin at uipc_syscalls.c:1257) for heap seeding.",
  "attempts": 84,
  "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 (baseline) / #1 patched build Oct  8 23:30:36 UTC 2026",
  "runtime_sec": 900,
  "guest_dirty": 0,
  "build_cmd": "cc -O -o make_interp2 make_interp2.c && cc -O -o run_leak run_leak.c && ./make_interp2 final.bin 1000 128 && chmod 755 final.bin",
  "run_cmd": "su -m maxx -c script -q tty.txt ./run_leak ./final.bin 1; grep -ac ELF interpreter tty.txt  # expect >=1 with bytes after the 1000-byte payload",
  "code_hash": "873d4b71927a427ff54e3639a0b6f6dc02c048e03eb1c2c5edccae9cc6c7184d",
  "notes": "p_filesz must be <= min(PAGE_SIZE, MAXPATHLEN=1024) (imgact_elf.c:663-666); exact-1024 payloads usually leak 0 visible bytes (neighbor first byte tends to 0x00) - size=1000 is the deterministic configuration. KLD not needed for this finding.",
  "recommended_fix": "extract_interpreter(): reject PT_INTERP payloads that are not NUL-terminated within p_filesz before returning success (see fix.diff).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Patched kernel (nativekernel rebuild with fix.diff, kernel #1): same binary -> ENOEXEC, 0 ELF interpreter lines on the pty (baseline: 1 line + 23 leaked heap bytes); normal NUL-terminated interpreters unaffected (system boots/runs).",
  "fix_evidence": "run.log DF-5629 fix validation section; VERDICT.md; fix.diff in pack."
}