⬢ DragonFlyBSD Kernel Audit
DF-3346 / guard.h
← back to finding ↓ download raw
/* Common guard-page helper (fork-based, robust): place a buffer at the
 * very end of a mapped page followed by a PROT_NONE page; run the
 * verbatim code in a forked child -- exit(0) = ran cleanly, killed by
 * SIGSEGV/SIGBUS = the over-read crossed the guard page (proof). */
#ifndef GUARD_H
#define GUARD_H
#include <sys/mman.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

static char *
guard_buf(size_t len)	/* returns buffer of exactly len usable bytes */
{
	long pg = sysconf(_SC_PAGESIZE);
	char *base = mmap(NULL, 2 * pg, PROT_READ | PROT_WRITE,
	    MAP_PRIVATE | MAP_ANON, -1, 0);
	if (base == MAP_FAILED) { perror("mmap"); exit(2); }
	if (mprotect(base + pg, pg, PROT_NONE) < 0) { perror("mprotect"); exit(2); }
	return base + pg - len;	/* end of the FIRST page; second page is the guard */
}

static const char *gu_desc;
static int gu_quiet;

static int
gu_check(void (*fn)(void), const char *desc)
{
	pid_t pid;
	int st;

	gu_desc = desc;
	fflush(stdout);
	pid = fork();
	if (pid == 0) {
		fn();
		_exit(0);
	}
	waitpid(pid, &st, 0);
	if (WIFSIGNALED(st) &&
	    (WTERMSIG(st) == SIGSEGV || WTERMSIG(st) == SIGBUS)) {
		printf("  SEGV in child -- %s\n", gu_desc);
		return (1);
	}
	if (!gu_quiet)
		printf("    (child ran without fault)\n");
	return (0);
}
#endif