Created
February 21, 2017 09:22
-
-
Save pguyot/0abecd6df1c59f13384440a45bd21385 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// POSIX-compliant (?) prototype to test mapping small pages and getting signals on protected accesses. | |
#include <sys/mman.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <signal.h> | |
#include <stdlib.h> | |
#include <setjmp.h> | |
static void* first_page; | |
static void* second_page; | |
static void* third_page; | |
static void* fourth_page; | |
static sigjmp_buf env; | |
static int fault = 0; | |
void handler(int signal, siginfo_t * info, void* context) { | |
printf("SIGBUS at %p\n", info->si_addr); | |
// just remap for writing or exit with siglongjump | |
if ((void*) ((unsigned long long) info->si_addr &~ 0xfff) == second_page) { | |
int r = mprotect(second_page, getpagesize(), PROT_READ | PROT_WRITE); | |
} else { | |
fault++; | |
siglongjmp(env, 1); | |
} | |
} | |
int main() { | |
int pagesize = getpagesize(); | |
printf("pagesize = %i\n", pagesize); | |
// Ask a first page | |
first_page = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); | |
printf("first_page at %p\n", first_page); | |
second_page = mmap(first_page + pagesize, pagesize, PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); | |
printf("second_page at %p\n", second_page); | |
third_page = mmap(second_page + pagesize, pagesize, PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); | |
printf("third_page at %p\n", third_page); | |
fourth_page = mmap(third_page + pagesize, pagesize, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); | |
printf("fourth_page at %p\n", fourth_page); | |
// Install handler | |
struct sigaction act; | |
act.sa_flags = SA_SIGINFO; | |
act.sa_sigaction = handler; | |
act.sa_mask = 0; | |
sigaction(SIGBUS, &act, NULL); | |
char c; | |
// Install sigsetjmp. | |
sigsetjmp(env, 1); | |
if (fault == 0) { | |
printf("reading first_page...\n"); | |
c = *((char*) first_page); | |
printf("writing first_page...\n"); | |
((char*) first_page)[0] = c + 1; | |
printf("reading second_page...\n"); | |
c = *((char*) second_page); | |
printf("writing second_page... (this will call our handler which will change protection)\n"); | |
((char*) second_page)[0] = c + 1; | |
printf("reading third_page... (this should call our handler and abort, but doesn't on MacOS X as PROT_WRITE implies PROT_READ)\n"); | |
c = *((char*) third_page); | |
printf("writing third_page...\n"); | |
((char*) third_page)[0] = c + 1; | |
printf("reading fourth_page... (this will call our handler and we will jump to the fault handler below)\n"); | |
c = *((char*) fourth_page); | |
printf("writing fourth_page...\n"); | |
((char*) fourth_page)[0] = c + 1; | |
} else if (fault == 1) { | |
printf("Got a first fault...\n"); | |
printf("writing fourth_page... (this will call our handler again and we will jump to the second fault handler)\n"); | |
((char*) fourth_page)[0] = c + 1; | |
} else if (fault == 2) { | |
printf("Got a second fault...\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment