DragonFlyBSD Kernel Audit
DF-0767 / panic.txt
← back to finding ↓ download raw
== DF-0767 panic signature (from dfbsd-qemu/boot.log, unpatched #0 kernel) ==

Trigger: unprivileged `mkdir /mnt/df0767_pwn` as maxx (uid 1001) against a
malicious NFSv3 server that (a) replies MKDIR with no object filehandle
(gotvp=0, forcing nfs_lookitup) and (b) replies the subsequent LOOKUP with
the *parent* directory filehandle, taking the NFS_CMPFH branch in
nfs_lookitup() where the local `np` is never assigned, so the trailing
`*npp = np` stores stack garbage; nfs_mkdir then does `newvp = NFSTOV(np)`
and dereferences the wild pointer.

Fatal trap 9: general protection fault while in kernel mode
cpuid = 0; lapic id = 0
instruction pointer	= 0x8:0xffffffff8080f5d8
stack pointer	        = 0x10:0xfffff801182df428
frame pointer	        = 0x10:0xfffff801182df5e8
code segment		= base 0x0, limit 0xffff, type 0x1b
			= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags	= interrupt enabled, resume, IOPL = 0
current process		= 870
current thread          = pri 10
kernel: type 9 trap, code=0

CPU0 stopping CPUs: 0x0000003e
 stopped
Stopped at      nfs_mkdir+0x328:        cmpl    $0x2,0xe8(%rdi)
db>

== interpretation ==
nfs_mkdir+0x328 == nfs_vnops.c:2355 `if (newvp->v_type != VDIR)` where
newvp was just produced by `newvp = NFSTOV(np)` (line 2354) consuming the
uninitialized `np` returned from nfs_lookitup().  rdi == wild `newvp`;
`cmpl $0x2,0xe8(%rdi)` reads v_type at struct vnode offset 0xe8 and compares
to VDIR(=2).  The GPF (trap 9, not page-fault trap 12) fires because the
wild `newvp` is a non-canonical x86-64 address derived from garbage stack
residue via `np->n_vnode`.