DF-0011 / panic.txt
DF-0011 — kernel panic signature captured from serial console (dfbsd-qemu/boot.log)
during the decisive run of nopasscred_panic (guest in DDB after panic).
Trigger: unprivileged user (maxx, uid 1001) ran ./nopasscred_panic which:
Phase 1: pinned ~73000 plain MT_CONTROL/MT_SONAME mbufs by flooding many
AF_UNIX SOCK_DGRAM receiver buffers with SCM_CREDS-bearing 1-byte
datagrams and holding the socketpairs open. Pinned plain:pkthdr
ratio is 2:1, so the ~72904-deep plain objcache was exhausted while
the pkthdr cache stayed only half full.
Phase 2: fired plain send() (no control) to an SO_PASSCRED receiver. The
data pkthdr mbuf allocated (M_WAITOK, pkthdr cache had room), so
execution proceeded into uipc_send's SO_PASSCRED block, where
sbcreatecontrol() did m_get(M_NOWAIT, MT_CONTROL) on the EXHAUSTED
plain cache, returned NULL, and unp_internalize(NULL) dereferenced
mtod(NULL) -> *(caddr_t*)(NULL + offsetof(mh_data)) = read at vaddr 0x10.
===== serial console excerpt (dfbsd-qemu/boot.log) =====
login: Warning: objcache(mbuf) exhausted on cpu1!
Fatal user address access from kernel mode from nopasscred_panic at ffffffff806cdac1
Fatal trap 12: page fault while in kernel mode
cpuid = 1; lapic id = 1
fault virtual address = 0x10
fault code = supervisor read data, page not present
instruction pointer = 0x8:0xffffffff806cdac1
stack pointer = 0x10:0xfffff800ab5d3568
frame pointer = 0x10:0xfffff800ab5d35a8
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 0, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 1468
current thread = pri 6
kernel: type 12 trap, code=0
CPU1 stopping CPUs: 0x00000001
stopped
Stopped at unp_internalize.isra.12+0x11: movq 0x10(%rdi),%rbx
db>
===== interpretation =====
- "objcache(mbuf) exhausted on cpu1!" -> the plain "mbuf" objcache (the one
sbcreatecontrol's m_get(M_NOWAIT, MT_CONTROL) draws from, uipc_mbuf.c:798)
hit its allocation ceiling: the NULL-return precondition is met.
- fault virtual address = 0x10 -> offsetof(struct m_hdr, mh_data). This is the
load of m_data from a NULL struct mbuf pointer, i.e. mtod(NULL, ...). The
finding markdown guessed 0x0; the real fault address is 0x10 (mh_data offset).
- "Stopped at unp_internalize.isra.12+0x11: movq 0x10(%rdi),%rbx" with
%rdi == 0 (NULL control) -> exactly the deref at uipc_usrreq.c:1706
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
when control == NULL (sbcreatecontrol returned NULL at uipc_usrreq.c:695 and
the return was used unchecked at :697).
- current process 1468 = the unprivileged trigger (nopasscred_panic, run as
maxx). This is a local unprivileged DoS, exactly as claimed.