DF-5701 / trunc_fixed.c
/* * Fixed-bcmp truncation check: huge lengths must NEVER yield a false * "equal". With the fix, bcmp actually compares the requested range; * inside the 3-page guarded arena a >=2^31 request therefore faults * (as memcmp would) instead of returning 0. */ #include <stdio.h> #include <string.h> #include <sys/mman.h> #include <sys/wait.h> #include <unistd.h> int bcmp_fixed(const void *, const void *, size_t); #define PS 4096 static int child_call(size_t length, unsigned char *b1, unsigned char *b2) { pid_t pid = fork(); if (pid == 0) { volatile int r = bcmp_fixed(b1, b2, length); printf(" returned %d (clean)\n", r); _exit(r == 0 ? 3 : 4); /* 3 == false-equal-with-clean-exit */ } int st = 0; waitpid(pid, &st, 0); if (WIFSIGNALED(st)) return -WTERMSIG(st); return WEXITSTATUS(st); } int main(void) { unsigned char *a1 = mmap(NULL, 3*PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); unsigned char *a2 = mmap(NULL, 3*PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (a1 == MAP_FAILED || a2 == MAP_FAILED) return 2; mprotect(a1, PS, PROT_NONE); mprotect(a1 + 2*PS, PS, PROT_NONE); mprotect(a2, PS, PROT_NONE); mprotect(a2 + 2*PS, PS, PROT_NONE); unsigned char *b1 = a1+PS, *b2 = a2+PS; memset(b1, 0x41, PS); memset(b2, 0x41, PS); printf("fixed bcmp(2^32) on guarded pages: "); int r1 = child_call((size_t)1<<32, b1, b2); printf("outcome=%s\n", r1 == -11 ? "SIGSEGV while genuinely comparing (correct)" : r1 == 3 ? "FALSE EQUAL (bug remains)" : "other"); printf("fixed bcmp(2^32+8) on guarded pages: "); int r2 = child_call(((size_t)1<<32)+8, b1, b2); printf("outcome=%s\n", r2 == -11 ? "SIGSEGV while genuinely comparing (correct)" : r2 == 3 ? "FALSE EQUAL (bug remains)" : "other"); printf("RESULT: %s\n", (r1 == -11 && r2 == -11) ? "FIX-PASS (no false equal)" : "FIX-FAIL"); return 0; } |