DragonFlyBSD Kernel Audit
DF-0011 / panic.txt
← back to finding ↓ download raw
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.