⬢ DragonFlyBSD Kernel Audit
DF-5194 / guard_probe.c
← back to finding ↓ download raw
/*
 * guard_probe.c -- DF-5194: guard + in-bounds verification (root)
 * Run with the snake already running (vidconsole boot, module loaded).
 */
#include <sys/ioctl.h>
#include <sys/consio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define VRAM_LEN 8192

static int rd(unsigned char *b)
{
	int fd = open("/dev/mem", O_RDONLY);
	ssize_t n = pread(fd, b, VRAM_LEN, 0xB8000);
	close(fd);
	return n == VRAM_LEN ? 0 : -1;
}

static int count(const unsigned char *b, int *maxidx)
{
	int c = 0;
	*maxidx = -1;
	for (int j = 0; j < VRAM_LEN; j += 2)
		if (b[j+1] == 0x07 && b[j] != 0x20 && b[j]) {
			c++;
			if (j / 2 > *maxidx) *maxidx = j / 2;
		}
	return c;
}

static double now(void)
{
	struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC, &ts);
	return ts.tv_sec + ts.tv_nsec / 1e9;
}

int main(void)
{
	unsigned char b[VRAM_LEN];
	int fd, v, cells, maxidx, i, mode;
	double t0, t1;

	fd = open("/dev/ttyv0", O_WRONLY);
	if (fd < 0) { perror("ttyv0"); return 1; }

	/* start saver */
	v = 1;
	ioctl(fd, CONS_BLANKTIME, &v);
	ioctl(fd, CONS_SAVERSTART, &v);

	/* wait for the snake to fully unfold */
	for (i = 0; i < 100; i++) {
		usleep(200000);
		rd(b);
		cells = count(b, &maxidx);
		if (cells >= 20) break;
	}
	printf("[1] snake running: %d cells, max cell index=%d "
	       "(screen has 2000 cells; vtb window 8192B sampled)\n",
	       cells, maxidx);
	if (maxidx < 2000)
		printf("[+] IN-BOUNDS: all snake cells < xsize*ysize (2000)\n");
	else
		printf("[!] OOB CELLS PRESENT: maxidx=%d >= 2000\n", maxidx);

	/* guard: mode change while blanked */
	printf("[2] CONS_SET(80x30) while blanked...\n");
	mode = 32;
	errno = 0;
	t0 = now();
	v = ioctl(fd, CONS_SET, &mode);
	t1 = now();
	printf("    rc=%d errno=%d elapsed=%.3fs\n", v, errno, t1 - t0);
	if (v == 0)
		printf("[+] GUARD HELD: mode change succeeded; saver was "
		       "stopped (unblanked) first by sc_clean_up\n");

	/* confirm snake gone */
	sleep(1);
	rd(b);
	cells = count(b, &maxidx);
	printf("[3] after mode change: %d cells (snake stopped)\n", cells);

	/* restore 80x25 */
	mode = 24;
	v = ioctl(fd, CONS_SET, &mode);
	printf("[4] CONS_SET(80x25) rc=%d\n", v);

	/* force blank again: fresh re-init expected (blanked was reset) */
	v = 1;
	ioctl(fd, CONS_SAVERSTART, &v);
	int first_cells = -1;
	for (i = 0; i < 100; i++) {
		usleep(100000);
		rd(b);
		cells = count(b, &maxidx);
		if (cells > 0) { first_cells = cells; break; }
	}
	printf("[5] re-blank: first non-zero sample has %d cells "
	       "(small == fresh re-init, not stale geometry)\n", first_cells);
	for (i = 0; i < 100; i++) {
		usleep(200000);
		rd(b);
		cells = count(b, &maxidx);
		if (cells >= 20) break;
	}
	printf("[6] snake running again: %d cells, maxidx=%d\n", cells, maxidx);

	/* cleanup */
	v = 0;
	ioctl(fd, CONS_SAVERSTART, &v);
	v = 0;
	ioctl(fd, CONS_BLANKTIME, &v);
	printf("[*] cleanup done\n");
	return 0;
}