DF-0940 / trig.c
/* * trig.c - DF-0940 verification trigger. * * The finding claims an unprivileged user can mmap an >4 GiB MAP_STACK and * trigger an integer-truncation DoS in vm_map_growstack(). This trigger * exercises that exact code path and demonstrates that: * * (a) mmap(MAP_STACK | MAP_ANON, 8 GiB) succeeds (RLIMIT_VMEM = infinity), * (b) the returned region is a NORMAL anon mapping (MAP_STACK was stripped * by vm_mmap.c:429-436), and * (c) deep reads/writes succeed without invoking vm_map_growstack at all — * no panic, no DoS, no kernel memory growth. * * Build: cc -O0 -o trig trig.c * Run: ./trig * * Expected output on the vulnerable (and fixed) kernel: prints the mapping * details, reads a zero byte, exits 0. Guest stays up. */ #define _GNU_SOURCE #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> static void dump_map_range(const char *p, size_t stacksz) { FILE *f = fopen("/proc/curproc/map", "r"); if (!f) return; char line[256]; unsigned long lo, hi; while (fgets(line, sizeof line, f)) { if (sscanf(line, "%lx %lx", &lo, &hi) == 2 && lo >= (unsigned long)p && hi <= (unsigned long)p + stacksz + 0x100000) { fprintf(stderr, " %s", line); } } fclose(f); } int main(void) { size_t stacksz = (size_t)8 << 30; /* 8 GiB */ char *p = mmap(NULL, stacksz, PROT_READ | PROT_WRITE, MAP_STACK | MAP_ANON, -1, 0); if (p == MAP_FAILED) { perror("mmap MAP_STACK"); return 1; } fprintf(stderr, "MAP_STACK at %p, size %zu GiB\n", p, stacksz >> 30); fprintf(stderr, "--- /proc/curproc/map entries in range ---\n"); dump_map_range(p, stacksz); /* Write to the lowest byte of the reserved range. If MAP_STACK were * honored, this would trigger vm_map_growstack with a >4 GiB grow_amount. * Because MAP_STACK is stripped (vm_mmap.c:429), this is just a normal * anon page write — succeeds trivially. */ volatile char *bottom = p; *bottom = 'x'; fprintf(stderr, "wrote *bottom = 'x' (no fault, no growstack)\n"); /* Read 5 GiB "below" the stack top. Again, just a normal anon read. */ volatile char *deep = p + (stacksz - (5ULL << 30)); char c = *deep; fprintf(stderr, "read *deep (%p) = 0x%02x (no fault, no growstack)\n", deep, (unsigned char)c); fprintf(stderr, "RESULT: trig exits 0; guest unaffected. Bug NOT triggered.\n"); return 0; } |