#include #include #include #include #include #include #include int fib(int n) { int first = 0, second = 1, next = 0, i = 0; while(i <= n) { if(i < 2) { next = i; } else { next = first + second; first = second; second = next; } i++; } return next; } int pass_test() { return 0x42; } void fatal(char *msg) { fprintf(stderr, "*** FATAL ERROR: %s\n", (msg ? msg : "no message")); fflush(stderr); abort(); } void test_shared() { static char filename[] = "/tmp/DoubleMapXXXXXX"; int fd = mkstemp(filename); if(fd == -1) { fatal("mkstemp"); } if(ftruncate(fd, PAGE_SIZE) == -1) { fatal("ftruncate"); } uint8_t *const write_addr = mmap(0, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); uint8_t *const exec_addr = mmap(write_addr+PAGE_SIZE, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED, fd, 0); if(write_addr == MAP_FAILED || exec_addr == MAP_FAILED) { fatal("mmap"); } size_t size = PAGE_SIZE; memcpy(write_addr, fib, size); int (*fun_pointer)() = (void*)exec_addr; // Give the JIT something to potentially cache for(int i = 0; i < 15000; i++) { if(fun_pointer(20) != 6765) { fatal("fibonacci"); } } memcpy(write_addr, pass_test, size); if(fun_pointer() == 0x42) { printf("test_shared passed\n"); } munmap(write_addr, 2 * size); munmap(exec_addr, size); } void test_consecutive() { uint8_t *const page0 = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); // throwaway mmap to reduce likelhood of page0 and page1 mapping to consecutive physical frames uint8_t *const throwaway = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); uint8_t *const page1 = mmap(page0 + PAGE_SIZE, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if(page0 == MAP_FAILED || throwaway == MAP_FAILED || page1 == MAP_FAILED) { fatal("mmap"); } // Attempt to influence virtual to physical mapping - we want page0->page1 to not be contiguous // physically page0[0] = 0; throwaway[0] = 0; page1[0] = 0; for(int32_t i = 0; i < 100; i++) { uint8_t* start = (uint8_t*)(page1 - i - 1); memcpy(start, fib, PAGE_SIZE); int (*fun_pointer)() = (void*)start; for(int j = 0; j < 15000; j++) { if(fun_pointer(20) != 6765) { fatal("fibonacci"); } } } printf("test_consecutive passed\n"); } void test_consecutive_written() { uint8_t *const page0 = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); // throwaway mmap to reduce likelhood of page0 and page1 mapping to consecutive physical frames uint8_t *const throwaway = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); uint8_t *const page1 = mmap(page0 + PAGE_SIZE, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if(page0 == MAP_FAILED || throwaway == MAP_FAILED || page1 == MAP_FAILED) { fatal("mmap"); } // Attempt to influence virtual to physical mapping - we want page0->page1 to not be contiguous // physically page0[0] = 0; throwaway[0] = 0; page1[0] = 0; uint8_t* start = page1 - 8; uint8_t* ptr = start; const int32_t INC_COUNT = 16; // xor eax, eax *ptr++ = 0x31; *ptr++ = 0xc0; for(int i = 0; i < INC_COUNT; i++) { // inc eax *ptr++ = 0x40; } // ret *ptr++ = 0xC3; int (*fun_pointer)() = (void*)start; for(int i = 0; i < 15000; i++) { int32_t result = fun_pointer(); if(result != INC_COUNT) { fatal("test_consecutive_written"); } } // overwrite one INC at the start of the second page with a NOP *page1 = 0x90; int32_t result = fun_pointer(); if(result != INC_COUNT - 1) { fatal("test_consecutive_written after overwrite"); } printf("test_consecutive_written passed\n"); } int main() { test_shared(); // disabled for now, takes long and not sure if it actually catches bugs //test_consecutive(); test_consecutive_written(); return 0; }