⬢ DragonFlyBSD Kernel Audit
DF-2367 / rijnh.c
← back to finding ↓ download raw
/*
 * rijnh.c -- userland driver for the kern.rijnh.test kernel harness
 * (DF-2367 / DF-2368 verification).  Runs on the guest.
 *
 * Most ops just write a command string to the sysctl and print the
 * readback; results are also kprintf'd with tag RIJNH: (dmesg).
 *
 * The poison/direct ops set up the user-VA guard layout the kernel
 * rig walks into: one mapped (pre-faulted) page followed by an
 * unmapped page, with the rijndael_ctx placed in the last 512 bytes
 * of the mapped page so the ek[] walk of the runaway round loop
 * crosses the page boundary after ~16 32-byte steps.
 *
 * Build: cc -O -o rijnh rijnh.c
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define	SYSCTL_NAME	"kern.rijnh.test"

static int
do_cmd(const char *cmd)
{
	char buf[512];
	size_t len = sizeof(buf);
	int rc;

	rc = sysctlbyname(SYSCTL_NAME, buf, &len, cmd, strlen(cmd) + 1);
	if (rc != 0) {
		perror("sysctlbyname(write)");
		return (rc);
	}
	/* read back the harness result string */
	memset(buf, 0, sizeof(buf));
	len = sizeof(buf);
	rc = sysctlbyname(SYSCTL_NAME, buf, &len, NULL, 0);
	if (rc == 0)
		printf("readback: %s\n", buf);
	return (0);
}

static int
do_poison(const char *op)
{
	char cmd[128];
	char *base;
	unsigned long addr;

	base = mmap(NULL, 2 * 4096, PROT_READ | PROT_WRITE,
	    MAP_ANON | MAP_PRIVATE, -1, 0);
	if (base == MAP_FAILED) {
		perror("mmap");
		return (1);
	}
	if (munmap(base + 4096, 4096) != 0) {	/* guard page: UNMAPPED */
		perror("munmap");
		return (1);
	}
	memset(base, 0xAA, 4096);			/* pre-fault the page */
	addr = (unsigned long)(base + 4096 - 512);
	printf("%s: mapped page %p, guard page %p (unmapped),"
	    " ctx at %lx\n", op, base, base + 4096, addr);
	fflush(stdout);
	snprintf(cmd, sizeof(cmd), "%s %lx", op, addr);
	return (do_cmd(cmd));
}

static void
usage(void)
{
	fprintf(stderr,
	    "usage: rijnh kat | setkey <bits> | twinval <n> |"
	    " idx <keyhex> <pthex> | idxr1 <keyhex> <pthex> |"
	    " bench <n> <keyhex> | poison | direct\n");
	exit(2);
}

int
main(int argc, char **argv)
{
	char cmd[512];

	if (argc < 2)
		usage();

	if (strcmp(argv[1], "kat") == 0)
		return (do_cmd("kat"));
	if (strcmp(argv[1], "poison") == 0 || strcmp(argv[1], "direct") == 0)
		return (do_poison(argv[1]));
	if (strcmp(argv[1], "setkey") == 0 && argc == 3) {
		snprintf(cmd, sizeof(cmd), "setkey %s", argv[2]);
		return (do_cmd(cmd));
	}
	if (strcmp(argv[1], "twinval") == 0 && argc == 3) {
		snprintf(cmd, sizeof(cmd), "twinval %s", argv[2]);
		return (do_cmd(cmd));
	}
	if ((strcmp(argv[1], "idx") == 0 || strcmp(argv[1], "idxr1") == 0) &&
	    argc == 4) {
		snprintf(cmd, sizeof(cmd), "%s %s %s", argv[1], argv[2],
		    argv[3]);
		return (do_cmd(cmd));
	}
	if (strcmp(argv[1], "bench") == 0 && argc == 4) {
		snprintf(cmd, sizeof(cmd), "bench %s %s", argv[2], argv[3]);
		return (do_cmd(cmd));
	}
	usage();
	return (2);
}