DragonFlyBSD Kernel Audit
DF-0016 / leak_sample.txt
← back to finding ↓ download raw
# DF-0016 leak sample — unredacted kernel pointers in kern.proc.* (kinfo_proc)
# Guest: DragonFly 6.5-DEVELOPMENT v6.5.0.1712.g89e6a-DEVELOPMENT (amd64)
# Reader: uid=1001 (maxx), NOT in wheel, NOT the owner of the target pids.
#
# sysctl_kern_proc (KERN_PROC_PID, kern_proc.c:1686) only checks PRISON_CHECK
# (jail) -- NOT p_trespass. fill_kinfo_proc / fill_kinfo_lwp write raw kernel
# virtual addresses into user-visible kinfo fields, copied out unredacted via
# sysctl_out_proc (kern_proc.c:1603/1612/1633). An unprivileged user can thus
# read the struct-proc slab address, filedesc slab address, and wait-channel
# of ANY pid (including every root daemon).
#
# 24 kernel pointers leaked across 8 processes in the decisive run.

## decisive run: kern.proc.pid.<root-pid> read as maxx
pid 1      uid=0    comm=init
    kp_paddr   = 0xfffff80066807880   (struct proc slab)     kern_kinfo.c:128
    kp_fd      = 0xfffff80066840ec0   (filedesc slab)        kern_kinfo.c:129
    kl_wchan   = 0xfffff80066807880   (wait channel)         kern_kinfo.c:272
pid 68     uid=0    comm=hammer2
    kp_paddr   = 0xfffff800ab143280   (struct proc slab)
    kp_fd      = 0xfffff800ab163c40   (filedesc slab)
    kl_wchan   = 0xfffff80065c799f8   (wait channel)
pid 285    uid=0    comm=dhclient
    kp_paddr   = 0xfffff8006680c880 ; kp_fd = 0xfffff8006684c140 ; kl_wchan = 0xfffff8006680c880
pid 328    uid=0    comm=devd
    kp_paddr   = 0xfffff800ab144180 ; kp_fd = 0xfffff800ab1669c0 ; kl_wchan = 0xfffff80067a5dff8
pid 411    uid=0    comm=syslogd
    kp_paddr   = 0xfffff800ab145080 ; kp_fd = 0xfffff800ab167b40 ; kl_wchan = 0xfffff80067a5e778
pid 699    uid=0    comm=sshd
    kp_paddr   = 0xfffff800ab144b80 ; kp_fd = 0xfffff800ab1677c0 ; kl_wchan = 0xfffff80067a5e4f8
pid 730    uid=0    comm=cron
    kp_paddr   = 0xfffff800ab144680 ; kp_fd = 0xfffff800ab16a540
    kl_wchan   = 0xffffffff8130f670   (kernel .text/.data!)  kern_kinfo.c:272

## nm /boot/kernel/kernel cross-reference (proves the leaked values are real
## kernel addresses, not garbage/zeros)
cron kl_wchan  0xffffffff8130f670  ->  nearest nm symbol: nanowait.<clone>+0x0  EXACT
   (a .text-range address -> directly reveals the kernel .text base = KASLR defeat)
kp_paddr/kp_fd/kl_wchan in 0xfffff8xxxxxxxxxx = DragonFly kernel KVA/malloc region
   (slab-allocated struct proc / struct filedesc / wait-channel tokens). These are
   dynamic allocations, so nm has no symbol; they are confirmed real by:
     - canonical upper-half kernel addresses (>= 0xffff800000000000)
     - STABLE across repeated reads (3x: pid 1 kp_paddr identical) -- a real,
       fixed live kernel object address, not random stack residue
     - DIFFERENT distinct values per pid, clustered in slab-sized groups
       (e.g. init/dhclient kp_paddr in 0xfffff8006680xxxx; hammer2/devd/syslogd/
        sshd/cron in 0xfffff800ab14xxxx) -- consistent with slab bucket layout

## stability check (decisive run)
pid 1 kp_paddr: 0xfffff80066807880 / 0xfffff80066807880 / 0xfffff80066807880  (STABLE)

## variance
run.log vs run.2.log: root-daemon slab addresses byte-identical (long-running
processes do not relocate); the self (leak_kinfo) process kp_paddr differs run
to run (new process, new slab object) -- expected, and itself confirms these are
live slab addresses.

## interpretation
Any unprivileged local user recovers, for every process on the system: the
slab address of its struct proc (kp_paddr) and struct filedesc (kp_fd), plus a
wait-channel address that is sometimes a kernel .text symbol (cron -> nanowait).
This is a reliable KASLR-bypass + slab-layout primitive that escalates the
practical severity of any local heap/struct-proc corruption bug (e.g. DF-0013)
from DoS to reliable code execution.