DF-3568 / guard_rij_badbits.c
/* * guard_rij_badbits.c - prove rijndael_set_key (api wrapper, no validation) * passes attacker-controlled keyBits straight through and that * rijndaelKeySetupEnc then reads key material beyond keyBits/8 bytes * when keyBits is invalid (KASSERT compiled out = production kernel * without INVARIANTS; userland mirrors that with -DNDEBUG). * * sys/crypto/rijndael/rijndael-api.c:38-43 (no bounds check, void return) * sys/crypto/rijndael/rijndael-alg-fst.c:738 (KASSERT only) * sys/crypto/rijndael/rijndael-alg-fst.c:740-785 (unconditional * rk[0..7] = key[0..31] loads regardless of keyBits) * * mode "safe": 32-byte buffer, bits=64 -> prints ctx.Nr (expect 0: silent * garbage schedule, no error path) * mode "guard": 8-byte buffer at end of a page before a PROT_NONE guard; * bits=64 -> first OOB byte load at key+8 faults. * Exit 42 = fault confirmed. * * Build: cc -DNDEBUG -I/usr/src/sys ... rijndael-api.c rijndael-alg-fst.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <sys/mman.h> #include <sys/types.h> #include <crypto/rijndael/rijndael.h> static void handler(int sig, siginfo_t *si, void *uc) { (void)uc; printf("FAULT-CONFIRMED: sig=%d si_addr=%p (expected key+8 on guard page)\n", sig, si->si_addr); fflush(stdout); _exit(42); } int main(int argc, char **argv) { rijndael_ctx ctx; unsigned char pt[16], ct[16]; int i; if (argc < 2) return 2; if (strcmp(argv[1], "safe") == 0) { unsigned char key32[32]; for (i = 0; i < 32; i++) key32[i] = i; rijndael_set_key(&ctx, key32, 64); printf("safe mode: bits=64 accepted silently, ctx.Nr=%d " "(0 = unusable schedule, no error surfaced)\n", ctx.Nr); memset(pt, 0xAA, sizeof(pt)); rijndael_encrypt(&ctx, pt, ct); printf("safe mode: rijndael_encrypt ran with Nr=%d and produced " "garbage without any failure indication\n", ctx.Nr); return 0; } { unsigned char *base, *key8; struct sigaction sa; base = mmap(NULL, 2 * 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (base == MAP_FAILED || mprotect(base + 4096, 4096, PROT_NONE) != 0) { perror("mmap/mprotect"); return 2; } key8 = base + 4096 - 8; /* 8-byte key, guard right after */ for (i = 0; i < 8; i++) key8[i] = i; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = handler; sa.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &sa, NULL); sigaction(SIGBUS, &sa, NULL); printf("calling rijndael_set_key(&ctx, key8=%p, bits=64) " "(guard page at %p)\n", (void *)key8, (void *)(base + 4096)); fflush(stdout); rijndael_set_key(&ctx, key8, 64); printf("BUG-NOT-PRESENT: survived bits=64 with 8-byte key\n"); return 0; } } |