aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-04-30 16:27:31 +0200
committervan Hauser <vh@thc.org>2020-04-30 16:27:31 +0200
commita37eca9df538a4184551244d435e027ca86ccb25 (patch)
tree78597b8a03f2a54e7384a5ba6b4305c82caf5585
parente68d2345d5c301dfdf7df3a86ccb0d9eb0aabbbd (diff)
downloadafl++-a37eca9df538a4184551244d435e027ca86ccb25.tar.gz
afl-untracer - next step
-rw-r--r--examples/afl_untracer/Makefile7
-rw-r--r--examples/afl_untracer/afl-untracer.c238
-rw-r--r--examples/afl_untracer/libtestinstr.c35
-rw-r--r--src/afl-common.c2
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