From a37eca9df538a4184551244d435e027ca86ccb25 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 30 Apr 2020 16:27:31 +0200 Subject: afl-untracer - next step --- src/afl-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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 -- cgit 1.4.1 From efa9df24c2a5f97c212a5a22dda19dcbbab0b5de Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 30 Apr 2020 17:59:59 +0200 Subject: afl-untracer completed --- docs/Changelog.md | 2 + examples/afl_network_proxy/README.md | 11 +++ examples/afl_network_proxy/afl-network-client.c | 23 +++--- examples/afl_network_proxy/afl-network-server.c | 2 + examples/afl_untracer/Makefile | 2 +- examples/afl_untracer/README.md | 7 +- examples/afl_untracer/afl-untracer.c | 96 +++++++++++-------------- examples/afl_untracer/patches.txt | 23 ++++++ include/forkserver.h | 1 + src/afl-forkserver.c | 14 ++-- 10 files changed, 106 insertions(+), 75 deletions(-) create mode 100644 examples/afl_untracer/patches.txt (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index faf015c6..565bee72 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,6 +31,8 @@ sending a mail to . - added examples/afl_network_proxy which allows to fuzz a target over the network (not fuzzing tcp/ip services but running afl-fuzz on one system and the target being on an embedded device) + - added examples/afl_untracer which does a binary-only fuzzing with the + modifications done in memory - added examples/afl_proxy which can be easily used to fuzz and instrument non-standard things - all: diff --git a/examples/afl_network_proxy/README.md b/examples/afl_network_proxy/README.md index 65012601..c33096be 100644 --- a/examples/afl_network_proxy/README.md +++ b/examples/afl_network_proxy/README.md @@ -20,6 +20,7 @@ e.g.: ``` $ afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@ ``` + ### on the fuzzing master Just run afl-fuzz with your normal options, however the target should be @@ -42,3 +43,13 @@ either. Note that also the outgoing interface can be specified with a '%' for ## how to compile and install `make && sudo make install` + +## Future + +It would be much faster and more effective if `afl-network-server` does not +send the map data back (64kb or more) but the checksum that `afl-fuzz` would +generate. This change however would make it incompatible with existing +afl spinoffs. + +But in the future this will be implemented and supported as a compile option. + diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c index ede2ff8d..53512286 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -175,7 +175,7 @@ static void __afl_start_forkserver(void) { static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - s32 status, res = 0xffffff; + s32 status, res = 0x0fffffff; // res is a dummy pid /* Wait for parent by reading from the pipe. Abort if read fails. */ if (read(FORKSRV_FD, &status, 4) != 4) return 0; @@ -193,9 +193,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { } -static void __afl_end_testcase(void) { - - int status = 0xffffff; +static void __afl_end_testcase(int status) { if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); @@ -273,7 +271,7 @@ int main(int argc, char *argv[]) { __afl_map_shm(); __afl_start_forkserver(); - int i = 1, j; + int i = 1, j, status, ret; // fprintf(stderr, "Waiting for first testcase\n"); while ((len = __afl_next_testcase(buf, max_len)) > 0) { @@ -281,17 +279,25 @@ int main(int argc, char *argv[]) { if (send(s, &len, 4, 0) != 4) PFATAL("sending size data %d failed", len); if (send(s, buf, len, 0) != len) PFATAL("sending test data failed"); - int received = 0, ret; + int received = 0; + while (received < 4 && + (ret = recv(s, &status + received, 4 - received, 0)) > 0) + received += ret; + if (received != 4) + FATAL("did not receive waitpid data (%d, %d)", received, ret); + // fprintf(stderr, "Received status\n"); + + int received = 0; while (received < __afl_map_size && (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received, 0)) > 0) received += ret; if (received != __afl_map_size) - FATAL("did not receive valid data (%d, %d)", received, ret); + FATAL("did not receive coverage data (%d, %d)", received, ret); // fprintf(stderr, "Received coverage\n"); /* report the test case is done and wait for the next */ - __afl_end_testcase(); + __afl_end_testcase(status); // fprintf(stderr, "Waiting for next testcase %d\n", ++i); } @@ -299,4 +305,3 @@ int main(int argc, char *argv[]) { return 0; } - diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index 1bd37560..2f9f8c8e 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -579,6 +579,8 @@ int main(int argc, char **argv_orig, char **envp) { // fprintf(stderr, "received %u\n", in_len); run_target(fsrv, use_argv, in_data, in_len, 1); + if (send(s, fsrv->child_status, 4, 0) != 4) + FATAL("could not send waitpid data"); if (send(s, fsrv->trace_bits, fsrv->map_size, 0) != fsrv->map_size) FATAL("could not send coverage data"); // fprintf(stderr, "sent result\n"); diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile index bfef8fa8..5c525877 100644 --- a/examples/afl_untracer/Makefile +++ b/examples/afl_untracer/Makefile @@ -7,4 +7,4 @@ libtestinstr.so: libtestinstr.c $(CC) -fPIC -o libtestinstr.so -shared libtestinstr.c clean: - rm -f afl-untracer *~ core + rm -f afl-untracer libtestinstr.so *~ core diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md index 90798028..d3af0ceb 100644 --- a/examples/afl_untracer/README.md +++ b/examples/afl_untracer/README.md @@ -3,9 +3,14 @@ afl-untracer is an example skeleton file which can easily be used to fuzz a closed source library. -It is faster and requires less memory than qemu_mode however it is way +It requires less memory than qemu_mode however it is way more course grained and does not provide interesting features like compcov or cmplog. Read and modify afl-untracer.c then `make` and use it as the afl-fuzz target (or even remote via afl-network-proxy). + +This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL) +and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz). +This implementation is slower because the traps are not patched out with each +run, but on the other hand gives much better coverage information. diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 420f09a2..4d512356 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -76,16 +76,9 @@ 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! -/* 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; +/* If you want to have debug output set this to 1, can also be set with + AFL_DEBUG */ +static u32 debug = 0; // END STEP 1 @@ -130,7 +123,7 @@ void read_library_information() { if (debug) fprintf(stderr, "Library list:\n"); while (fgets(buf, sizeof(buf), f)) { - if (strstr(buf, " r-xp ")) { + if (strstr(buf, " r-x")) { if (liblist_cnt >= MAX_LIB_COUNT) { @@ -159,9 +152,9 @@ void read_library_information() { liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); if (debug) - fprintf(stderr, "%s:%x (%x-%x)\n", liblist[liblist_cnt].name, + fprintf(stderr, "%s:%x (%lx-%lx)\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[liblist_cnt].addr_start, liblist[liblist_cnt].addr_end - 1); liblist_cnt++; } @@ -367,17 +360,13 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1; // fprintf(stderr, "write1 %d\n", do_exit); - if (!do_exit) - __afl_area_ptr[0] = 1; // otherwise afl-fuzz will exit with NOINST return status; } -static void __afl_end_testcase(void) { +static void __afl_end_testcase(int status) { - 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; + if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1; // fprintf(stderr, "write2 %d\n", do_exit); if (do_exit) exit(0); @@ -455,6 +444,19 @@ void setup_trap_instrumentation() { // It's an offset, parse it and do the patching. unsigned long offset = strtoul(line, NULL, 16); + + // I dont know what it is. /proc//maps shows the right start address + // and the offsets generated by the python scripts are fine as well. + // And loading the library into gdb also shows the offsets generated + // by the script are correct. However when loaded via dlopen the first + // 0x1000 are skipped ... +#if defined(__linux__) + if (offset >= 0x1000) + offset -= 0x1000; + else + fprintf(stderr, "Warning: offset is < 0x1000: %x\n", offset); +#endif + if (offset > lib_size) FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large", offset, lib_size); @@ -482,11 +484,10 @@ void setup_trap_instrumentation() { // 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__ + //__arm__: // linux thumb: 0xde01 - // linux thumb2: 0xf7f0a000 // linux arm: 0xe7f001f0 - //__aarch64__ + //__aarch64__: // linux aarch64: 0xd4200000 #endif @@ -510,6 +511,8 @@ void setup_trap_instrumentation() { } +/* the signal handler for the traps / debugging interrupts + No debug output here because this would cost speed */ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { uint64_t addr; @@ -525,31 +528,25 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { #error "Unsupported platform" #endif - if (debug) - fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr, - si->si_addr); + //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 uint8_t *faultaddr; - if (si->si_addr) + if (unlikely(si->si_addr)) faultaddr = (u8 *)si->si_addr - 1; else faultaddr = (u8 *)addr; - // u8 *loc = SHADOW(faultaddr); - if (debug) - 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; - if (debug) - 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. - if (index == 0) abort(); + if (unlikely(index == 0)) abort(); // Restore original instruction *faultaddr = orig_byte; @@ -561,6 +558,7 @@ 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_function)(u8 *buf, int len); +/* the MAIN function */ int main(int argc, char *argv[]) { pid = getpid(); @@ -579,11 +577,11 @@ int main(int argc, char *argv[]) { // inclusive of the cleanup functions // NOTE: above the main() you have to define the functions! - /* setup the target */ void *dl = dlopen("./libtestinstr.so", RTLD_LAZY); if (!dl) FATAL("could not find target library"); o_function = dlsym(dl, "testinstr"); if (!o_function) FATAL("could not resolve target function from library"); + if (debug) fprintf(stderr, "Function address: %p\n", o_function); // END STEP 2 @@ -595,42 +593,33 @@ int main(int argc, char *argv[]) { while (1) { -#ifdef USE_FORK if ((pid = fork()) == -1) PFATAL("fork failed"); + if (pid) { u32 status; if (waitpid(pid, &status, 0) < 0) exit(1); + /* report the test case is done and wait for the next */ + __afl_end_testcase(status); } else { -#endif pid = getpid(); while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { -#ifdef USE_FORK + // in this function the fuzz magic happens, this is STEP 3 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 + // we can use _exit which is faster because our target library + // was loaded via dlopen and there cannot have deconstructors + // registered. + _exit(0); } -#ifdef USE_FORK - } -#endif - } return 0; @@ -651,9 +640,4 @@ static void fuzz() { // END STEP 3 -#ifndef USE_FORK - pthread_exit(NULL); -#endif - } - diff --git a/examples/afl_untracer/patches.txt b/examples/afl_untracer/patches.txt new file mode 100644 index 00000000..b3063e3a --- /dev/null +++ b/examples/afl_untracer/patches.txt @@ -0,0 +1,23 @@ +libtestinstr.so:0x2000L +0x1050L +0x1063L +0x106fL +0x1078L +0x1080L +0x10a4L +0x10b0L +0x10b8L +0x10c0L +0x10c9L +0x10d7L +0x10e3L +0x10f8L +0x1100L +0x1105L +0x111aL +0x1135L +0x1143L +0x114eL +0x115cL +0x116aL +0x116bL diff --git a/include/forkserver.h b/include/forkserver.h index 3c473572..7e7784f5 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -43,6 +43,7 @@ typedef struct afl_forkserver { s32 fsrv_pid, /* PID of the fork server */ child_pid, /* PID of the fuzzed program */ + child_status, /* waitpid result for the child */ out_dir_fd; /* FD of the lock file */ s32 out_fd, /* Persistent fd for fsrv->out_file */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index d5a60077..a9e2175d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -790,8 +790,6 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, s32 res; u32 exec_ms; - int status = 0; - /* After this memset, fsrv->trace_bits[] are effectively volatile, so we must prevent any earlier operations from venturing into that territory. */ @@ -821,7 +819,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (fsrv->child_pid <= 0) { FATAL("Fork server is misbehaving (OOM?)"); } - exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, stop_soon_p); + exec_ms = read_timed(fsrv->fsrv_st_fd, &fsrv->child_status, 4, timeout, stop_soon_p); if (exec_ms > timeout) { @@ -830,7 +828,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, kill(fsrv->child_pid, SIGKILL); fsrv->last_run_timed_out = 1; - if (read(fsrv->fsrv_st_fd, &status, 4) < 4) { exec_ms = 0; } + if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; } } @@ -862,7 +860,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } - if (!WIFSTOPPED(status)) { fsrv->child_pid = 0; } + if (!WIFSTOPPED(fsrv->child_status)) { fsrv->child_pid = 0; } fsrv->total_execs++; @@ -874,9 +872,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* Report outcome to caller. */ - if (WIFSIGNALED(status) && !*stop_soon_p) { + if (WIFSIGNALED(fsrv->child_status) && !*stop_soon_p) { - fsrv->last_kill_signal = WTERMSIG(status); + fsrv->last_kill_signal = WTERMSIG(fsrv->child_status); if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL) { @@ -891,7 +889,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and must use a special exit code. */ - if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { + if (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) { fsrv->last_kill_signal = 0; return FSRV_RUN_CRASH; -- cgit 1.4.1 From cc78fb721b9abbafadde81068b8a98ffd3ef9ed2 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 1 May 2020 01:11:54 +0200 Subject: code format --- examples/afl_network_proxy/afl-network-client.c | 3 +- examples/afl_untracer/afl-untracer.c | 78 ++++++++++++------------- examples/afl_untracer/libtestinstr.c | 4 +- src/afl-forkserver.c | 3 +- 4 files changed, 44 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c index b510aa14..b9cd88f0 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -175,7 +175,7 @@ static void __afl_start_forkserver(void) { static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - s32 status, res = 0x0fffffff; // res is a dummy pid + s32 status, res = 0x0fffffff; // res is a dummy pid /* Wait for parent by reading from the pipe. Abort if read fails. */ if (read(FORKSRV_FD, &status, 4) != 4) return 0; @@ -305,3 +305,4 @@ int main(int argc, char *argv[]) { return 0; } + diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 9f9ea3f1..5338bfd5 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -155,9 +155,11 @@ void read_library_information() { liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); if (debug) - fprintf(stderr, "%s:%x (%lx-%lx)\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 - 1); + fprintf( + stderr, "%s:%x (%lx-%lx)\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 - 1); liblist_cnt++; } @@ -170,25 +172,17 @@ void read_library_information() { #elif defined(__FreeBSD__) int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; - char *buf, *start, *end; + char * buf, *start, *end; size_t miblen = sizeof(mib) / sizeof(mib[0]); size_t len; if (debug) fprintf(stderr, "Library list:\n"); - if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { - - return; - - } + if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; } len = len * 4 / 3; buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); - if (buf == MAP_FAILED) { - - return; - - } + if (buf == MAP_FAILED) { return; } if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { @@ -205,31 +199,33 @@ void read_library_information() { struct kinfo_vmentry *region = (struct kinfo_vmentry *)start; size_t size = region->kve_structsize; - if (size == 0) { - - break; - - } + if (size == 0) { break; } if ((region->kve_protection & KVME_PROT_READ) && !(region->kve_protection & KVME_PROT_EXEC)) { - liblist[liblist_cnt].name = region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0; - liblist[liblist_cnt].addr_start = region->kve_start; - liblist[liblist_cnt].addr_end = region->kve_end; + liblist[liblist_cnt].name = + region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0; + liblist[liblist_cnt].addr_start = region->kve_start; + liblist[liblist_cnt].addr_end = region->kve_end; - if (debug) { - fprintf(stderr, "%s:%x (%lx-%lx)\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 - 1); - } + if (debug) { + + fprintf(stderr, "%s:%x (%lx-%lx)\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 - 1); + + } + + liblist_cnt++; - liblist_cnt++; } start += size; } + #endif } @@ -532,7 +528,7 @@ void setup_trap_instrumentation() { uint32_t *shadow = SHADOW(lib_addr + 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 @@ -546,14 +542,14 @@ void setup_trap_instrumentation() { 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 arm: 0xe7f001f0 - //__aarch64__: - // linux aarch64: 0xd4200000 + //__arm__: + // linux thumb: 0xde01 + // linux arm: 0xe7f001f0 + //__aarch64__: + // linux aarch64: 0xd4200000 #endif bitmap_index++; @@ -596,7 +592,8 @@ 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); + // 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 @@ -605,12 +602,13 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { faultaddr = (u8 *)si->si_addr - 1; else faultaddr = (u8 *)addr; - //if (debug) 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; - //if (debug) 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. @@ -672,7 +670,6 @@ int main(int argc, char *argv[]) { } else { - pid = getpid(); while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { @@ -709,3 +706,4 @@ static void fuzz() { // END STEP 3 } + diff --git a/examples/afl_untracer/libtestinstr.c b/examples/afl_untracer/libtestinstr.c index b21c3db5..96b1cf21 100644 --- a/examples/afl_untracer/libtestinstr.c +++ b/examples/afl_untracer/libtestinstr.c @@ -20,8 +20,7 @@ void testinstr(char *buf, int len) { - if (len < 1) - return; + if (len < 1) return; buf[len] = 0; // we support three input cases @@ -33,3 +32,4 @@ void testinstr(char *buf, int len) { printf("Neither one or zero? How quaint!\n"); } + diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a9e2175d..c1623f22 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -819,7 +819,8 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (fsrv->child_pid <= 0) { FATAL("Fork server is misbehaving (OOM?)"); } - exec_ms = read_timed(fsrv->fsrv_st_fd, &fsrv->child_status, 4, timeout, stop_soon_p); + exec_ms = read_timed(fsrv->fsrv_st_fd, &fsrv->child_status, 4, timeout, + stop_soon_p); if (exec_ms > timeout) { -- cgit 1.4.1 From 378573ab8b2f9b150429503c649e86e0fed4e946 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 2 May 2020 00:39:13 +0200 Subject: AFL_LLVM_SKIP_NEVERZERO added --- docs/Changelog.md | 3 +++ docs/env_variables.md | 4 ++++ llvm_mode/LLVMInsTrim.so.cc | 5 +++-- llvm_mode/README.neverzero.md | 10 +++++++++- llvm_mode/afl-clang-fast.c | 6 ++++++ llvm_mode/afl-llvm-lto-instrumentation.so.cc | 14 +++++++++++--- llvm_mode/afl-llvm-pass.so.cc | 10 +++++----- src/afl-common.c | 7 ++++--- 8 files changed, 45 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 565bee72..cae99681 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,9 @@ sending a mail to . address for the shared memory map is used as this increases the fuzzing speed - fixes to LTO mode if instrumented edges > MAP_SIZE + - added AFL_LLVM_SKIP_NEVERZERO to skip the never zero coverage counter + implmentation. For targets with little or no loops or heavy called + functions. Gives a small performance boost. - qemu_mode: - add information on PIE/PIC load addresses for 32 bit - better dependency checks diff --git a/docs/env_variables.md b/docs/env_variables.md index 41c8f12a..bdbb8520 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -204,6 +204,10 @@ Then there are a few specific features that are only available in llvm_mode: slowdown due a performance issue that is only fixed in llvm 9+. This feature increases path discovery by a little bit. + - Setting AFL_LLVM_SKIP_NEVERZERO=1 will not implement the skip zero + test. If the target performs only few loops then this will give a + small performance boost. + See llvm_mode/README.neverzero.md ### CMPLOG diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index 98263ef1..c78250eb 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -56,6 +56,7 @@ struct InsTrim : public ModulePass { protected: uint32_t function_minimum_size = 1; uint32_t debug = 0; + char * skip_nozero = NULL; private: std::mt19937 generator; @@ -112,6 +113,7 @@ struct InsTrim : public ModulePass { if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL) if (!be_quiet) OKF("LLVM neverZero activated (by hexcoder)\n"); #endif + skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); if (getenv("AFL_LLVM_INSTRIM_LOOPHEAD") != NULL || getenv("LOOPHEAD") != NULL) { @@ -304,8 +306,7 @@ struct InsTrim : public ModulePass { NULL) // with llvm 9 we make this the default as the bug in llvm is // then fixed #else - if (1) // with llvm 9 we make this the default as the bug in llvm is - // then fixed + if (!skip_nozero) #endif { diff --git a/llvm_mode/README.neverzero.md b/llvm_mode/README.neverzero.md index 1e406560..903e5bd3 100644 --- a/llvm_mode/README.neverzero.md +++ b/llvm_mode/README.neverzero.md @@ -20,8 +20,16 @@ This is implemented in afl-gcc, however for llvm_mode this is optional if the llvm version is below 9 - as there is a perfomance bug that is only fixed in version 9 and onwards. -If you want to enable this for llvm < 9 then set +If you want to enable this for llvm versions below 9 then set ``` export AFL_LLVM_NOT_ZERO=1 ``` + +In case you are on llvm 9 or greater and you do not want this behaviour then +you can set: +``` +AFL_LLVM_SKIP_NEVERZERO=1 +``` +If the target does not have extensive loops or functions that are called +a lot then this can give a small performance boost. diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 3de5fd7d..c59b814d 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -562,6 +562,11 @@ int main(int argc, char **argv, char **envp) { instrument_mode = INSTRUMENT_PCGUARD; #endif + if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO")) + FATAL( + "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set " + "together"); + if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) != NULL) { if (strncasecmp(ptr, "default", strlen("default")) == 0 || @@ -726,6 +731,7 @@ int main(int argc, char **argv, char **envp) { "AFL_HARDEN: adds code hardening to catch memory bugs\n" "AFL_INST_RATIO: percentage of branches to instrument\n" "AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n" + "AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n" "AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n" "AFL_LLVM_LAF_SPLIT_FLOATS: transform floating point comp. to " "cascaded " diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 118ada52..2811d98e 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -78,6 +78,8 @@ class AFLLTOPass : public ModulePass { FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n", ptr, MAP_SIZE - 1); + skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -111,6 +113,7 @@ class AFLLTOPass : public ModulePass { int afl_global_id = 1, debug = 0, autodictionary = 0; uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0; uint64_t map_addr = 0x10000; + char * skip_nozero = NULL; }; @@ -614,9 +617,14 @@ bool AFLLTOPass::runOnModule(Module &M) { Value *Incr = IRB.CreateAdd(Counter, One); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + if (skip_nozero) { + + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); + + } + IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 9314c3d1..3e9026c8 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -84,7 +84,7 @@ class AFLCoverage : public ModulePass { uint32_t ngram_size = 0; uint32_t debug = 0; uint32_t map_size = MAP_SIZE; - char * ctx_str = NULL; + char * ctx_str = NULL, *skip_nozero = NULL; }; @@ -180,6 +180,7 @@ bool AFLCoverage::runOnModule(Module &M) { #if LLVM_VERSION_MAJOR < 9 char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO"); #endif + skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); unsigned PrevLocSize; @@ -467,6 +468,9 @@ bool AFLCoverage::runOnModule(Module &M) { if (neverZero_counters_str != NULL) { // with llvm 9 we make this the default as the bug in llvm is // then fixed +#else + if (!skip_nozero) { + #endif /* hexcoder: Realize a counter that skips zero during overflow. * Once this counter reaches its maximum value, it next increments to 1 @@ -482,12 +486,8 @@ bool AFLCoverage::runOnModule(Module &M) { auto carry = IRB.CreateZExt(cf, Int8Ty); Incr = IRB.CreateAdd(Incr, carry); -#if LLVM_VERSION_MAJOR < 9 - } -#endif - IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); diff --git a/src/afl-common.c b/src/afl-common.c index 8f21ad94..54b2e790 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -69,9 +69,10 @@ char *afl_environment_variables[] = { "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR", "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", "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_UNTRACER_FILE", + "AFL_LLVM_SKIP_NEVERZERO", "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_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 -- cgit 1.4.1 From 5b1b986c89042e749990f6d14c596d6b4e8ec23a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 3 May 2020 14:19:03 +0200 Subject: fix for afl-tmin -f --- src/afl-tmin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-tmin.c b/src/afl-tmin.c index d6fbd493..98568473 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -839,7 +839,7 @@ int main(int argc, char **argv_orig, char **envp) { if (out_file) { FATAL("Multiple -f options not supported"); } fsrv->use_stdin = 0; - out_file = optarg; + out_file = ck_strdup(optarg); break; case 'e': -- cgit 1.4.1