1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <errno.h> 7 #include <limits.h> 8 #include <signal.h> 9 #include <stdint.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <signal.h> 13 #include <string.h> 14 #include <sys/mman.h> 15 16 17 #ifndef PAGE_SIZE 18 # define PAGE_SIZE 4096 19 #endif 20 21 22 static const size_t kMapChunkSize = 4 * PAGE_SIZE; 23 static const size_t kTestSize = 256 * PAGE_SIZE; 24 25 static int64_t sHandledSignals = 0; 26 27 static uint8_t* sMappedBase; 28 static size_t sMappedSize; 29 static uint8_t* sTouchedAddress; 30 31 32 static void 33 signal_handler(int signal) 34 { 35 sHandledSignals++; 36 37 //printf("SIGSEGV at %p\n", sTouchedAddress); 38 39 // protect the last page of the current allocation writable 40 if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, 41 PROT_READ | PROT_WRITE) < 0) { 42 fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno)); 43 exit(1); 44 } 45 46 // allocate the next chunk 47 void* mappedAddress = mmap(sMappedBase + sMappedSize, kMapChunkSize, 48 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 49 if (mappedAddress == MAP_FAILED) { 50 fprintf(stderr, "SIGSEGV: mmap() failed: %s\n", strerror(errno)); 51 exit(1); 52 } 53 54 printf("mapped %d bytes at %p\n", (int)kMapChunkSize, mappedAddress); 55 56 sMappedSize += kMapChunkSize; 57 58 // map the last page read-only 59 if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ) 60 < 0) { 61 fprintf(stderr, "SIGSEGV: mprotect() failed: %s\n", strerror(errno)); 62 exit(1); 63 } 64 } 65 66 67 int 68 main() 69 { 70 // install signal handler 71 if (signal(SIGSEGV, signal_handler) == SIG_ERR) { 72 fprintf(stderr, "Error: Failed to install signal handler: %s\n", 73 strerror(errno)); 74 exit(1); 75 } 76 77 // Map the complete test size plus one chunk and unmap all but the first 78 // chunk again, so no other memory gets into the way, when we mmap() the 79 // other chunks with MAP_FIXED. 80 sMappedBase = (uint8_t*)mmap(NULL, kTestSize + kMapChunkSize, 81 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 82 if (sMappedBase == MAP_FAILED) { 83 fprintf(stderr, "mmap() failed: %s\n", strerror(errno)); 84 return 1; 85 } 86 munmap(sMappedBase + kMapChunkSize, kTestSize); 87 88 sMappedSize = kMapChunkSize; 89 90 printf("mapped %d bytes at %p\n", (int)sMappedSize, sMappedBase); 91 92 if (mprotect(sMappedBase + sMappedSize - PAGE_SIZE, PAGE_SIZE, PROT_READ) 93 < 0) { 94 fprintf(stderr, "mprotect() failed: %s\n", strerror(errno)); 95 return 1; 96 } 97 98 for (int i = 0; i < 256 * PAGE_SIZE; i++) { 99 sTouchedAddress = sMappedBase + i; 100 *sTouchedAddress = 1; 101 } 102 103 printf("test finished successfully!\n"); 104 105 return 0; 106 } 107