⬢ DragonFlyBSD Kernel Audit
DF-3567 / guard_bf_len0.c
← back to finding ↓ download raw
/*
 * guard_bf_len0.c - prove BF_set_key dereferences data[0] when len == 0
 * (sys/crypto/blowfish/bf_skey.c:83-99).
 *
 * A zero-length key buffer has no readable bytes; we model it by placing
 * `data` at a PROT_NONE guard page. The first of the 72 key-schedule byte
 * reads (ri = *(d++)) faults; si_addr == data proves the dereference.
 * Exit 42 = fault confirmed at data[0].
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <crypto/blowfish/blowfish.h>

static void
handler(int sig, siginfo_t *si, void *uc)
{
	(void)uc;
	printf("FAULT-CONFIRMED: sig=%d si_addr=%p (expected data[0] at guard page)\n",
	    sig, si->si_addr);
	fflush(stdout);
	_exit(42);
}

int
main(void)
{
	BF_KEY key;
	unsigned char *guard;
	struct sigaction sa;

	guard = mmap(NULL, 2 * 4096, PROT_READ | PROT_WRITE,
	    MAP_ANON | MAP_PRIVATE, -1, 0);
	if (guard == MAP_FAILED || mprotect(guard + 4096, 4096, PROT_NONE) != 0) {
		perror("mmap/mprotect");
		return 2;
	}
	memset(&sa, 0, sizeof(sa));
	sa.sa_sigaction = handler;
	sa.sa_flags = SA_SIGINFO;
	sigaction(SIGSEGV, &sa, NULL);
	sigaction(SIGBUS, &sa, NULL);

	printf("calling BF_set_key(&key, len=0, data=guard-page %p)\n",
	    (void *)(guard + 4096));
	fflush(stdout);
	BF_set_key(&key, 0, guard + 4096);	/* data[0] dereference -> fault */
	printf("BUG-NOT-PRESENT: survived len=0\n");
	return 0;
}