⬢ DragonFlyBSD Kernel Audit
DF-5344 / brand_guard.c
← back to finding ↓ download raw
/*
 * 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;
}