DF-4538 / cs4281_probe.c
/* * 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); } |