DF-5344 / brand_guard.c
/* * Guard-page proof for the identcpu.c brand-string bug (no sanitizer needed). * * Places a 48-byte "cpu_brand" at the very end of a readable page with a * PROT_NONE page immediately after, then runs the EXACT algorithm from * sys/platform/pc64/x86_64/identcpu.c printcpuinfo(): * * [118-125] for (i=0x80000002;i<0x80000005;i++){memcpy(brand,regs,16);brand+=16;} * [160-164] brand=cpu_brand; while(*brand==' ')++brand; * if(*brand!='\0') strcpy(cpu_model,brand); * * mode 0: 48 non-NUL bytes ('A') -> strcpy must read brand[48] -> SIGSEGV * mode 1: 48 spaces -> skip-loop reads brand[48] -> SIGSEGV * mode 2 (control): 47 'A' + NUL -> all reads in bounds, no signal */ #include <stdio.h> #include <string.h> #include <sys/mman.h> #include <stdlib.h> int main(int argc, char **argv) { int mode = argc > 1 ? atoi(argv[1]) : 0; unsigned char *pages, *cpu_brand; char cpu_model[128]; unsigned char leaf[48]; char *brand; int i; pages = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (pages == MAP_FAILED) { perror("mmap"); return 1; } if (mprotect(pages + 4096, 4096, PROT_NONE) != 0) { perror("mprotect"); return 1; } cpu_brand = pages + 4096 - 48; /* brand[0..47] readable, brand[48] = guard */ switch (mode) { case 0: memset(leaf, 'A', 48); break; case 1: memset(leaf, ' ', 48); break; default: memset(leaf, 'A', 48); leaf[47] = '\0'; break; } /* identcpu.c:118-125 -- no termination is ever written */ brand = (char *)cpu_brand; for (i = 0; i < 3; i++) { memcpy(brand, leaf + i * 16, 16); brand += 16; } /* identcpu.c:127-154 bounded vendor build (abridged) */ strcpy(cpu_model, "Clawhammer"); strcat(cpu_model, "EM64T"); /* identcpu.c:160-164 */ brand = (char *)cpu_brand; while (*brand == ' ') ++brand; if (*brand != '\0') strcpy(cpu_model, brand); printf("mode %d: survived; cpu_model='%s' (len %zu)\n", mode, cpu_model, strlen(cpu_model)); return 0; } |