Created
April 12, 2017 23:43
-
-
Save FauxFaux/9032a665250fbcbe6fe6060ebe93a14f to your computer and use it in GitHub Desktop.
Repairing a SIGBUS from an OOB read of an mmap'd file
This file contains hidden or 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
#include <assert.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stddef.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
#include <signal.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
char *ptr; | |
int fd; | |
const size_t range = 1024*1024*1024; | |
volatile sig_atomic_t resized = 0; | |
static void handler(int sig, siginfo_t *si, void *unused) { | |
char *read_addr = si->si_addr; | |
ptrdiff_t diff = read_addr - ptr; | |
// if it's within the bounds of our mapped range.. | |
if (diff >= 0 && diff <= range) { | |
// if the file is already big enough, panic! | |
off_t size = lseek(fd, 0, SEEK_END); | |
if (diff <= size || -1 == size) { | |
exit(67); | |
} | |
// enlarge the file so the read can succeed | |
if (ftruncate(fd, diff)) { | |
exit(68); | |
} | |
// report error | |
resized = 1 + size; | |
} else { | |
exit(69); | |
} | |
} | |
int main() { | |
fd = open("data", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); | |
if (fd < 0) { | |
perror("open"); | |
return 3; | |
} | |
ptr = mmap(NULL, range, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | |
if (-1 == ptr) { | |
perror("mmap"); | |
return 3; | |
} | |
struct sigaction sa = {}; | |
sa.sa_flags = SA_SIGINFO; | |
sigemptyset(&sa.sa_mask); | |
sa.sa_sigaction = &handler; | |
assert(-1 != sigaction(SIGBUS, &sa, NULL)); | |
char found = ptr[9005]; | |
if (resized) { | |
printf("first reading failed, fixing file back to original observed length: %d\n", resized - 1); | |
if (ftruncate(fd, resized - 1)) { | |
perror("couldn't retruncate"); | |
} | |
return 5; | |
} else { | |
printf("first read success: %d\n", (int)found); | |
} | |
char found2 = ptr[90005]; | |
if (resized) { | |
printf("second reading failed, fixing file back to original observed length: %d\n", resized - 1); | |
if (ftruncate(fd, resized - 1)) { | |
perror("couldn't retruncate"); | |
} | |
return 6; | |
} else { | |
printf("second read success: %d\n", (int)found2); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment