⬢ DragonFlyBSD Kernel Audit
DF-4539 / cs4281_probe.c
← back to finding ↓ download raw
/*
 * DF-4537 probe: environment documentation for the cs4281 attach-failure
 * mixer-UAF family (DF-4156 family, 10th instance).
 *
 * The bug: cs4281_pci_attach() publishes the 0666 /dev/mixerN via
 * mixer_init() (cs4281.c:845) BEFORE pcm_register() (cs4281.c:847).
 * If pcm_register() fails, the bad: unwind ac97_destroy()s the codec
 * and kfrees the softc, but /dev/mixerN still dispatches ioctls into
 * the freed codec/softc (only pcm_unregister()->mixer_uninit() ever
 * destroys the cdev, and it cannot run after failed pcm_register).
 *
 * This probe documents (a) whether any /dev/mixerN exists from a CS4281
 * on this guest, and (b) that an *unprivileged* uid can open any
 * existing mixer node and issue SOUND_MIXER_READ_* ioctls -- the exact
 * unprivileged surface the family finding describes for a machine where
 * a CS4281 attach reaches mixer_init() and then fails pcm_register().
 *
 * Exit 0 = environment documented (no trigger device present, or the
 * unpriv ioctl surface demonstrated on a present node).
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <glob.h>
#include <machine/soundcard.h>

int
main(void)
{
	glob_t g;
	int i, fd, val = -1;

	printf("probe: uid=%d euid=%d\n", getuid(), geteuid());

	if (glob("/dev/mixer*", 0, NULL, &g) != 0 || g.gl_pathc == 0) {
		printf("probe: no /dev/mixer* nodes exist on this guest "
		    "(no snd_cs4281 attach => no family trigger surface)\n");
		globfree(&g);
		return (0);
	}

	for (i = 0; i < (int)g.gl_pathc; i++) {
		fd = open(g.gl_pathv[i], O_RDWR);
		if (fd < 0) {
			printf("probe: %s: open failed (errno=%d) -- "
			    "not reachable unprivileged\n",
			    g.gl_pathv[i], errno);
			continue;
		}
		if (ioctl(fd, SOUND_MIXER_READ_VOLUME, &val) == 0)
			printf("probe: %s: UNPRIV mixer ioctl OK "
			    "(SOUND_MIXER_READ_VOLUME=0x%04x)\n",
			    g.gl_pathv[i], val);
		else
			printf("probe: %s: opened unpriv, ioctl errno=%d\n",
			    g.gl_pathv[i], errno);
		close(fd);
	}
	globfree(&g);
	return (0);
}