⬢ DragonFlyBSD Kernel Audit
DF-5630 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5630",
  "status": "reproduced",
  "verdict": "Unprivileged-triggerable 4-byte OOB read: note_overflow() (imgact_elf.c:1700-1707) bounds only n_namesz, but bsd_trans_osrel() (imgact_elf.c:1866-1875) reads the 4-byte descriptor at note+24 of any note whose header matches the DragonFly brandnote {10,4,1,DragonFly} bound into the exec path at elf_machdep.c:66-67. A note truncated right after the vendor name (22 bytes) at the end of the first page makes the kernel read image_header[4096..4099] - the adjacent physical page via the DMAP. Proven by value differential with a KLD sysctl harness: control note -> p_osrel=0x44332211 (exact in-file descriptor), bug note -> p_osrel=0x200a2a2f (/*\\n ) which appears nowhere in the crafted file. Silent on this guest (p_osrel has no userspace reader; DMAP read never faults) - Low severity now, a 4-byte kernel-memory oracle the day p_osrel gains exposure. Fix validated: truncated note rejected with ENOEXEC, full notes unaffected.",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "exploit_chain": "execve(crafted ELF EI_OSABI=255, uid 1001) -> get_brandinfo loop 1 (BI_BRAND_NOTE) -> check_PT_NOTE accepts {10,4,1}+DragonFly\\0 within 22 proven bytes -> BN_TRANSLATE_OSREL callback bsd_trans_osrel reads *(int32_t*)(note+24) past segment/page end (DMAP neighbor physical page) -> imgp->proc->p_osrel = OOB bytes; observable only via the root-loaded df_osrel.ko sysctl harness (evidence gathering, not part of the attack).",
  "evidence": "run.log: case2 control p_osrel=0x44332211 vs case3 bug p_osrel=0x200a2a2f (3/3 runs), case1 nonote ENOEXEC; fix validation: bug binary ENOEXEC on patched kernel while control still yields 0x44332211. df_osrel.c KLD harness in pack.",
  "kernel_refs": [
    "sys/kern/imgact_elf.c:1700",
    "sys/kern/imgact_elf.c:1786",
    "sys/kern/imgact_elf.c:1792",
    "sys/kern/imgact_elf.c:1866",
    "sys/kern/imgact_elf.c:1872",
    "sys/kern/imgact_elf.c:129",
    "sys/cpu/x86_64/misc/elf_machdep.c:66",
    "sys/cpu/x86_64/misc/elf_machdep.c:67",
    "sys/kern/kern_exec.c:838"
  ],
  "poc_changes": "Authored from scratch. Three harness iterations were needed: (1) note offsets must be 4-aligned or check_PT_NOTE breaks at aligned(note, Elf32_Addr); (2) e_entry must lie within [p_vaddr, p_vaddr+p_memsz) or exec_elf64_imgact leaves entry=0 (SIGSEGV at address 0) - used p_memsz=258 to span the stub at 0x400100; (3) CTLTYPE_STRING sysctl harness replaced with RW-int pid + RD-int value pair.",
  "attempts": 6,
  "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": 1500,
  "guest_dirty": 0,
  "build_cmd": "cc -o make_note make_note.c && ./make_note bug note_bug.bin && ./make_note control note_ctl.bin && ./make_note nonote note_none.bin && (cd kld && make) && kldload kld/df_osrel.ko",
  "run_cmd": "sh run_guest.sh   # as root: runs the three binaries as maxx, reads p_osrel via sysctl debug.df_osrel_pid/debug.df_osrel_val",
  "code_hash": "29696012b558fb5f16a77bdca2051fc06f87900f44461648d5a962c27b16e907",
  "notes": "Heap path variant (PT_NOTE beyond first page, imgact_elf.c:1757) reads past a kmalloc(notesz<=PAGE_SIZE) chunk instead - same root cause. No panic route on this guest: first page is DMAP-backed (cpu/x86_64/misc/lwbuf.c:95) and kmalloc neighbors stay mapped. p_osrel currently write-only in kernel (kern_exec.c:298, imgact_elf.c:867, init_main.c:385) - impact none today, escalation to a leak primitive if p_osrel is ever exposed (procstat/sysctl).",
  "recommended_fix": "note_overflow(): require the whole declared note (header + rounded name + descriptor) to fit within the remaining segment bytes (see fix.diff).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Patched kernel (kernel #1 with fix.diff): bug-note binary rejected with ENOEXEC (was: execs + p_osrel=0x200a2a2f from OOB); control note still execs with p_osrel=0x44332211 (no regression for every real DragonFly binarys ABI note); nonote still ENOEXEC.",
  "fix_evidence": "run.log DF-5630 fix validation section; VERDICT.md; fix.diff in pack."
}