DF-2674 / stack_growx.c
/* * DF-2674 - vm_map_growstack() maps grown stack pages VM_PROT_ALL (RWX), * ignoring the original stack protection (RW, set by exec at * sys/kern/kern_exec.c:991-995). The grown region is silently executable. * * Uses /proc/self/map (DragonFly procfs format: * 0xSTART 0xEND res res obj PERM ref 0 flags COW type path ) */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> typedef struct { unsigned long s, e; char perm[8]; } reg_t; static int read_regs(reg_t *regs, int max, unsigned long lo, unsigned long hi) { FILE *f = fopen("/proc/self/map", "r"); char line[512]; int n = 0; if (!f) { perror("/proc/self/map"); exit(1); } while (fgets(line, sizeof(line), f) && n < max) { reg_t r; char perm[8] = { 0 }; unsigned long s, e; if (sscanf(line, "0x%lx 0x%lx %*d %*d %*p %7s", &s, &e, perm) != 3) continue; if (e <= lo || s >= hi) continue; r.s = s; r.e = e; strncpy(r.perm, perm, sizeof(r.perm) - 1); regs[n++] = r; } fclose(f); return n; } static void show(const char *tag, reg_t *regs, int n) { int i; printf("---- %s ----\n", tag); for (i = 0; i < n; i++) printf("0x%016lx-0x%016lx %s\n", regs[i].s, regs[i].e, regs[i].perm); } int main(void) { reg_t regs[64]; volatile char probe; unsigned long sp = (unsigned long)&probe; unsigned long lo = sp - (64UL << 20), hi = sp + (16UL * 1024); int n, i, exec_before = 0, exec_after = 0; unsigned long lowest; n = read_regs(regs, 64, lo, hi); show("before growth", regs, n); lowest = regs[0].s; for (i = 0; i < n; i++) { if (strchr(regs[i].perm, 'x')) exec_before++; if (regs[i].s < lowest) lowest = regs[i].s; } /* fault below the current stack mapping -> vm_map_growstack */ *(volatile char *)(lowest - 4096) = 1; n = read_regs(regs, 64, lo, hi); show("after growth", regs, n); for (i = 0; i < n; i++) if (strchr(regs[i].perm, 'x')) exec_after++; printf("executable regions near stack: before=%d after=%d\n", exec_before, exec_after); if (exec_after > exec_before) { printf ("VERDICT: REPRODUCED - stack growth created executable " "(rwx) stack mapping\n"); return (0); } printf("VERDICT: not reproduced\n"); return (1); } |