diff options
-rw-r--r-- | examples/afl_untracer/Makefile | 7 | ||||
-rw-r--r-- | examples/afl_untracer/afl-untracer.c | 238 | ||||
-rw-r--r-- | examples/afl_untracer/libtestinstr.c | 35 | ||||
-rw-r--r-- | src/afl-common.c | 2 |
4 files changed, 199 insertions, 83 deletions
diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile index ea20ebc0..bfef8fa8 100644 --- a/examples/afl_untracer/Makefile +++ b/examples/afl_untracer/Makefile @@ -1,7 +1,10 @@ -all: afl-untracer +all: afl-untracer libtestinstr.so afl-untracer: afl-untracer.c - $(CC) -I../../include -g -o afl-untracer afl-untracer.c -ldl + $(CC) -I../../include -g -o afl-untracer afl-untracer.c -ldl -pthread + +libtestinstr.so: libtestinstr.c + $(CC) -fPIC -o libtestinstr.so -shared libtestinstr.c clean: rm -f afl-untracer *~ core diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 112573e2..420f09a2 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -50,6 +50,7 @@ #include <errno.h> #include <dlfcn.h> #include <fcntl.h> +#include <pthread.h> #include <sys/mman.h> #include <sys/shm.h> @@ -67,14 +68,26 @@ #define MEMORY_MAP_DECREMENT 0x200000000000 #define MAX_LIB_COUNT 128 -#ifdef __ANDROID__ -u32 __afl_map_size = MAP_SIZE; -#else -__thread u32 __afl_map_size = MAP_SIZE; -#endif +// STEP 1: + +/* use stdin (1) or a file on the commandline (0) */ +static u32 use_stdin = 1; + +/* This is were the testcase data is written into */ +static u8 buf[10000]; // this is the maximum size for a test case! set it! -u8 __afl_dummy[MAP_SIZE]; -u8 *__afl_area_ptr = __afl_dummy; +/* if you want to use fork() then uncomment the following line. Otherwise + threads are used. The differences: + fork() pthread() + speed slow fast + coverage detailed minimal + memory leaks no problem an issue */ +//#define USE_FORK + +/* If you want to have debug output set this to 1 */ +static u32 debug = 1; + +// END STEP 1 typedef struct library_list { @@ -83,11 +96,26 @@ typedef struct library_list { } library_list_t; -library_list_t liblist[MAX_LIB_COUNT]; -u32 liblist_cnt; -u32 use_stdin = 1; +#ifdef __ANDROID__ +u32 __afl_map_size = MAP_SIZE; +u32 do_exit; +#else +__thread u32 __afl_map_size = MAP_SIZE; +__thread u32 do_exit; +#endif + +static pid_t pid = 65537; +static pthread_t __afl_thread; +static u8 __afl_dummy[MAP_SIZE]; +static u8 * __afl_area_ptr = __afl_dummy; +static u8 * inputfile; // this will point to argv[1] +static u32 len; + +static library_list_t liblist[MAX_LIB_COUNT]; +static u32 liblist_cnt; static void sigtrap_handler(int signum, siginfo_t *si, void *context); +static void fuzz(); /* read the library information */ void read_library_information() { @@ -99,7 +127,7 @@ void read_library_information() { if ((f = fopen("/proc/self/maps", "r")) == NULL) FATAL("cannot open /proc/self/maps"); - fprintf(stderr, "Library list:\n"); + if (debug) fprintf(stderr, "Library list:\n"); while (fgets(buf, sizeof(buf), f)) { if (strstr(buf, " r-xp ")) { @@ -130,9 +158,10 @@ void read_library_information() { liblist[liblist_cnt].name = strdup(n); liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); - fprintf(stderr, "%s:%x (%x-%x)\n", liblist[liblist_cnt].name, - liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, - liblist[liblist_cnt].addr_start, liblist[liblist_cnt].addr_end); + if (debug) + fprintf(stderr, "%s:%x (%x-%x)\n", liblist[liblist_cnt].name, + liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, + liblist[liblist_cnt].addr_start, liblist[liblist_cnt].addr_end); liblist_cnt++; } @@ -141,7 +170,7 @@ void read_library_information() { } - fprintf(stderr, "\n"); + if (debug) fprintf(stderr, "\n"); #endif @@ -300,7 +329,6 @@ static void __afl_map_shm(void) { } /* Fork server logic. */ - static void __afl_start_forkserver(void) { u8 tmp[4] = {0, 0, 0, 0}; @@ -312,36 +340,46 @@ static void __afl_start_forkserver(void) { memcpy(tmp, &status, 4); /* Phone home and tell the parent that we're OK. */ - - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (write(FORKSRV_FD + 1, tmp, 4) != 4) do_exit = 1; + // fprintf(stderr, "write0 %d\n", do_exit); } static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - s32 status, res = 0xffffff; + s32 status; /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &status, 4) != 4) return 0; + if (read(FORKSRV_FD, &status, 4) != 4) do_exit = 1; + // fprintf(stderr, "read %d\n", do_exit); /* we have a testcase - read it if we read from stdin */ - if (use_stdin) status = read(0, buf, max_len); + if (use_stdin) { + + if ((status = read(0, buf, max_len)) <= 0) exit(-1); + + } else + + status = 1; + // fprintf(stderr, "stdin: %d %d\n", use_stdin, status); /* report that we are starting the target */ - if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; + if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1; + // fprintf(stderr, "write1 %d\n", do_exit); - if (status < 1) - return 0; - else - return status; + if (!do_exit) + __afl_area_ptr[0] = 1; // otherwise afl-fuzz will exit with NOINST + return status; } static void __afl_end_testcase(void) { - int status = 0xffffff; - - if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); + s32 res = 0xffffff; + if (write(FORKSRV_FD + 1, &res, 4) != 4) do_exit = 1; + // if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1; + // fprintf(stderr, "write2 %d\n", do_exit); + if (do_exit) exit(0); } @@ -365,7 +403,7 @@ void setup_trap_instrumentation() { if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename); // Index into the coverage bitmap for the current trap instruction. - int bitmap_index = -1; + int bitmap_index = 0; while ((nread = getline(&line, &len, patches)) != -1) { @@ -403,8 +441,9 @@ void setup_trap_instrumentation() { void *shadow_addr = SHADOW(lib_addr + i); void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0); - fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow, - shadow + lib_size - 1, lib_addr); + if (debug) + fprintf(stderr, "Shadow: %s %d = %p-%p for %p\n", line, i, shadow, + shadow + lib_size - 1, lib_addr); if (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory"); } @@ -420,38 +459,39 @@ void setup_trap_instrumentation() { FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large", offset, lib_size); - bitmap_index++; - if (bitmap_index >= __afl_map_size) FATAL("Too many basic blocks to instrument"); uint32_t *shadow = SHADOW(lib_addr + offset); - if (*shadow != 0) FATAL("Potentially duplicate patch entry: 0x%lx", offset); + if (*shadow != 0) FATAL("Duplicate patch entry: 0x%lx", offset); - // Make lookup entry in shadow memory. + // Make lookup entry in shadow memory. #if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__)) // this is for Intel x64 uint8_t orig_byte = lib_addr[offset]; *shadow = (bitmap_index << 8) | orig_byte; lib_addr[offset] = 0xcc; // replace instruction with debug trap - fprintf(stderr, - "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %08x\n", - lib_addr, offset, lib_addr + offset, orig_byte, shadow, - bitmap_index, *shadow); + if (debug) + fprintf(stderr, + "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %08x\n", + lib_addr, offset, lib_addr + offset, orig_byte, shadow, + bitmap_index, *shadow); #else - // this will be ARM and AARCH64 - // for ARM we will need to identify if the code is in thumb or ARM + // this will be ARM and AARCH64 + // for ARM we will need to identify if the code is in thumb or ARM #error "non x86_64 not supported yet" - //__arm__ - // linux thumb: 0xde01 - // linux thumb2: 0xf7f0a000 - // linux arm: 0xe7f001f0 - //__aarch64__ - // linux aarch64: 0xd4200000 + //__arm__ + // linux thumb: 0xde01 + // linux thumb2: 0xf7f0a000 + // linux arm: 0xe7f001f0 + //__aarch64__ + // linux aarch64: 0xd4200000 #endif + bitmap_index++; + } free(line); @@ -464,7 +504,7 @@ void setup_trap_instrumentation() { sigemptyset(&s.sa_mask); sigaction(SIGTRAP, &s, 0); - fprintf(stderr, "Patched %u locations.\n", bitmap_index); + if (debug) fprintf(stderr, "Patched %u locations.\n", bitmap_index); __afl_map_size = bitmap_index; if (__afl_map_size % 8) __afl_map_size = (((__afl_map_size + 7) >> 3) << 3); @@ -485,8 +525,9 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { #error "Unsupported platform" #endif - fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr, - si->si_addr); + if (debug) + fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr, + si->si_addr); // If the trap didn't come from our instrumentation, then we probably will // just segfault here @@ -496,13 +537,15 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { else faultaddr = (u8 *)addr; // u8 *loc = SHADOW(faultaddr); - fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr)); + if (debug) + fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr)); uint32_t shadow = *SHADOW(faultaddr); uint8_t orig_byte = shadow & 0xff; uint32_t index = shadow >> 8; - fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n", shadow, - orig_byte, index); + if (debug) + fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n", shadow, + orig_byte, index); // Index zero is invalid so that it is still possible to catch actual trap // instructions in instrumented libraries. @@ -516,62 +559,77 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { } /* here you need to specify the parameter for the target function */ -static void *(*o_TIFFOpen)(char *filename, char *mode); -static void *(*o_TIFFClose)(u8 *file); +static void *(*o_function)(u8 *buf, int len); int main(int argc, char *argv[]) { - // STEP 1: use stdin or filename via commandline and set the maximum - // size for a test case + pid = getpid(); + if (getenv("AFL_DEBUG")) debug = 1; /* by default we use stdin, but also a filename can be passed, in this case the input is argv[1] and we have to disable stdin */ - if (argc > 1) use_stdin = 0; + if (argc > 1) { - /* This is were the testcase data is written into */ - u8 buf[10000]; // this is the maximum size for a test case! set it! + use_stdin = 0; + inputfile = argv[1]; - // END STEP 1 + } // STEP 2: load the library you want to fuzz and lookup the functions, // inclusive of the cleanup functions // NOTE: above the main() you have to define the functions! /* setup the target */ - void *dl = dlopen("/prg/tests/libtiff.so", RTLD_LAZY); + void *dl = dlopen("./libtestinstr.so", RTLD_LAZY); if (!dl) FATAL("could not find target library"); - o_TIFFOpen = dlsym(dl, "TIFFOpen"); - if (!o_TIFFOpen) FATAL("could not resolve target function from library"); - o_TIFFClose = dlsym(dl, "TIFFClose"); - if (!o_TIFFClose) FATAL("could not resolve target function from library"); + o_function = dlsym(dl, "testinstr"); + if (!o_function) FATAL("could not resolve target function from library"); // END STEP 2 /* setup instrumentation, shared memory and forkserver */ - u32 len; read_library_information(); setup_trap_instrumentation(); __afl_map_shm(); __afl_start_forkserver(); - while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { + while (1) { -// -> this still needs threading otherwise fuzzing stops when we crash +#ifdef USE_FORK + if ((pid = fork()) == -1) PFATAL("fork failed"); + if (pid) { - // STEP 3: call the function to fuzz, also the functions you might - // need to call to prepare the function and - important! - - // to clean everything up + u32 status; + if (waitpid(pid, &status, 0) < 0) exit(1); - // in this example we use the input file, not stdin! - u8 *file (*o_function)(argv[1], "wl"); + } else { - // we have to release memory - if (file) (void)(*o_TIFFClose)(file); +#endif - // END STEP 3 + pid = getpid(); + while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - /* report the test case is done and wait for the next */ - __afl_end_testcase(); +#ifdef USE_FORK + fuzz(); +#else + if (pthread_create(&__afl_thread, NULL, (void *)fuzz, NULL) != 0) + PFATAL("cannot create thread"); + pthread_join(__afl_thread, NULL); +#endif + + /* report the test case is done and wait for the next */ + __afl_end_testcase(); +#ifdef USE_FORK + exit(0); +#endif + + } + +#ifdef USE_FORK + + } + +#endif } @@ -579,3 +637,23 @@ int main(int argc, char *argv[]) { } +static void fuzz() { + + // STEP 3: call the function to fuzz, also the functions you might + // need to call to prepare the function and - important! - + // to clean everything up + + // in this example we use the input file, not stdin! + (*o_function)(buf, len); + + // normally you also need to cleanup + //(*o_LibFree)(foo); + + // END STEP 3 + +#ifndef USE_FORK + pthread_exit(NULL); +#endif + +} + diff --git a/examples/afl_untracer/libtestinstr.c b/examples/afl_untracer/libtestinstr.c new file mode 100644 index 00000000..b21c3db5 --- /dev/null +++ b/examples/afl_untracer/libtestinstr.c @@ -0,0 +1,35 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +void testinstr(char *buf, int len) { + + if (len < 1) + return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} diff --git a/src/afl-common.c b/src/afl-common.c index dda62219..8f21ad94 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -71,7 +71,7 @@ char *afl_environment_variables[] = { "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", - "AFL_NO_UI", "AFL_NO_PYTHON", + "AFL_NO_UI", "AFL_NO_PYTHON", "AFL_UNTRACER_FILE", "AFL_NO_X86", // not really an env but we dont want to warn on it "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE", //"AFL_PERSISTENT", // not implemented anymore, so warn additionally |