Skip to content

Instantly share code, notes, and snippets.

@pguyot
Created February 21, 2017 09:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pguyot/0abecd6df1c59f13384440a45bd21385 to your computer and use it in GitHub Desktop.
Save pguyot/0abecd6df1c59f13384440a45bd21385 to your computer and use it in GitHub Desktop.
// 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