DragonFlyBSD Kernel Audit
DF-2586 / leak_sample.txt
← back to finding ↓ download raw
DF-2586 — OOB read proof (panic signature interpretation)
=========================================================

The decisive PoC sets the buggy geometry via kvm_write (root-only state setup
that shortcuts the timing of the natural msgbuf_clear path):
    msg_bufx = msg_size            -> xindex_modulo == 0
    msg_bufr = msg_size/2 + 100000 -> rindex_modulo > msg_size/2
Then issues sysctlbyname("kern.msgbuf", buf, 1MiB_oldlen).

On the UNPATCHED #0 kernel this PANICS:
    panic: assertion "obj != NULL" failed in vm_object_hold_shared at vm_object.c:330
    --- trap 0xc, rip=std_copyout+0x15a ---
    std_copyout() at std_copyout+0x15a

Trap 0xc = page fault raised INSIDE std_copyout's source-side read. The buggy
branch-3 length (n - rindex_modulo) underflows to ~4.095 billion (u_int),
sysctl_old_user clips it to the 1 MiB oldlen, and copyout reads 1 MiB starting
at msg_ptr + rindex_modulo -- running PAST msg_ptr + msg_size into unmapped
kernel memory -> fault -> KASSERT(obj != NULL) panic.

This is DECISIVE proof the buggy code path is an OOB read. Had the adjacent
memory been mapped (it usually is, just past the msgbuf), the same read would
have LEAKED kernel-heap residue to userspace instead of crashing.

REACHABILITY (honest): the OOB-underflow geometry requires msg_bufr to be
"stale" (modulo > msg_size/2). In steady state msg_bufr tracks
msg_bufx - msg_size + 2048 so rindex_modulo==2048 and the bug is only a benign
2048-byte UNDER-read (no OOB, no leak). The stale state is produced ONLY by
root writing kern.msgbuf_clear=1 (msg_bufr := msg_bufx). An unprivileged user
cannot trigger the OOB -- verified by polling (see unpriv log). So the bug's
realistic impact ceiling is: root-triggerable local kernel OOB read / panic
(does NOT cross a privilege boundary; root->root + DoS). The code fix is still
warranted -- it's a real latent OOB defect.

Decisive run output was lost to the panic (ssh channel died before flush); the
boot.log panic above is the proof. (geometry_steady.txt shows the natural
steady-state branch decision before the trigger.)