From 9276dc9e6c8a966c86aeef7ec6ebe6712c302615 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 28 Apr 2020 10:55:22 +0200 Subject: fix #329 --- qemu_mode/patches/afl-qemu-cpu-inl.h | 16 +--------------- qemu_mode/patches/syscall.diff | 11 ++++++++++- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 06243141..6e9ddc3b 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -275,20 +275,6 @@ void afl_setup(void) { } -static void print_mappings(void) { - - u8 buf[MAX_LINE]; - FILE *f = fopen("/proc/self/maps", "r"); - - if (!f) return; - - while (fgets(buf, MAX_LINE, f)) - printf("%s", buf); - - fclose(f); - -} - /* Fork server logic, invoked once we hit _start. */ void afl_forkserver(CPUState *cpu) { @@ -299,7 +285,7 @@ void afl_forkserver(CPUState *cpu) { if (forkserver_installed == 1) return; forkserver_installed = 1; - if (getenv("AFL_QEMU_DEBUG_MAPS")) print_mappings(); + if (getenv("AFL_QEMU_DEBUG_MAPS")) open_self_maps(cpu->env_ptr, 0); // if (!afl_area_ptr) return; // not necessary because of fixed dummy buffer diff --git a/qemu_mode/patches/syscall.diff b/qemu_mode/patches/syscall.diff index 775fc9e0..b8c5ff39 100644 --- a/qemu_mode/patches/syscall.diff +++ b/qemu_mode/patches/syscall.diff @@ -1,5 +1,5 @@ diff --git a/linux-user/syscall.c b/linux-user/syscall.c -index b13a170e..4af79175 100644 +index b13a170e..3f5cc902 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -111,6 +111,9 @@ @@ -43,6 +43,15 @@ index b13a170e..4af79175 100644 ts = (TaskState *)cpu->opaque; if (flags & CLONE_SETTLS) cpu_set_tls (env, newtls); +@@ -6554,7 +6558,7 @@ static int open_self_cmdline(void *cpu_env, int fd) + return 0; + } + +-static int open_self_maps(void *cpu_env, int fd) ++int open_self_maps(void *cpu_env, int fd) + { + CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); + TaskState *ts = cpu->opaque; @@ -7324,10 +7328,12 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_stime /* not on alpha */ case TARGET_NR_stime: -- cgit 1.4.1 From 781725aeafcbd6c6393f86b2c9961773a6f24428 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Apr 2020 02:54:57 +0200 Subject: added afl-proxy to examples --- docs/Changelog.md | 2 + examples/afl-proxy/Makefile | 7 ++ examples/afl-proxy/afl-proxy.c | 241 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 examples/afl-proxy/Makefile create mode 100644 examples/afl-proxy/afl-proxy.c diff --git a/docs/Changelog.md b/docs/Changelog.md index dadfa7e0..dd408bd0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -28,6 +28,8 @@ sending a mail to . - unicorn_mode: - better submodule handling - afl-showmap: fix for -Q mode + - added examples/afl-proxy which can be easily used to fuzz and instrument + non-standard things - all: - forkserver communication now also used for error reporting - fix 32 bit build options diff --git a/examples/afl-proxy/Makefile b/examples/afl-proxy/Makefile new file mode 100644 index 00000000..4b368f8d --- /dev/null +++ b/examples/afl-proxy/Makefile @@ -0,0 +1,7 @@ +all: afl-proxy + +afl-proxy: afl-proxy.c + $(CC) -I../../include -o afl-proxy afl-proxy.c + +clean: + rm -f afl-proxy *~ core diff --git a/examples/afl-proxy/afl-proxy.c b/examples/afl-proxy/afl-proxy.c new file mode 100644 index 00000000..7d25421d --- /dev/null +++ b/examples/afl-proxy/afl-proxy.c @@ -0,0 +1,241 @@ +/* + american fuzzy lop++ - afl-proxy skeleton example + --------------------------------------------------- + + Written by Marc Heuse + + 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 + + + HOW-TO + ====== + + You only need to change the while() loop of the main() to send the + data of buf[] with length len to the target and write the coverage + information to __afl_area_ptr[__afl_map_size] + + +*/ + +#ifdef __ANDROID__ +#include "android-ashmem.h" +#endif +#include "config.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +u8 *__afl_area_ptr; + +#ifdef __ANDROID__ +u32 __afl_map_size = MAP_SIZE; +#else +__thread u32 __afl_map_size = MAP_SIZE; +#endif + +/* Error reporting to forkserver controller */ + +void send_forkserver_error(int error) { + + u32 status; + if (!error || error > 0xffff) return; + status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + +} + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + char *id_str = getenv(SHM_ENV_VAR); + char *ptr; + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { + + u32 val = atoi(ptr); + if (val > 0) __afl_map_size = val; + + } + + if (__afl_map_size > MAP_SIZE) { + + if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { + + fprintf(stderr, + "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + if (id_str) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + exit(-1); + + } + + } else { + + fprintf(stderr, + "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + + } + + } + + if (id_str) { + +#ifdef USEMMAP + const char * shm_file_path = id_str; + int shm_fd = -1; + unsigned char *shm_base = NULL; + + /* create the shared memory segment as if it was a file */ + shm_fd = shm_open(shm_file_path, O_RDWR, 0600); + if (shm_fd == -1) { + + fprintf(stderr, "shm_open() failed\n"); + send_forkserver_error(FS_ERROR_SHM_OPEN); + exit(1); + + } + + /* map the shared memory segment to the address space of the process */ + shm_base = + mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if (shm_base == MAP_FAILED) { + + close(shm_fd); + shm_fd = -1; + + fprintf(stderr, "mmap() failed\n"); + send_forkserver_error(FS_ERROR_MMAP); + exit(2); + + } + + __afl_area_ptr = shm_base; +#else + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, 0, 0); + +#endif + + if (__afl_area_ptr == (void *)-1) { + + send_forkserver_error(FS_ERROR_SHMAT); + exit(1); + + } + + /* Write something into the bitmap so that the parent doesn't give up */ + + __afl_area_ptr[0] = 1; + + } + +} + +/* Fork server logic. */ + +static void __afl_start_forkserver(void) { + + u8 tmp[4] = {0, 0, 0, 0}; + s32 child_pid; + u32 status = 0; + u32 already_read_first = 0; + u32 was_killed; + + u8 child_stopped = 0; + + void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); + + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + + /* Phone home and tell the parent that we're OK. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + +} + +static u32 __afl_next_testcase(u8 *buf, u32 max_len) { + + s32 status; + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &status, 4) != 4) return 0; + + /* we have a testcase - read it */ + status = read(0, buf, max_len); + + if (status < 1) + return 0; + else + return status; + +} + +static void __afl_end_testcase(void) { + + int status = 0xffffff; + + if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); + +} + +/* you just need to modify the while() loop in this main() */ + +int main(int argc, char *argv[]) { + + /* This is were the testcase data is written into */ + u8 buf[1024]; + u32 len; + + /* here you specify the map size you need that you are reporting to + afl-fuzz. */ + __afl_map_size = MAP_SIZE; + + /* then we initialize the shared memory map and start the forkserver */ + __afl_map_shm(); + __afl_start_forkserver(); + + while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { + + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ + + // ... the magic ... + + /* report the test case is done and wait for the next */ + __afl_end_testcase(); + + } + + return 0; + +} -- cgit 1.4.1 From ce2814967df3aac7a707b5f7e458b45eec992149 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Apr 2020 02:56:51 +0200 Subject: add readme for afl-proxy --- examples/afl-proxy/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 examples/afl-proxy/README.md diff --git a/examples/afl-proxy/README.md b/examples/afl-proxy/README.md new file mode 100644 index 00000000..3c768a19 --- /dev/null +++ b/examples/afl-proxy/README.md @@ -0,0 +1,9 @@ +# afl-proxy + +afl-proxy is an example skeleton file which can easily be used to fuzz +and instrument non-standard things. + +You only need to change the while() loop of the main() to send the +data of buf[] with length len to the target and write the coverage +information to __afl_area_ptr[__afl_map_size] + -- cgit 1.4.1 From bc2e65e4821ef4b8fbc33be6c705adfa1c32e02f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Apr 2020 15:18:03 +0200 Subject: added afl_network_proxy --- GNUmakefile | 7 + docs/Changelog.md | 5 +- examples/afl-proxy/afl-proxy.c | 8 +- examples/afl_network_proxy/Makefile | 22 + examples/afl_network_proxy/README.md | 44 ++ examples/afl_network_proxy/afl-network-client.c | 299 ++++++++++++ examples/afl_network_proxy/afl-network-server.c | 603 ++++++++++++++++++++++++ 7 files changed, 980 insertions(+), 8 deletions(-) create mode 100644 examples/afl_network_proxy/Makefile create mode 100644 examples/afl_network_proxy/README.md create mode 100644 examples/afl_network_proxy/afl-network-client.c create mode 100644 examples/afl_network_proxy/afl-network-server.c diff --git a/GNUmakefile b/GNUmakefile index 8ea64109..98092f11 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -445,6 +445,7 @@ clean: -$(MAKE) -C gcc_plugin clean $(MAKE) -C libdislocator clean $(MAKE) -C libtokencap clean + $(MAKE) -C examples/afl_network_proxy clean $(MAKE) -C examples/socket_fuzzing clean $(MAKE) -C examples/argv_fuzzing clean $(MAKE) -C qemu_mode/unsigaction clean @@ -468,6 +469,7 @@ distrib: all radamsa -$(MAKE) -C gcc_plugin $(MAKE) -C libdislocator $(MAKE) -C libtokencap + $(MAKE) -C examples/afl_network_proxy $(MAKE) -C examples/socket_fuzzing $(MAKE) -C examples/argv_fuzzing cd qemu_mode && sh ./build_qemu_support.sh @@ -476,6 +478,7 @@ distrib: all radamsa binary-only: all radamsa $(MAKE) -C libdislocator $(MAKE) -C libtokencap + $(MAKE) -C examples/afl_network_proxy $(MAKE) -C examples/socket_fuzzing $(MAKE) -C examples/argv_fuzzing cd qemu_mode && sh ./build_qemu_support.sh @@ -486,6 +489,9 @@ source-only: all radamsa -$(MAKE) -C gcc_plugin $(MAKE) -C libdislocator $(MAKE) -C libtokencap + #$(MAKE) -C examples/afl_network_proxy + #$(MAKE) -C examples/socket_fuzzing + #$(MAKE) -C examples/argv_fuzzing %.8: % @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@ @@ -521,6 +527,7 @@ install: all $(MANPAGES) if [ -f afl-fuzz-document ]; then set -e; install -m 755 afl-fuzz-document $${DESTDIR}$(BIN_PATH); fi if [ -f socketfuzz32.so -o -f socketfuzz64.so ]; then $(MAKE) -C examples/socket_fuzzing install; fi if [ -f argvfuzz32.so -o -f argvfuzz64.so ]; then $(MAKE) -C examples/argv_fuzzing install; fi + if [ -f examples/afl_network_proxy/afl-network-server ]; then $(MAKE) -C examples/afl_network_proxy install; fi set -e; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-g++ set -e; if [ -f afl-clang-fast ] ; then ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi diff --git a/docs/Changelog.md b/docs/Changelog.md index dd408bd0..faf015c6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -28,7 +28,10 @@ sending a mail to . - unicorn_mode: - better submodule handling - afl-showmap: fix for -Q mode - - added examples/afl-proxy which can be easily used to fuzz and instrument + - 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_proxy which can be easily used to fuzz and instrument non-standard things - all: - forkserver communication now also used for error reporting diff --git a/examples/afl-proxy/afl-proxy.c b/examples/afl-proxy/afl-proxy.c index 7d25421d..eea03549 100644 --- a/examples/afl-proxy/afl-proxy.c +++ b/examples/afl-proxy/afl-proxy.c @@ -163,14 +163,7 @@ static void __afl_map_shm(void) { static void __afl_start_forkserver(void) { u8 tmp[4] = {0, 0, 0, 0}; - s32 child_pid; u32 status = 0; - u32 already_read_first = 0; - u32 was_killed; - - u8 child_stopped = 0; - - void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); @@ -239,3 +232,4 @@ int main(int argc, char *argv[]) { return 0; } + diff --git a/examples/afl_network_proxy/Makefile b/examples/afl_network_proxy/Makefile new file mode 100644 index 00000000..eeee1178 --- /dev/null +++ b/examples/afl_network_proxy/Makefile @@ -0,0 +1,22 @@ +PREFIX ?= /usr/local +BIN_PATH = $(PREFIX)/bin +DOC_PATH = $(PREFIX)/share/doc/afl + +PROGRAMS = afl-network-client afl-network-server + +all: $(PROGRAMS) + +afl-network-client: afl-network-client.c + $(CC) -I../../include -o afl-network-client afl-network-client.c + +afl-network-server: afl-network-server.c + $(CC) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" + +clean: + rm -f $(PROGRAMS) *~ core + +install: all + install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH) + install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH) + install -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md + \ No newline at end of file diff --git a/examples/afl_network_proxy/README.md b/examples/afl_network_proxy/README.md new file mode 100644 index 00000000..65012601 --- /dev/null +++ b/examples/afl_network_proxy/README.md @@ -0,0 +1,44 @@ +# afl-network-proxy + +If you want to run afl-fuzz over the network than this is what you need :) +Note that the impact on fuzzing speed will be huge, expect a loss of 90%. + +## When to use this + +1. when you have to fuzz a target that has to run on a system that cannot + contain the fuzzing output (e.g. /tmp too small and file system is read-only) +2. when the target instantly reboots on crashes +3. ... any other reason you would need this + +## how to get it running + +### on the target + +Run `afl-network-server` with your target with the -m and -t values you need. +Important is the -i parameter which is the TCP port to liste on. +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 +`afl-network-client` with the IP and PORT of the `afl-network-server` and +increase the -t value: +``` +$ afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111 +``` +Note the '+' on the -t parameter value. the afl-network-server will take +care of proper timeouts hence afl-fuzz should not. The '+' increases the timout +and the value itself should be 500-1000 higher than the one on +afl-network-server. + +### networking + +The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to +either. Note that also the outgoing interface can be specified with a '%' for +`afl-network-client`, e.g. `fe80::1234%eth0`. + +## how to compile and install + +`make && sudo make install` diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c new file mode 100644 index 00000000..bf89fc04 --- /dev/null +++ b/examples/afl_network_proxy/afl-network-client.c @@ -0,0 +1,299 @@ +/* + american fuzzy lop++ - afl-network-client + --------------------------------------- + + Written by Marc Heuse + + 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 + +*/ + +#ifdef __ANDROID__ +#include "android-ashmem.h" +#endif +#include "config.h" +#include "types.h" +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +u8 *__afl_area_ptr; + +#ifdef __ANDROID__ +u32 __afl_map_size = MAP_SIZE; +#else +__thread u32 __afl_map_size = MAP_SIZE; +#endif + +/* Error reporting to forkserver controller */ + +void send_forkserver_error(int error) { + + u32 status; + if (!error || error > 0xffff) return; + status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + +} + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + char *id_str = getenv(SHM_ENV_VAR); + char *ptr; + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { + + u32 val = atoi(ptr); + if (val > 0) __afl_map_size = val; + + } + + if (__afl_map_size > MAP_SIZE) { + + if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { + + fprintf(stderr, + "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + if (id_str) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + exit(-1); + + } + + } else { + + fprintf(stderr, + "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + + } + + } + + if (id_str) { + +#ifdef USEMMAP + const char * shm_file_path = id_str; + int shm_fd = -1; + unsigned char *shm_base = NULL; + + /* create the shared memory segment as if it was a file */ + shm_fd = shm_open(shm_file_path, O_RDWR, 0600); + if (shm_fd == -1) { + + fprintf(stderr, "shm_open() failed\n"); + send_forkserver_error(FS_ERROR_SHM_OPEN); + exit(1); + + } + + /* map the shared memory segment to the address space of the process */ + shm_base = + mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if (shm_base == MAP_FAILED) { + + close(shm_fd); + shm_fd = -1; + + fprintf(stderr, "mmap() failed\n"); + send_forkserver_error(FS_ERROR_MMAP); + exit(2); + + } + + __afl_area_ptr = shm_base; +#else + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, 0, 0); + +#endif + + if (__afl_area_ptr == (void *)-1) { + + send_forkserver_error(FS_ERROR_SHMAT); + exit(1); + + } + + /* Write something into the bitmap so that the parent doesn't give up */ + + __afl_area_ptr[0] = 1; + + } + +} + +/* Fork server logic. */ + +static void __afl_start_forkserver(void) { + + u8 tmp[4] = {0, 0, 0, 0}; + u32 status = 0; + + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + + /* Phone home and tell the parent that we're OK. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + +} + +static u32 __afl_next_testcase(u8 *buf, u32 max_len) { + + s32 status, res = 0xffffff; + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &status, 4) != 4) return 0; + + /* we have a testcase - read it */ + status = read(0, buf, max_len); + + /* report that we are starting the target */ + if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; + + if (status < 1) + return 0; + else + return status; + +} + +static void __afl_end_testcase(void) { + + int status = 0xffffff; + + if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); + +} + +/* you just need to modify the while() loop in this main() */ + +int main(int argc, char *argv[]) { + + u8 * interface, *buf, *ptr; + s32 s = -1; + struct addrinfo hints, *hres, *aip; + u32 len, max_len = 65536; + + if (argc < 3 || argc > 4) { + + printf("Syntax: %s host port [max-input-size]\n\n", argv[0]); + printf("Requires host and port of the remote afl-proxy-server instance.\n"); + printf( + "IPv4 and IPv6 are supported, also binding to an interface with " + "\"%%\"\n"); + printf("The max-input-size default is %u.\n", max_len); + printf( + "The default map size is %u and can be changed with setting " + "AFL_MAP_SIZE.\n", + __afl_map_size); + exit(-1); + + } + + if ((interface = index(argv[1], '%')) != NULL) *interface++ = 0; + + if (argc > 3) + if ((max_len = atoi(argv[3])) < 0) + FATAL("max-input-size may not be negative or larger than 2GB: %s", + argv[3]); + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) + if ((__afl_map_size = atoi(ptr)) < 8) + FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr); + + if ((buf = malloc(max_len)) == NULL) + PFATAL("can not allocate %u memory", max_len); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + if (getaddrinfo(argv[1], argv[2], &hints, &hres) != 0) + PFATAL("could not resolve target %s", argv[1]); + + for (aip = hres; aip != NULL && s == -1; aip = aip->ai_next) { + + if ((s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol)) >= 0) { + +#ifdef SO_BINDTODEVICE + if (interface != NULL) + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface, + strlen(interface) + 1) < 0) + fprintf(stderr, "Warning: could not bind to device %s\n", interface); +#else + fprintf(stderr, + "Warning: binding to interface is not supported for your OS\n"); +#endif + if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1; + + } + + } + + if (s == -1) + FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]); + + /* we initialize the shared memory map and start the forkserver */ + __afl_map_shm(); + __afl_start_forkserver(); + + int i = 1, j; + //fprintf(stderr, "Waiting for first testcase\n"); + while ((len = __afl_next_testcase(buf, max_len)) > 0) { + + //fprintf(stderr, "Sending testcase with len %u\n", len); + 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; + 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); + //fprintf(stderr, "Received coverage\n"); + + /* report the test case is done and wait for the next */ + __afl_end_testcase(); + //fprintf(stderr, "Waiting for next testcase %d\n", ++i); + + } + + return 0; + +} diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c new file mode 100644 index 00000000..dc0e00a2 --- /dev/null +++ b/examples/afl_network_proxy/afl-network-server.c @@ -0,0 +1,603 @@ +/* + american fuzzy lop++ - network proxy server + ------------------------------------------- + + Originally written by Michal Zalewski + + Forkserver design by Jann Horn + + Now maintained by Marc Heuse , + Heiko Eißfeldt and + Andrea Fioraldi and + Dominik Maier + + Copyright 2016, 2017 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 + + */ + +#define AFL_MAIN + +#ifdef __ANDROID__ +#include "android-ashmem.h" +#endif + +#include "config.h" +#include "types.h" +#include "debug.h" +#include "alloc-inl.h" +#include "hash.h" +#include "forkserver.h" +#include "sharedmem.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u8 *in_file, /* Minimizer input test case */ + *out_file; + +static u8 *in_data; /* Input data for trimming */ + +static s32 in_len; +static u32 map_size = MAP_SIZE; + +static volatile u8 stop_soon; /* Ctrl-C pressed? */ + +/* See if any bytes are set in the bitmap. */ + +static inline u8 anything_set(afl_forkserver_t *fsrv) { + + u32 *ptr = (u32 *)fsrv->trace_bits; + u32 i = (map_size >> 2); + + while (i--) { + + if (*(ptr++)) { return 1; } + + } + + return 0; + +} + +static void at_exit_handler(void) { + + afl_fsrv_killall(); + +} + +/* Write output file. */ + +static s32 write_to_file(u8 *path, u8 *mem, u32 len) { + + s32 ret; + + unlink(path); /* Ignore errors */ + + ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600); + + if (ret < 0) { PFATAL("Unable to create '%s'", path); } + + ck_write(ret, mem, len, path); + + lseek(ret, 0, SEEK_SET); + + return ret; + +} + +/* Execute target application. Returns 0 if the changes are a dud, or + 1 if they should be kept. */ + +static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, + u8 first_run) { + + afl_fsrv_write_to_testcase(fsrv, mem, len); + + fsrv_run_result_t ret = + afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon); + + if (ret == FSRV_RUN_ERROR) { FATAL("Couldn't run child"); } + + if (stop_soon) { + + SAYF(cRST cLRD "\n+++ aborted by user +++\n" cRST); + exit(1); + + } + +} + +/* Handle Ctrl-C and the like. */ + +static void handle_stop_sig(int sig) { + + stop_soon = 1; + afl_fsrv_killall(); + +} + +/* Do basic preparations - persistent fds, filenames, etc. */ + +static void set_up_environment(afl_forkserver_t *fsrv) { + + u8 *x; + + fsrv->dev_null_fd = open("/dev/null", O_RDWR); + if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } + + if (!out_file) { + + u8 *use_dir = "."; + + if (access(use_dir, R_OK | W_OK | X_OK)) { + + use_dir = get_afl_env("TMPDIR"); + if (!use_dir) { use_dir = "/tmp"; } + + } + + out_file = alloc_printf("%s/.afl-input-temp-%u", use_dir, getpid()); + + } + + unlink(out_file); + + fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600); + + if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } + + /* Set sane defaults... */ + + x = get_afl_env("ASAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "abort_on_error=1")) { + + FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + + } + + if (!strstr(x, "symbolize=0")) { + + FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); + + } + + } + + x = get_afl_env("MSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) { + + FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY( + MSAN_ERROR) " - please fix!"); + + } + + if (!strstr(x, "symbolize=0")) { + + FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); + + } + + } + + setenv("ASAN_OPTIONS", + "abort_on_error=1:" + "detect_leaks=0:" + "symbolize=0:" + "allocator_may_return_null=1", + 0); + + setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" + "abort_on_error=1:" + "allocator_may_return_null=1:" + "msan_track_origins=0", 0); + + if (get_afl_env("AFL_PRELOAD")) { + + if (fsrv->qemu_mode) { + + u8 *qemu_preload = getenv("QEMU_SET_ENV"); + u8 *afl_preload = getenv("AFL_PRELOAD"); + u8 *buf; + + s32 i, afl_preload_size = strlen(afl_preload); + for (i = 0; i < afl_preload_size; ++i) { + + if (afl_preload[i] == ',') { + + PFATAL( + "Comma (',') is not allowed in AFL_PRELOAD when -Q is " + "specified!"); + + } + + } + + if (qemu_preload) { + + buf = alloc_printf("%s,LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s", + qemu_preload, afl_preload, afl_preload); + + } else { + + buf = alloc_printf("LD_PRELOAD=%s,DYLD_INSERT_LIBRARIES=%s", + afl_preload, afl_preload); + + } + + setenv("QEMU_SET_ENV", buf, 1); + + ck_free(buf); + + } else { + + setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); + setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); + + } + + } + +} + +/* Setup signal handlers, duh. */ + +static void setup_signal_handlers(void) { + + struct sigaction sa; + + sa.sa_handler = NULL; + sa.sa_flags = SA_RESTART; + sa.sa_sigaction = NULL; + + sigemptyset(&sa.sa_mask); + + /* Various ways of saying "stop". */ + + sa.sa_handler = handle_stop_sig; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + +} + +/* Display usage hints. */ + +static void usage(u8 *argv0) { + + SAYF( + "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" + + "Required parameters:\n" + + " -i port - the port to listen for the client to connect to\n\n" + + "Execution control settings:\n" + + " -f file - input file read by the tested program (stdin)\n" + " -t msec - timeout for each run (%d ms)\n" + " -m megs - memory limit for child process (%d MB)\n" + " -Q - use binary-only instrumentation (QEMU mode)\n" + " -U - use unicorn-based instrumentation (Unicorn mode)\n" + " -W - use qemu-based instrumentation with Wine (Wine " + "mode)\n\n" + + "Environment variables used:\n" + "TMPDIR: directory to use for temporary input files\n" + "ASAN_OPTIONS: custom settings for ASAN\n" + " (must contain abort_on_error=1 and symbolize=0)\n" + "MSAN_OPTIONS: custom settings for MSAN\n" + " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" + " the target was compiled for\n" + "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + + , argv0, EXEC_TIMEOUT, MEM_LIMIT); + + exit(1); + +} + + +int recv_testcase(int s, void **buf, size_t *max_len) { + + int size, received = 0, ret; + + while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0) + received += ret; + + if (received != 4) + FATAL("did not receive size information"); + if (size < 1) + FATAL("did not receive valid size information"); + //fprintf(stderr, "received size information of %d\n", size); + + *buf = maybe_grow(buf, max_len, size); + //fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); + received = 0; + while (received < size && (ret = recv(s, ((char*)*buf) + received, size - received, 0)) > 0) + received += ret; + + if (received != size) + FATAL("did not receive testcase data %u != %u, %d", received, size, ret); + + //fprintf(stderr, "received testcase\n"); + return size; +} + +/* Main entry point */ + +int main(int argc, char **argv_orig, char **envp) { + + s32 opt, s, sock, on = 1, port = -1; + size_t max_len = 0; + u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + char **use_argv; + struct sockaddr_in6 serveraddr, clientaddr; + int addrlen = sizeof(clientaddr); + char str[INET6_ADDRSTRLEN]; + char ** argv = argv_cpy_dup(argc, argv_orig); + + afl_forkserver_t fsrv_var = {0}; + afl_forkserver_t *fsrv = &fsrv_var; + afl_fsrv_init(fsrv); + map_size = get_map_size(); + fsrv->map_size = map_size; + + while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) { + + switch (opt) { + + case 'i': + + if (port > 0) { FATAL("Multiple -i options not supported"); } + port = atoi(optarg); + if (port < 1 || port > 65535) + FATAL("invalid port definition, must be between 1-65535: %s", optarg); + break; + + case 'f': + + if (out_file) { FATAL("Multiple -f options not supported"); } + fsrv->use_stdin = 0; + out_file = optarg; + break; + + case 'm': { + + u8 suffix = 'M'; + + if (mem_limit_given) { FATAL("Multiple -m options not supported"); } + mem_limit_given = 1; + + if (!optarg) { FATAL("Wrong usage of -m"); } + + if (!strcmp(optarg, "none")) { + + fsrv->mem_limit = 0; + break; + + } + + if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 || + optarg[0] == '-') { + + FATAL("Bad syntax used for -m"); + + } + + switch (suffix) { + + case 'T': + fsrv->mem_limit *= 1024 * 1024; + break; + case 'G': + fsrv->mem_limit *= 1024; + break; + case 'k': + fsrv->mem_limit /= 1024; + break; + case 'M': + break; + + default: + FATAL("Unsupported suffix or bad syntax for -m"); + + } + + if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); } + + if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) { + + FATAL("Value of -m out of range on 32-bit systems"); + + } + + } + + break; + + case 't': + + if (timeout_given) { FATAL("Multiple -t options not supported"); } + timeout_given = 1; + + if (!optarg) { FATAL("Wrong usage of -t"); } + + fsrv->exec_tmout = atoi(optarg); + + if (fsrv->exec_tmout < 10 || optarg[0] == '-') { + + FATAL("Dangerously low value of -t"); + + } + + break; + + case 'Q': + + if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } + if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; } + + fsrv->qemu_mode = 1; + break; + + case 'U': + + if (unicorn_mode) { FATAL("Multiple -Q options not supported"); } + if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; } + + unicorn_mode = 1; + break; + + case 'W': /* Wine+QEMU mode */ + + if (use_wine) { FATAL("Multiple -W options not supported"); } + fsrv->qemu_mode = 1; + use_wine = 1; + + if (!mem_limit_given) { fsrv->mem_limit = 0; } + + break; + + case 'h': + usage(argv[0]); + return -1; + break; + + default: + usage(argv[0]); + + } + + } + + if (optind == argc || port < 1) { usage(argv[0]); } + + check_environment_vars(envp); + + sharedmem_t shm = {0}; + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); + + in_data = maybe_grow((void**)&in_data, &max_len, 65536); + + atexit(at_exit_handler); + setup_signal_handlers(); + + set_up_environment(fsrv); + + fsrv->target_path = find_binary(argv[optind]); + detect_file_args(argv + optind, out_file, &fsrv->use_stdin); + + if (fsrv->qemu_mode) { + + if (use_wine) { + + use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind, + argv + optind); + + } else { + + use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind, + argv + optind); + + } + + } else { + + use_argv = argv + optind; + + } + + if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) PFATAL("socket() failed"); + +#ifdef SO_REUSEADDR + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { + + WARNF("setsockopt(SO_REUSEADDR) failed"); + + } + +#endif + memset(&serveraddr, 0, sizeof(serveraddr)); + serveraddr.sin6_family = AF_INET6; + serveraddr.sin6_port = htons(port); + serveraddr.sin6_addr = in6addr_any; + + if (bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) + PFATAL("bind() failed"); + + if (listen(sock, 1) < 0) { PFATAL("listen() failed"); } + + afl_fsrv_start(fsrv, use_argv, &stop_soon, + get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + + fprintf(stderr, + "Waiting for incoming connection from afl-network-client on port %d " + "...\n", + port); + + if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); } + fprintf(stderr, "Received connection, starting ...\n"); + + while ((in_len = recv_testcase(s, (void**)&in_data, &max_len)) > 0) { + + //fprintf(stderr, "received %u\n", in_len); + run_target(fsrv, use_argv, in_data, in_len, 1); + + if (send(s, fsrv->trace_bits, fsrv->map_size, 0) != fsrv->map_size) + FATAL("could not send coverage data"); + //fprintf(stderr, "sent result\n"); + + } + + unlink(out_file); + if (out_file) { ck_free(out_file); } + out_file = NULL; + + afl_shm_deinit(&shm); + afl_fsrv_deinit(fsrv); + if (fsrv->target_path) { ck_free(fsrv->target_path); } + if (in_data) { ck_free(in_data); } + + argv_cpy_free(argv); + + exit(0); + +} + -- cgit 1.4.1 From c53663c7ac2c1f96a2dfe3fcbc6fb232bf1d9a74 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Apr 2020 15:21:51 +0200 Subject: afl-proxy -> afl_proxy --- examples/afl-proxy/Makefile | 7 -- examples/afl-proxy/README.md | 9 -- examples/afl-proxy/afl-proxy.c | 235 ----------------------------------------- examples/afl_proxy/Makefile | 7 ++ examples/afl_proxy/README.md | 9 ++ examples/afl_proxy/afl-proxy.c | 235 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 251 insertions(+), 251 deletions(-) delete mode 100644 examples/afl-proxy/Makefile delete mode 100644 examples/afl-proxy/README.md delete mode 100644 examples/afl-proxy/afl-proxy.c create mode 100644 examples/afl_proxy/Makefile create mode 100644 examples/afl_proxy/README.md create mode 100644 examples/afl_proxy/afl-proxy.c diff --git a/examples/afl-proxy/Makefile b/examples/afl-proxy/Makefile deleted file mode 100644 index 4b368f8d..00000000 --- a/examples/afl-proxy/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: afl-proxy - -afl-proxy: afl-proxy.c - $(CC) -I../../include -o afl-proxy afl-proxy.c - -clean: - rm -f afl-proxy *~ core diff --git a/examples/afl-proxy/README.md b/examples/afl-proxy/README.md deleted file mode 100644 index 3c768a19..00000000 --- a/examples/afl-proxy/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# afl-proxy - -afl-proxy is an example skeleton file which can easily be used to fuzz -and instrument non-standard things. - -You only need to change the while() loop of the main() to send the -data of buf[] with length len to the target and write the coverage -information to __afl_area_ptr[__afl_map_size] - diff --git a/examples/afl-proxy/afl-proxy.c b/examples/afl-proxy/afl-proxy.c deleted file mode 100644 index eea03549..00000000 --- a/examples/afl-proxy/afl-proxy.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - american fuzzy lop++ - afl-proxy skeleton example - --------------------------------------------------- - - Written by Marc Heuse - - 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 - - - HOW-TO - ====== - - You only need to change the while() loop of the main() to send the - data of buf[] with length len to the target and write the coverage - information to __afl_area_ptr[__afl_map_size] - - -*/ - -#ifdef __ANDROID__ -#include "android-ashmem.h" -#endif -#include "config.h" -#include "types.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -u8 *__afl_area_ptr; - -#ifdef __ANDROID__ -u32 __afl_map_size = MAP_SIZE; -#else -__thread u32 __afl_map_size = MAP_SIZE; -#endif - -/* Error reporting to forkserver controller */ - -void send_forkserver_error(int error) { - - u32 status; - if (!error || error > 0xffff) return; - status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); - if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; - -} - -/* SHM setup. */ - -static void __afl_map_shm(void) { - - char *id_str = getenv(SHM_ENV_VAR); - char *ptr; - - if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { - - u32 val = atoi(ptr); - if (val > 0) __afl_map_size = val; - - } - - if (__afl_map_size > MAP_SIZE) { - - if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { - - fprintf(stderr, - "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - if (id_str) { - - send_forkserver_error(FS_ERROR_MAP_SIZE); - exit(-1); - - } - - } else { - - fprintf(stderr, - "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " - "be able to run this instrumented program!\n", - __afl_map_size); - - } - - } - - if (id_str) { - -#ifdef USEMMAP - const char * shm_file_path = id_str; - int shm_fd = -1; - unsigned char *shm_base = NULL; - - /* create the shared memory segment as if it was a file */ - shm_fd = shm_open(shm_file_path, O_RDWR, 0600); - if (shm_fd == -1) { - - fprintf(stderr, "shm_open() failed\n"); - send_forkserver_error(FS_ERROR_SHM_OPEN); - exit(1); - - } - - /* map the shared memory segment to the address space of the process */ - shm_base = - mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - - if (shm_base == MAP_FAILED) { - - close(shm_fd); - shm_fd = -1; - - fprintf(stderr, "mmap() failed\n"); - send_forkserver_error(FS_ERROR_MMAP); - exit(2); - - } - - __afl_area_ptr = shm_base; -#else - u32 shm_id = atoi(id_str); - - __afl_area_ptr = shmat(shm_id, 0, 0); - -#endif - - if (__afl_area_ptr == (void *)-1) { - - send_forkserver_error(FS_ERROR_SHMAT); - exit(1); - - } - - /* Write something into the bitmap so that the parent doesn't give up */ - - __afl_area_ptr[0] = 1; - - } - -} - -/* Fork server logic. */ - -static void __afl_start_forkserver(void) { - - u8 tmp[4] = {0, 0, 0, 0}; - u32 status = 0; - - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) - status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (status) status |= (FS_OPT_ENABLED); - memcpy(tmp, &status, 4); - - /* Phone home and tell the parent that we're OK. */ - - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; - -} - -static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - - s32 status; - - /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &status, 4) != 4) return 0; - - /* we have a testcase - read it */ - status = read(0, buf, max_len); - - if (status < 1) - return 0; - else - return status; - -} - -static void __afl_end_testcase(void) { - - int status = 0xffffff; - - if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); - -} - -/* you just need to modify the while() loop in this main() */ - -int main(int argc, char *argv[]) { - - /* This is were the testcase data is written into */ - u8 buf[1024]; - u32 len; - - /* here you specify the map size you need that you are reporting to - afl-fuzz. */ - __afl_map_size = MAP_SIZE; - - /* then we initialize the shared memory map and start the forkserver */ - __afl_map_shm(); - __afl_start_forkserver(); - - while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - - /* here you have to create the magic that feeds the buf/len to the - target and write the coverage to __afl_area_ptr */ - - // ... the magic ... - - /* report the test case is done and wait for the next */ - __afl_end_testcase(); - - } - - return 0; - -} - diff --git a/examples/afl_proxy/Makefile b/examples/afl_proxy/Makefile new file mode 100644 index 00000000..4b368f8d --- /dev/null +++ b/examples/afl_proxy/Makefile @@ -0,0 +1,7 @@ +all: afl-proxy + +afl-proxy: afl-proxy.c + $(CC) -I../../include -o afl-proxy afl-proxy.c + +clean: + rm -f afl-proxy *~ core diff --git a/examples/afl_proxy/README.md b/examples/afl_proxy/README.md new file mode 100644 index 00000000..3c768a19 --- /dev/null +++ b/examples/afl_proxy/README.md @@ -0,0 +1,9 @@ +# afl-proxy + +afl-proxy is an example skeleton file which can easily be used to fuzz +and instrument non-standard things. + +You only need to change the while() loop of the main() to send the +data of buf[] with length len to the target and write the coverage +information to __afl_area_ptr[__afl_map_size] + diff --git a/examples/afl_proxy/afl-proxy.c b/examples/afl_proxy/afl-proxy.c new file mode 100644 index 00000000..eea03549 --- /dev/null +++ b/examples/afl_proxy/afl-proxy.c @@ -0,0 +1,235 @@ +/* + american fuzzy lop++ - afl-proxy skeleton example + --------------------------------------------------- + + Written by Marc Heuse + + 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 + + + HOW-TO + ====== + + You only need to change the while() loop of the main() to send the + data of buf[] with length len to the target and write the coverage + information to __afl_area_ptr[__afl_map_size] + + +*/ + +#ifdef __ANDROID__ +#include "android-ashmem.h" +#endif +#include "config.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +u8 *__afl_area_ptr; + +#ifdef __ANDROID__ +u32 __afl_map_size = MAP_SIZE; +#else +__thread u32 __afl_map_size = MAP_SIZE; +#endif + +/* Error reporting to forkserver controller */ + +void send_forkserver_error(int error) { + + u32 status; + if (!error || error > 0xffff) return; + status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + +} + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + char *id_str = getenv(SHM_ENV_VAR); + char *ptr; + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { + + u32 val = atoi(ptr); + if (val > 0) __afl_map_size = val; + + } + + if (__afl_map_size > MAP_SIZE) { + + if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { + + fprintf(stderr, + "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + if (id_str) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + exit(-1); + + } + + } else { + + fprintf(stderr, + "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + + } + + } + + if (id_str) { + +#ifdef USEMMAP + const char * shm_file_path = id_str; + int shm_fd = -1; + unsigned char *shm_base = NULL; + + /* create the shared memory segment as if it was a file */ + shm_fd = shm_open(shm_file_path, O_RDWR, 0600); + if (shm_fd == -1) { + + fprintf(stderr, "shm_open() failed\n"); + send_forkserver_error(FS_ERROR_SHM_OPEN); + exit(1); + + } + + /* map the shared memory segment to the address space of the process */ + shm_base = + mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if (shm_base == MAP_FAILED) { + + close(shm_fd); + shm_fd = -1; + + fprintf(stderr, "mmap() failed\n"); + send_forkserver_error(FS_ERROR_MMAP); + exit(2); + + } + + __afl_area_ptr = shm_base; +#else + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, 0, 0); + +#endif + + if (__afl_area_ptr == (void *)-1) { + + send_forkserver_error(FS_ERROR_SHMAT); + exit(1); + + } + + /* Write something into the bitmap so that the parent doesn't give up */ + + __afl_area_ptr[0] = 1; + + } + +} + +/* Fork server logic. */ + +static void __afl_start_forkserver(void) { + + u8 tmp[4] = {0, 0, 0, 0}; + u32 status = 0; + + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + + /* Phone home and tell the parent that we're OK. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + +} + +static u32 __afl_next_testcase(u8 *buf, u32 max_len) { + + s32 status; + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &status, 4) != 4) return 0; + + /* we have a testcase - read it */ + status = read(0, buf, max_len); + + if (status < 1) + return 0; + else + return status; + +} + +static void __afl_end_testcase(void) { + + int status = 0xffffff; + + if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); + +} + +/* you just need to modify the while() loop in this main() */ + +int main(int argc, char *argv[]) { + + /* This is were the testcase data is written into */ + u8 buf[1024]; + u32 len; + + /* here you specify the map size you need that you are reporting to + afl-fuzz. */ + __afl_map_size = MAP_SIZE; + + /* then we initialize the shared memory map and start the forkserver */ + __afl_map_shm(); + __afl_start_forkserver(); + + while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { + + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ + + // ... the magic ... + + /* report the test case is done and wait for the next */ + __afl_end_testcase(); + + } + + return 0; + +} + -- cgit 1.4.1 From fced3e00cedf1fe4a100c20dc64ee7e4f3bc3223 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 29 Apr 2020 20:44:30 +0200 Subject: wip: afl-untracer --- examples/afl_network_proxy/afl-network-client.c | 13 +- examples/afl_network_proxy/afl-network-server.c | 33 +- examples/afl_proxy/afl-proxy.c | 9 +- examples/afl_untracer/Makefile | 7 + examples/afl_untracer/README.md | 11 + examples/afl_untracer/afl-untracer.c | 581 ++++++++++++++++++++++++ examples/afl_untracer/ida_get_patchpoints.py | 52 +++ 7 files changed, 681 insertions(+), 25 deletions(-) create mode 100644 examples/afl_untracer/Makefile create mode 100644 examples/afl_untracer/README.md create mode 100644 examples/afl_untracer/afl-untracer.c create mode 100644 examples/afl_untracer/ida_get_patchpoints.py diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c index bf89fc04..ede2ff8d 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -274,26 +274,29 @@ int main(int argc, char *argv[]) { __afl_start_forkserver(); int i = 1, j; - //fprintf(stderr, "Waiting for first testcase\n"); + // fprintf(stderr, "Waiting for first testcase\n"); while ((len = __afl_next_testcase(buf, max_len)) > 0) { - //fprintf(stderr, "Sending testcase with len %u\n", len); + // fprintf(stderr, "Sending testcase with len %u\n", len); 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; - while (received < __afl_map_size && (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received, 0)) > 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); - //fprintf(stderr, "Received coverage\n"); + // fprintf(stderr, "Received coverage\n"); /* report the test case is done and wait for the next */ __afl_end_testcase(); - //fprintf(stderr, "Waiting for next testcase %d\n", ++i); + // fprintf(stderr, "Waiting for next testcase %d\n", ++i); } return 0; } + diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index dc0e00a2..1bd37560 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -118,7 +118,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) { 1 if they should be kept. */ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, - u8 first_run) { + u8 first_run) { afl_fsrv_write_to_testcase(fsrv, mem, len); @@ -333,31 +333,30 @@ static void usage(u8 *argv0) { } - int recv_testcase(int s, void **buf, size_t *max_len) { int size, received = 0, ret; - + while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0) received += ret; - if (received != 4) - FATAL("did not receive size information"); - if (size < 1) - FATAL("did not receive valid size information"); - //fprintf(stderr, "received size information of %d\n", size); + if (received != 4) FATAL("did not receive size information"); + if (size < 1) FATAL("did not receive valid size information"); + // fprintf(stderr, "received size information of %d\n", size); *buf = maybe_grow(buf, max_len, size); - //fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); + // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); received = 0; - while (received < size && (ret = recv(s, ((char*)*buf) + received, size - received, 0)) > 0) + while (received < size && + (ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0) received += ret; if (received != size) FATAL("did not receive testcase data %u != %u, %d", received, size, ret); - //fprintf(stderr, "received testcase\n"); + // fprintf(stderr, "received testcase\n"); return size; + } /* Main entry point */ @@ -372,7 +371,7 @@ int main(int argc, char **argv_orig, char **envp) { int addrlen = sizeof(clientaddr); char str[INET6_ADDRSTRLEN]; char ** argv = argv_cpy_dup(argc, argv_orig); - + afl_forkserver_t fsrv_var = {0}; afl_forkserver_t *fsrv = &fsrv_var; afl_fsrv_init(fsrv); @@ -514,7 +513,7 @@ int main(int argc, char **argv_orig, char **envp) { sharedmem_t shm = {0}; fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); - in_data = maybe_grow((void**)&in_data, &max_len, 65536); + in_data = maybe_grow((void **)&in_data, &max_len, 65536); atexit(at_exit_handler); setup_signal_handlers(); @@ -575,17 +574,17 @@ int main(int argc, char **argv_orig, char **envp) { if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); } fprintf(stderr, "Received connection, starting ...\n"); - while ((in_len = recv_testcase(s, (void**)&in_data, &max_len)) > 0) { + while ((in_len = recv_testcase(s, (void **)&in_data, &max_len)) > 0) { - //fprintf(stderr, "received %u\n", in_len); + // fprintf(stderr, "received %u\n", in_len); run_target(fsrv, use_argv, in_data, in_len, 1); if (send(s, fsrv->trace_bits, fsrv->map_size, 0) != fsrv->map_size) FATAL("could not send coverage data"); - //fprintf(stderr, "sent result\n"); + // fprintf(stderr, "sent result\n"); } - + unlink(out_file); if (out_file) { ck_free(out_file); } out_file = NULL; diff --git a/examples/afl_proxy/afl-proxy.c b/examples/afl_proxy/afl-proxy.c index eea03549..36121e17 100644 --- a/examples/afl_proxy/afl-proxy.c +++ b/examples/afl_proxy/afl-proxy.c @@ -178,7 +178,7 @@ static void __afl_start_forkserver(void) { static u32 __afl_next_testcase(u8 *buf, u32 max_len) { - s32 status; + s32 status, res = 0xffffff; /* Wait for parent by reading from the pipe. Abort if read fails. */ if (read(FORKSRV_FD, &status, 4) != 4) return 0; @@ -186,6 +186,9 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { /* we have a testcase - read it */ status = read(0, buf, max_len); + /* report that we are starting the target */ + if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; + if (status < 1) return 0; else @@ -206,12 +209,12 @@ static void __afl_end_testcase(void) { int main(int argc, char *argv[]) { /* This is were the testcase data is written into */ - u8 buf[1024]; + u8 buf[1024]; // this is the maximum size for a test case! set it! u32 len; /* here you specify the map size you need that you are reporting to afl-fuzz. */ - __afl_map_size = MAP_SIZE; + __afl_map_size = MAP_SIZE; // default is 65536 /* then we initialize the shared memory map and start the forkserver */ __afl_map_shm(); diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile new file mode 100644 index 00000000..ea20ebc0 --- /dev/null +++ b/examples/afl_untracer/Makefile @@ -0,0 +1,7 @@ +all: afl-untracer + +afl-untracer: afl-untracer.c + $(CC) -I../../include -g -o afl-untracer afl-untracer.c -ldl + +clean: + rm -f afl-untracer *~ core diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md new file mode 100644 index 00000000..90798028 --- /dev/null +++ b/examples/afl_untracer/README.md @@ -0,0 +1,11 @@ +# afl-untracer + +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 +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). diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c new file mode 100644 index 00000000..112573e2 --- /dev/null +++ b/examples/afl_untracer/afl-untracer.c @@ -0,0 +1,581 @@ +/* + american fuzzy lop++ - afl-untracer skeleton example + --------------------------------------------------- + + Written by Marc Heuse + + 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 + + + HOW-TO + ====== + + You only need to change the following: + + 1. decide if you want to receive data from stdin [DEFAULT] or file(name) + -> use_stdin = 0 if via file, and what the maximum input size is + 2. dl load the library you want to fuzz, lookup the functions you need + and setup the calls to these + 3. in the while loop you call the functions in the necessary order - + incl the cleanup. the cleanup is important! + + Just look these steps up in the code, look for "// STEP x:" + + +*/ + +#define __USE_GNU +#define _GNU_SOURCE + +#ifdef __ANDROID__ +#include "android-ashmem.h" +#endif +#include "config.h" +#include "types.h" +#include "debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(__linux__) +#include +#elif defined(__APPLE__) && defined(__LP64__) +#include +#else +#error "Unsupproted platform" +#endif + +#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 + +u8 __afl_dummy[MAP_SIZE]; +u8 *__afl_area_ptr = __afl_dummy; + +typedef struct library_list { + + u8 *name; + u64 addr_start, addr_end; + +} library_list_t; + +library_list_t liblist[MAX_LIB_COUNT]; +u32 liblist_cnt; +u32 use_stdin = 1; + +static void sigtrap_handler(int signum, siginfo_t *si, void *context); + +/* read the library information */ +void read_library_information() { + +#if defined(__linux__) + FILE *f; + u8 buf[1024], *b, *m, *e, *n; + + if ((f = fopen("/proc/self/maps", "r")) == NULL) + FATAL("cannot open /proc/self/maps"); + + fprintf(stderr, "Library list:\n"); + while (fgets(buf, sizeof(buf), f)) { + + if (strstr(buf, " r-xp ")) { + + if (liblist_cnt >= MAX_LIB_COUNT) { + + WARNF("too many libraries to old, maximum count of %d reached", + liblist_cnt); + return; + + } + + b = buf; + m = index(buf, '-'); + e = index(buf, ' '); + if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' '); + if (n && + ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '(')) + n = NULL; + else + n++; + if (b && m && e && n && *n) { + + *m++ = 0; + *e = 0; + if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0; + + 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); + liblist_cnt++; + + } + + } + + } + + fprintf(stderr, "\n"); + +#endif + +} + +library_list_t *find_library(char *name) { + +#if defined(__linux__) + u32 i; + + for (i = 0; i < liblist_cnt; i++) + if (strncmp(liblist[i].name, name, strlen(name)) == 0) return &liblist[i]; +#elif defined(__APPLE__) && defined(__LP64__) + kern_return_t err; + static library_list_t lib; + + // get the list of all loaded modules from dyld + // the task_info mach API will get the address of the dyld all_image_info + // struct for the given task from which we can get the names and load + // addresses of all modules + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + err = task_info(mach_task_self(), TASK_DYLD_INFO, + (task_info_t)&task_dyld_info, &count); + + const struct dyld_all_image_infos *all_image_infos = + (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; + const struct dyld_image_info *image_infos = all_image_infos->infoArray; + + for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { + + const char * image_name = image_infos[i].imageFilePath; + mach_vm_address_t image_load_address = + (mach_vm_address_t)image_infos[i].imageLoadAddress; + if (strstr(image_name, name)) { + + lib.name = name; + lib.addr_start = (u64)image_load_address; + lib.addr_end = 0; + return &lib; + + } + + } + +#endif + + return NULL; + +} + +/* Error reporting to forkserver controller */ + +void send_forkserver_error(int error) { + + u32 status; + if (!error || error > 0xffff) return; + status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return; + +} + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + char *id_str = getenv(SHM_ENV_VAR); + char *ptr; + + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { + + u32 val = atoi(ptr); + if (val > 0) __afl_map_size = val; + + } + + if (__afl_map_size > MAP_SIZE) { + + if (__afl_map_size > FS_OPT_MAX_MAPSIZE) { + + fprintf(stderr, + "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + if (id_str) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + exit(-1); + + } + + } else { + + fprintf(stderr, + "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to " + "be able to run this instrumented program!\n", + __afl_map_size); + + } + + } + + if (id_str) { + +#ifdef USEMMAP + const char * shm_file_path = id_str; + int shm_fd = -1; + unsigned char *shm_base = NULL; + + /* create the shared memory segment as if it was a file */ + shm_fd = shm_open(shm_file_path, O_RDWR, 0600); + if (shm_fd == -1) { + + fprintf(stderr, "shm_open() failed\n"); + send_forkserver_error(FS_ERROR_SHM_OPEN); + exit(1); + + } + + /* map the shared memory segment to the address space of the process */ + shm_base = + mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + + if (shm_base == MAP_FAILED) { + + close(shm_fd); + shm_fd = -1; + + fprintf(stderr, "mmap() failed\n"); + send_forkserver_error(FS_ERROR_MMAP); + exit(2); + + } + + __afl_area_ptr = shm_base; +#else + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, 0, 0); + +#endif + + if (__afl_area_ptr == (void *)-1) { + + send_forkserver_error(FS_ERROR_SHMAT); + exit(1); + + } + + /* Write something into the bitmap so that the parent doesn't give up */ + + __afl_area_ptr[0] = 1; + + } + +} + +/* Fork server logic. */ + +static void __afl_start_forkserver(void) { + + u8 tmp[4] = {0, 0, 0, 0}; + u32 status = 0; + + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + + /* Phone home and tell the parent that we're OK. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + +} + +static u32 __afl_next_testcase(u8 *buf, u32 max_len) { + + s32 status, res = 0xffffff; + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &status, 4) != 4) return 0; + + /* we have a testcase - read it if we read from stdin */ + if (use_stdin) status = read(0, buf, max_len); + + /* report that we are starting the target */ + if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; + + if (status < 1) + return 0; + else + return status; + +} + +static void __afl_end_testcase(void) { + + int status = 0xffffff; + + if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1); + +} + +#define SHADOW(addr) \ + ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \ + MEMORY_MAP_DECREMENT - \ + ((uintptr_t)addr & 0x3) * 0x10000000000)) + +void setup_trap_instrumentation() { + + library_list_t *lib_base = NULL; + size_t lib_size = 0; + u8 * lib_addr; + char * line = NULL; + size_t nread, len = 0; + char * filename = getenv("AFL_UNTRACER_FILE"); + if (!filename) filename = getenv("TRAPFUZZ_FILE"); + if (!filename) FATAL("AFL_UNTRACER_FILE environment variable not set"); + + FILE *patches = fopen(filename, "r"); + 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; + + while ((nread = getline(&line, &len, patches)) != -1) { + + char *end = line + len; + + char *col = strchr(line, ':'); + if (col) { + + // It's a library:size pair + *col++ = 0; + + lib_base = find_library(line); + if (!lib_base) FATAL("Library %s does not appear to be loaded", line); + + // we ignore the defined lib_size + lib_size = strtoul(col, NULL, 16); +#if (__linux__) + if (lib_size < lib_base->addr_end - lib_base->addr_start) + lib_size = lib_base->addr_end - lib_base->addr_start; +#endif + if (lib_size % 0x1000 != 0) + WARNF("Invalid library size 0x%zx. Must be multiple of 0x1000", + lib_size); + + lib_addr = (u8 *)lib_base->addr_start; + + // Make library code writable. + if (mprotect((void *)lib_addr, lib_size, + PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + FATAL("Failed to mprotect library %s writable", line); + + // Create shadow memory. + for (int i = 0; i < 4; i++) { + + 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 (shadow == MAP_FAILED) FATAL("Failed to mmap shadow memory"); + + } + + // Done, continue with next line. + continue; + + } + + // It's an offset, parse it and do the patching. + unsigned long offset = strtoul(line, NULL, 16); + if (offset > lib_size) + 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); + + // 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); + +#else + // 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 +#endif + + } + + free(line); + fclose(patches); + + // Install signal handler for SIGTRAP. + struct sigaction s; + s.sa_flags = SA_SIGINFO; + s.sa_sigaction = sigtrap_handler; + sigemptyset(&s.sa_mask); + sigaction(SIGTRAP, &s, 0); + + 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); + +} + +static void sigtrap_handler(int signum, siginfo_t *si, void *context) { + + uint64_t addr; + // Must re-execute the instruction, so decrement PC by one instruction. + ucontext_t *ctx = (ucontext_t *)context; +#if defined(__APPLE__) && defined(__LP64__) + ctx->uc_mcontext->__ss.__rip -= 1; + addr = ctx->uc_mcontext->__ss.__rip; +#elif defined(__linux__) + ctx->uc_mcontext.gregs[REG_RIP] -= 1; + addr = ctx->uc_mcontext.gregs[REG_RIP]; +#else +#error "Unsupported platform" +#endif + + 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) + faultaddr = (u8 *)si->si_addr - 1; + else + faultaddr = (u8 *)addr; + // u8 *loc = SHADOW(faultaddr); + 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); + + // Index zero is invalid so that it is still possible to catch actual trap + // instructions in instrumented libraries. + if (index == 0) abort(); + + // Restore original instruction + *faultaddr = orig_byte; + + __afl_area_ptr[index] = 128; + +} + +/* 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); + +int main(int argc, char *argv[]) { + + // STEP 1: use stdin or filename via commandline and set the maximum + // size for a test case + + /* 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; + + /* This is were the testcase data is written into */ + u8 buf[10000]; // this is the maximum size for a test case! set it! + + // 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); + 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"); + + // 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) { + +// -> this still needs threading otherwise fuzzing stops when we crash + + // 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! + u8 *file (*o_function)(argv[1], "wl"); + + // we have to release memory + if (file) (void)(*o_TIFFClose)(file); + + // END STEP 3 + + /* report the test case is done and wait for the next */ + __afl_end_testcase(); + + } + + return 0; + +} + diff --git a/examples/afl_untracer/ida_get_patchpoints.py b/examples/afl_untracer/ida_get_patchpoints.py new file mode 100644 index 00000000..5a79658d --- /dev/null +++ b/examples/afl_untracer/ida_get_patchpoints.py @@ -0,0 +1,52 @@ +# +# IDAPython script for IDA Pro +# Slightly modified from https://github.com/googleprojectzero/p0tools/blob/master/TrapFuzz/findPatchPoints.py +# + +import idautils +import idaapi +import ida_nalt +import idc + +# See https://www.hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml + +from os.path import expanduser +home = expanduser("~") + +patchpoints = set() + +max_offset = 0 +for seg_ea in idautils.Segments(): + name = idc.get_segm_name(seg_ea) + #print("Segment: " + name) + if name != "__text" and name != ".text": + continue + + start = idc.get_segm_start(seg_ea) + end = idc.get_segm_end(seg_ea) + #print("Start: " + hex(start) + " End: " + hex(end)) + for func_ea in idautils.Functions(start, end): + f = idaapi.get_func(func_ea) + if not f: + continue + for block in idaapi.FlowChart(f): + if start <= block.start_ea < end: + max_offset = max(max_offset, block.start_ea) + patchpoints.add(block.start_ea) + #else: + # print("Warning: broken CFG?") + +# Round up max_offset to page size +size = max_offset +rem = size % 0x1000 +if rem != 0: + size += 0x1000 - rem + +print("Writing to " + home + "/Desktop/patches.txt") + +with open(home + "/Desktop/patches.txt", "w") as f: + f.write(ida_nalt.get_root_filename() + ':' + hex(size) + '\n') + f.write('\n'.join(map(hex, sorted(patchpoints)))) + f.write('\n') + +print("Done, found {} patchpoints".format(len(patchpoints))) -- cgit 1.4.1 From e68d2345d5c301dfdf7df3a86ccb0d9eb0aabbbd Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Wed, 29 Apr 2020 22:25:10 +0200 Subject: test.sh: continue after failed test case qemu persistent mode --- test/test.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test.sh b/test/test.sh index b8d4208f..e950e3de 100755 --- a/test/test.sh +++ b/test/test.sh @@ -802,7 +802,6 @@ test -e ../afl-qemu-trace && { echo CUT------------------------------------------------------------------CUT $ECHO "$RED[!] afl-fuzz is not working correctly with persistent qemu_mode" CODE=1 - exit 1 } rm -rf in out errors } || { -- cgit 1.4.1 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 --- examples/afl_untracer/Makefile | 7 +- examples/afl_untracer/afl-untracer.c | 238 +++++++++++++++++++++++------------ examples/afl_untracer/libtestinstr.c | 35 ++++++ src/afl-common.c | 2 +- 4 files changed, 199 insertions(+), 83 deletions(-) create mode 100644 examples/afl_untracer/libtestinstr.c 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 #include #include +#include #include #include @@ -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 +#include +#include +#include +#include +#include +#include + +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 -- 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 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 16f9cc73696b7d1bb32cdde954451b92d4c6569d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 30 Apr 2020 21:13:45 +0200 Subject: afl-network-client fix --- examples/afl_network_proxy/afl-network-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c index 53512286..b510aa14 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -287,7 +287,7 @@ int main(int argc, char *argv[]) { FATAL("did not receive waitpid data (%d, %d)", received, ret); // fprintf(stderr, "Received status\n"); - int received = 0; + received = 0; while (received < __afl_map_size && (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received, 0)) > 0) -- cgit 1.4.1 From 15547eb654d8edc9ecb2cd880322a82953cfa492 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 30 Apr 2020 21:17:13 +0200 Subject: fix send child status --- examples/afl_network_proxy/afl-network-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index 2f9f8c8e..e069af3d 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -579,7 +579,7 @@ 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) + 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"); -- cgit 1.4.1 From 59043b24ccdb15c2af3281570551990bc58e162e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 30 Apr 2020 21:29:30 +0100 Subject: afl-untracer raw freebsd support. --- examples/afl_untracer/afl-untracer.c | 67 ++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 4d512356..275df320 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -61,6 +61,9 @@ #include #elif defined(__APPLE__) && defined(__LP64__) #include +#elif defined(__FreeBSD__) +#include +#include #else #error "Unsupproted platform" #endif @@ -165,6 +168,67 @@ void read_library_information() { if (debug) fprintf(stderr, "\n"); +#elif defined(__FreeBSD__) + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, -1}; + char *buf, *start, *end; + size_t miblen = sizeof(mib) / sizeof(mib[0]); + size_t len; + + 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 (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { + + munmap(buf, len); + return; + + } + + start = buf; + end = buf + len; + + while (start < end) { + + struct kinfo_vmentry *region = (struct kinfo_vmentry *)start; + size_t size = region->kve_structsize; + + 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; + + 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++; + } + + start += size; + + } #endif } @@ -524,6 +588,9 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { #elif defined(__linux__) ctx->uc_mcontext.gregs[REG_RIP] -= 1; addr = ctx->uc_mcontext.gregs[REG_RIP]; +#elif defined(__FreeBSD__) && defined(__LP64__) + ctx->uc_mcontext.mc_rip -= 1; + addr = ctx->uc_mcontext.mc_rip; #else #error "Unsupported platform" #endif -- cgit 1.4.1 From 3cf4529f3ca50479f1f91b49be8a5e9c54d4588e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 30 Apr 2020 23:01:46 +0100 Subject: afl-untracer little change to display libraries mapping on FreeBSD. --- examples/afl_untracer/afl-untracer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 275df320..9f9ea3f1 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -169,11 +169,12 @@ void read_library_information() { if (debug) fprintf(stderr, "\n"); #elif defined(__FreeBSD__) - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, -1}; + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; 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; -- cgit 1.4.1 From 9d03763d942c19ac9c6cbe7d6a3f3cecba65abad Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 1 May 2020 00:57:20 +0200 Subject: at some point we have to do a rewrite of llvm_mode/GNUmakefile --- llvm_mode/GNUmakefile | 95 +++++++++++++++++++++++++++++------------------ llvm_mode/README.md | 21 ++++++++++- llvm_mode/afl-llvm-rt.o.c | 2 +- 3 files changed, 80 insertions(+), 38 deletions(-) diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 69b0875e..2cbe53cd 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -38,7 +38,7 @@ else LLVM_CONFIG ?= llvm-config endif -LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null ) +LLVMVER = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' ) LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-7]|^1[2-9]' && echo 1 || echo 0 ) LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 ) LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//') @@ -82,30 +82,66 @@ endif # this seems to be busted on some distros, so using the one in $PATH is # probably better. -CC ?= $(LLVM_BINDIR)/clang -CXX ?= $(LLVM_BINDIR)/clang++ +CC = $(LLVM_BINDIR)/clang +CXX = $(LLVM_BINDIR)/clang++ +# llvm-config --bindir may not providing a valid path, so ... ifeq "$(shell test -e $(CC) || echo 1 )" "1" - # llvm-config --bindir may not providing a valid path, so ... - ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1" - # we found one in the local install directory, lets use these - CC = $(BIN_DIR)/clang - CXX = $(BIN_DIR)/clang++ - else - # hope for the best - $(warning we have trouble finding clang/clang++ - llvm-config is not helping us) - CC = clang - CXX = clang++ + # however we must ensure that this is not a "CC=gcc make" + ifeq "$(shell command -v $(CC) 2> /dev/null)" "" + # we do not have a valid CC variable so we try alternatives + ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1" + # we found one in the local install directory, lets use these + CC = $(BIN_DIR)/clang + CXX = $(BIN_DIR)/clang++ + else + # hope for the best + $(warning we have trouble finding clang/clang++ - llvm-config is not helping us) + CC = clang + CXX = clang++ + endif endif endif # sanity check. # Are versions of clang --version and llvm-config --version equal? -CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([0-9]\.[0-9]\.[0-9]).*/s//\1/p') +CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p') -ifneq "$(CLANGVER)" "$(LLVMVER)" - CC = $(shell $(LLVM_CONFIG) --bindir)/clang - CXX = $(shell $(LLVM_CONFIG) --bindir)/clang++ +# I disable this because it does not make sense with what we did before (marc) +# We did exactly set these 26 lines above with these values, and it would break +# "CC=gcc make" etc. usages +ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" + CC_SAVE = $(LLVM_BINDIR)/clang +else + CC_SAVE = $(CC) +endif +ifeq "$(findstring clang, $(shell $(CXX) --version 2>/dev/null))" "" + CXX_SAVE = $(LLVM_BINDIR)/clang++ +else + CXX_SAVE = $(CXX) +endif + +CLANG_BIN = $(CC_SAVE) +CLANGPP_BIN = $(CXX_SAVE) + +ifeq "$(CC_SAVE)" "$(LLVM_BINDIR)/clang" + USE_BINDIR = 1 +else + ifeq "$(CXX_SAVE)" "$(LLVM_BINDIR)/clang++" + USE_BINDIR = 1 + else + USE_BINDIR = 0 + endif +endif + +# On old platform we cannot compile with clang because std++ libraries are too +# old. For these we need to use gcc/g++, so if we find REAL_CC and REAL_CXX +# variable we override the compiler variables here +ifneq "$(REAL_CC)" "" +CC = $(REAL_CC) +endif +ifneq "$(REAL_CXX)" "" +CXX = $(REAL_CXX) endif # After we set CC/CXX we can start makefile magic tests @@ -146,19 +182,6 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -fuse-ld=`command -v endif endif -CLANG_BIN = $(basename $(CC)) -CLANGPP_BIN = $(basename $(CXX)) -ifeq "$(shell test -e $(CLANG_BIN) || echo 1 )" "1" - CLANG_BIN = $(CC) - CLANGPP_BIN = $(CXX) -endif - -ifeq "$(CC)" "$(LLVM_BINDIR)/clang" - USE_BINDIR = 1 -else - USE_BINDIR = 0 -endif - CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2 override CFLAGS += -Wall \ -g -Wno-pointer-sign -I ../include/ \ @@ -166,7 +189,7 @@ override CFLAGS += -Wall \ -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \ -DLLVM_VERSION=\"$(LLVMVER)\" -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \ -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \ - -DCLANG_BIN=\"$(CC)\" -DCLANGPP_BIN=\"$(CXX)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function + -DCLANG_BIN=\"$(CLANG_BIN)\" -DCLANGPP_BIN=\"$(CLANGPP_BIN)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function ifdef AFL_TRACE_PC $(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets ) endif @@ -249,7 +272,7 @@ test_deps: @echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'" ifneq "$(CLANGVER)" "$(LLVMVER)" @echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)" - @echo "[!] Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang" + @echo "[!] Retry with the clang compiler from llvm: CC=`llvm-config --bindir`/clang" else @echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good." endif @@ -290,9 +313,9 @@ endif ../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc afl-llvm-common.o ifeq "$(LLVM_LTO)" "1" $(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o - $(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o - @$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi - @$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi + $(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o + @$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi + @$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi endif # laf @@ -323,7 +346,7 @@ endif test_build: $(PROGS) @echo "[*] Testing the CC wrapper and instrumentation output..." - unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_CC=$(CC) AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) + unset AFL_USE_ASAN AFL_USE_MSAN AFL_INST_RATIO; AFL_QUIET=1 AFL_PATH=. AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast $(CFLAGS) ../test-instr.c -o test-instr $(LDFLAGS) ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null echo 1 | ASAN_OPTIONS=detect_leaks=0 ../afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr diff --git a/llvm_mode/README.md b/llvm_mode/README.md index 607350fb..0bff1ff1 100644 --- a/llvm_mode/README.md +++ b/llvm_mode/README.md @@ -37,7 +37,26 @@ co-exists with the original code. The idea and much of the implementation comes from Laszlo Szekeres. -## 2) How to use this +## 2a) How to use this - short + +Set the `LLVM_CONFIG` variable to the clang version you want to use, e.g. +``` +LLVM_CONFIG=llvm-config-9 make +``` +In case you have your own compiled llvm version specify the full path: +``` +LLVM_CONFIG=~/llvm-project/build/bin/llvm-config make +``` +If you try to use a new llvm version on an old Linux this can fail because of +old c++ libraries. In this case usually switching to gcc/g++ to compile +llvm_mode will work: +``` +LLVM_CONFIG=llvm-config-7 REAL_CC=gcc REAL_CXX=g++ make +``` +It is highly recommended to use the newest clang version you can put your +hands on :) + +## 2b) How to use this - long In order to leverage this mechanism, you need to have clang installed on your system. You should also make sure that the llvm-config tool is in your path diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 8867ae36..722ca421 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -152,7 +152,7 @@ static void __afl_map_shm(void) { if (getenv("AFL_DEBUG")) fprintf(stderr, - "DEBUG: id_str %s, __afl_map_addr 0x%x, MAP_SIZE %u, " + "DEBUG: id_str %s, __afl_map_addr 0x%lx, MAP_SIZE %u, " "__afl_final_loc %u, max_size_forkserver %u/0x%x\n", id_str == NULL ? "" : id_str, __afl_map_addr, MAP_SIZE, __afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE); -- 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(-) 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 be4e5d2617e6d994457fa2434df65f6c180d9a2f Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 1 May 2020 02:07:35 +0200 Subject: minor sample things --- unicorn_mode/samples/persistent/Makefile | 3 +++ unicorn_mode/samples/persistent/harness.c | 4 ++-- unicorn_mode/samples/persistent/persistent_target | Bin 0 -> 20048 bytes 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100755 unicorn_mode/samples/persistent/persistent_target diff --git a/unicorn_mode/samples/persistent/Makefile b/unicorn_mode/samples/persistent/Makefile index cb491e10..9c7ed7aa 100644 --- a/unicorn_mode/samples/persistent/Makefile +++ b/unicorn_mode/samples/persistent/Makefile @@ -45,3 +45,6 @@ harness: harness.o debug: harness-debug.o ${MYCC} -L${LIBDIR} harness.o ../../unicornafl/libunicornafl.a $(LDFLAGS) -o harness-debug + +fuzz: harness + ../../../afl-fuzz -m none -i sample_inputs -o out -- ./harness @@ diff --git a/unicorn_mode/samples/persistent/harness.c b/unicorn_mode/samples/persistent/harness.c index 02d96e90..3d379f46 100644 --- a/unicorn_mode/samples/persistent/harness.c +++ b/unicorn_mode/samples/persistent/harness.c @@ -151,7 +151,7 @@ static void mem_map_checked(uc_engine *uc, uint64_t addr, size_t size, uint32_t //printf("SIZE %llx, align: %llx\n", size, ALIGNMENT); uc_err err = uc_mem_map(uc, addr, size, mode); if (err != UC_ERR_OK) { - printf("Error mapping %ld bytes at 0x%lx: %s (mode: %d)\n", size, addr, uc_strerror(err), mode); + printf("Error mapping %zu bytes at 0x%llx: %s (mode: %d)\n", size, (unsigned long long) addr, uc_strerror(err), mode); exit(1); } } @@ -213,7 +213,7 @@ int main(int argc, char **argv, char **envp) { // Setup the Stack mem_map_checked(uc, STACK_ADDRESS - STACK_SIZE, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); uint64_t stack_val = STACK_ADDRESS; - printf("%lu", stack_val); + printf("%llu", (unsigned long long) stack_val); uc_reg_write(uc, UC_X86_REG_RSP, &stack_val); // reserve some space for our input data diff --git a/unicorn_mode/samples/persistent/persistent_target b/unicorn_mode/samples/persistent/persistent_target new file mode 100755 index 00000000..83421a4f Binary files /dev/null and b/unicorn_mode/samples/persistent/persistent_target differ -- cgit 1.4.1 From 9f01737fa7e375e30acef05da9f93d26fcdf664e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 1 May 2020 02:08:04 +0200 Subject: updated unicorn --- unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index 0afcf291..3d95ba0b 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -25ae270 +f8e3792ed07710c5138e016376b73298999a35dc diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 25ae270c..f8e3792e 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 25ae270c1b949a5d1c2c5460b778f0a35bfe67d7 +Subproject commit f8e3792ed07710c5138e016376b73298999a35dc -- cgit 1.4.1 From a2bc3538f746b1e8f1c7b474b3a7b1fcc332998e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 1 May 2020 12:03:41 +0200 Subject: python no longer needed for build --- unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/build_unicorn_support.sh | 2 +- unicorn_mode/unicornafl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index 3d95ba0b..11bd2155 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -f8e3792ed07710c5138e016376b73298999a35dc +d4cc77cce71c15bb3d1f552d703a77e2a17cf42d diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index 965d7614..0961d6e1 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -183,7 +183,7 @@ echo "[*] Attempting to build unicornafl (fingers crossed!)..." $MAKECMD clean # make doesn't seem to work for unicorn # Fixed to 1 core for now as there is a race condition in the makefile -UNICORN_QEMU_FLAGS="--python=$PYTHONBIN" $MAKECMD -j1 || exit 1 +$MAKECMD -j1 || exit 1 echo "[+] Build process successful!" diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index f8e3792e..d4cc77cc 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit f8e3792ed07710c5138e016376b73298999a35dc +Subproject commit d4cc77cce71c15bb3d1f552d703a77e2a17cf42d -- cgit 1.4.1 From 33ddf6ea0e090ec2ef18dfa7c53b4dfe8130de26 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 1 May 2020 17:07:44 +0200 Subject: add ghidra script and workaround ghidra/linux/ida weirdness --- examples/afl_untracer/README.md | 4 ++ examples/afl_untracer/afl-untracer.c | 16 +---- examples/afl_untracer/ghidra_get_patchpoints.java | 84 +++++++++++++++++++++++ examples/afl_untracer/ida_get_patchpoints.py | 9 ++- 4 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 examples/afl_untracer/ghidra_get_patchpoints.java diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md index d3af0ceb..4ff96423 100644 --- a/examples/afl_untracer/README.md +++ b/examples/afl_untracer/README.md @@ -10,6 +10,10 @@ 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). +To generate the `patches.txt` file for your target library use the +`ida_get_patchpoints.py` script for IDA Pro or +`ghidra_get_patchpoints.java` for Ghidra. + 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 diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 5338bfd5..f812958c 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -506,18 +506,6 @@ 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); @@ -526,10 +514,12 @@ void setup_trap_instrumentation() { FATAL("Too many basic blocks to instrument"); uint32_t *shadow = SHADOW(lib_addr + offset); - if (*shadow != 0) FATAL("Duplicate patch entry: 0x%lx", offset); + if (*shadow != 0) continue; // skip duplicates // 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]; diff --git a/examples/afl_untracer/ghidra_get_patchpoints.java b/examples/afl_untracer/ghidra_get_patchpoints.java new file mode 100644 index 00000000..d341bea4 --- /dev/null +++ b/examples/afl_untracer/ghidra_get_patchpoints.java @@ -0,0 +1,84 @@ +/* ### + * IP: GHIDRA + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Find patch points for untracer tools (e.g. afl++ examples/afl_untracer) +// +// Copy to ..../Ghidra/Features/Search/ghidra_scripts/ +// Writes the results to ~/Desktop/patches.txt +// +// This is my very first Ghidra script. I am sure this could be done better. +// +//@category Search + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.*; +import ghidra.program.model.block.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.*; +import ghidra.program.model.mem.*; + +import java.io.*; + +public class ghidra_get_patchpoints extends GhidraScript { + + @Override + public void run() throws Exception { + + long segment_start = 0; + Memory memory = currentProgram.getMemory(); + MultEntSubModel model = new MultEntSubModel(currentProgram); + CodeBlockIterator subIter = model.getCodeBlocks(monitor); + BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt")); + + while (subIter.hasNext()) { + + CodeBlock multiEntryBlock = subIter.next(); + SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram); + CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor); + + while (bbIter.hasNext()) { + + CodeBlock basicBlock = bbIter.next(); + + if (segment_start == 0) { + + Address firstAddr = basicBlock.getFirstStartAddress(); + long firstBlockAddr = firstAddr.getAddressableWordOffset(); + MemoryBlock mb = memory.getBlock(firstAddr); + Address startAddr = mb.getStart(); + Address endAddr = mb.getEnd(); + segment_start = startAddr.getAddressableWordOffset(); + if ((firstBlockAddr - segment_start) >= 0x1000) + segment_start += 0x1000; + long segment_end = endAddr.getAddressableWordOffset(); + long segment_size = segment_end - segment_start; + if ((segment_size % 0x1000) > 0) + segment_size = (((segment_size / 0x1000) + 1) * 0x1000); + out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n"); + //println("Start: " + Long.toHexString(segment_start)); + //println("End: " + Long.toHexString(segment_end)); + + } + + if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0) + out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n"); + + } + } + + out.close(); + + } +} diff --git a/examples/afl_untracer/ida_get_patchpoints.py b/examples/afl_untracer/ida_get_patchpoints.py index 5a79658d..c7e8f899 100644 --- a/examples/afl_untracer/ida_get_patchpoints.py +++ b/examples/afl_untracer/ida_get_patchpoints.py @@ -24,6 +24,8 @@ for seg_ea in idautils.Segments(): start = idc.get_segm_start(seg_ea) end = idc.get_segm_end(seg_ea) + first = 0 + subtract_addr = 0 #print("Start: " + hex(start) + " End: " + hex(end)) for func_ea in idautils.Functions(start, end): f = idaapi.get_func(func_ea) @@ -31,8 +33,13 @@ for seg_ea in idautils.Segments(): continue for block in idaapi.FlowChart(f): if start <= block.start_ea < end: + if first == 0: + if block.start_ea >= 0x1000: + subtract_addr = 0x1000 + first = 1 + max_offset = max(max_offset, block.start_ea) - patchpoints.add(block.start_ea) + patchpoints.add(block.start_ea - subtract_addr) #else: # print("Warning: broken CFG?") -- 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(-) 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 ff1643d81fc42005206f4f1a390bdbd99856371a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 2 May 2020 00:43:33 +0200 Subject: todo update --- TODO.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/TODO.md b/TODO.md index d31178c8..12614f05 100644 --- a/TODO.md +++ b/TODO.md @@ -1,9 +1,9 @@ # TODO list for AFL++ -## Roadmap 2.65 +## Roadmap 2.65+ + - implement ngram and ctx in InsTrim - AFL_MAP_SIZE for afl-llvm-pass, qemu_mode and unicorn_mode - - fix stability calculation bug - random crc32 HASH_CONST per run? because with 65536 paths we have collisions - namespace for targets? e.g. network - libradamsa as a custom module? @@ -13,12 +13,10 @@ afl-fuzz: - sync_fuzzers(): only masters sync from all, slaves only sync from master (@andrea: be careful, often people run all slaves) - - ascii_only mode for mutation output + - ascii_only mode for mutation output - or use a custom mutator for this? - setting min_len/max_len/start_offset/end_offset limits for mutation output llvm_mode: - - added context sensitive branch coverage - - add CT cov and ngram cov to LTO and InsTrim - better whitelist solution for LTO gcc_plugin: @@ -26,18 +24,11 @@ gcc_plugin: - better instrumentation (seems to be better with gcc-9+) qemu_mode: - - update to 4.x (probably this will be skipped :( ) + - update to 5.x (if the performance bug if gone) - non colliding instrumentation - - instrim for QEMU mode via static analysis (with r2pipe? or angr?) - Idea: The static analyzer outputs a map in which each edge that must be - skipped is marked with 1. QEMU loads it at startup in the parent process. - rename qemu specific envs to AFL_QEMU (AFL_ENTRYPOINT, AFL_CODE_START/END, AFL_COMPCOV_LEVEL?) - add AFL_QEMU_EXITPOINT (maybe multiple?), maybe pointless as we have persistent mode - add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM - add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses - -custom_mutators: - - rip what Superion is doing into custom mutators for js, php, etc. - -- cgit 1.4.1 From 0c5c172a3045d2810d5e55169fbeece29620f7dd Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 2 May 2020 12:57:33 +0200 Subject: makefile fix --- llvm_mode/GNUmakefile | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 2cbe53cd..93886e47 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -93,11 +93,24 @@ ifeq "$(shell test -e $(CC) || echo 1 )" "1" ifeq "$(shell test -e '$(BIN_DIR)/clang' && echo 1)" "1" # we found one in the local install directory, lets use these CC = $(BIN_DIR)/clang - CXX = $(BIN_DIR)/clang++ else # hope for the best - $(warning we have trouble finding clang/clang++ - llvm-config is not helping us) + $(warning we have trouble finding clang - llvm-config is not helping us) CC = clang + endif + endif +endif +# llvm-config --bindir may not providing a valid path, so ... +ifeq "$(shell test -e $(CXX) || echo 1 )" "1" + # however we must ensure that this is not a "CC=gcc make" + ifeq "$(shell command -v $(CXX) 2> /dev/null)" "" + # we do not have a valid CC variable so we try alternatives + ifeq "$(shell test -e '$(BIN_DIR)/clang++' && echo 1)" "1" + # we found one in the local install directory, lets use these + CXX = $(BIN_DIR)/clang++ + else + # hope for the best + $(warning we have trouble finding clang++ - llvm-config is not helping us) CXX = clang++ endif endif @@ -111,18 +124,18 @@ CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[ # We did exactly set these 26 lines above with these values, and it would break # "CC=gcc make" etc. usages ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" "" - CC_SAVE = $(LLVM_BINDIR)/clang + CC_SAVE := $(LLVM_BINDIR)/clang else - CC_SAVE = $(CC) + CC_SAVE := $(CC) endif ifeq "$(findstring clang, $(shell $(CXX) --version 2>/dev/null))" "" - CXX_SAVE = $(LLVM_BINDIR)/clang++ + CXX_SAVE := $(LLVM_BINDIR)/clang++ else - CXX_SAVE = $(CXX) + CXX_SAVE := $(CXX) endif -CLANG_BIN = $(CC_SAVE) -CLANGPP_BIN = $(CXX_SAVE) +CLANG_BIN := $(CC_SAVE) +CLANGPP_BIN := $(CXX_SAVE) ifeq "$(CC_SAVE)" "$(LLVM_BINDIR)/clang" USE_BINDIR = 1 @@ -150,13 +163,13 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -march=native -o .te CFLAGS_OPT = -march=native endif -ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" +ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" AFL_CLANG_FLTO ?= -flto=full else - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" AFL_CLANG_FLTO ?= -flto=thin else - ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" + ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" AFL_CLANG_FLTO ?= -flto endif endif @@ -177,7 +190,7 @@ endif AFL_CLANG_FUSELD= ifneq "$(AFL_CLANG_FLTO)" "" -ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" +ifeq "$(shell echo 'int main() {return 0; }' | $(CLANG_BIN) -x c - -fuse-ld=`command -v ld` -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1" AFL_CLANG_FUSELD=1 endif endif @@ -272,7 +285,6 @@ test_deps: @echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'" ifneq "$(CLANGVER)" "$(LLVMVER)" @echo "[!] WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)" - @echo "[!] Retry with the clang compiler from llvm: CC=`llvm-config --bindir`/clang" else @echo "[*] We have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good." endif -- cgit 1.4.1 From 1c53bbea52cfecf6c886bb441f1c99c1ae28b0e6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 3 May 2020 14:09:32 +0200 Subject: doubled the speed of afl_network_proxy --- examples/afl_network_proxy/Makefile | 24 +---- examples/afl_network_proxy/README.md | 21 ++-- examples/afl_network_proxy/afl-network-client.c | 119 ++++++++++++++++++-- examples/afl_network_proxy/afl-network-server.c | 138 +++++++++++++++++++++--- 4 files changed, 246 insertions(+), 56 deletions(-) diff --git a/examples/afl_network_proxy/Makefile b/examples/afl_network_proxy/Makefile index eeee1178..0b306dde 100644 --- a/examples/afl_network_proxy/Makefile +++ b/examples/afl_network_proxy/Makefile @@ -1,22 +1,2 @@ -PREFIX ?= /usr/local -BIN_PATH = $(PREFIX)/bin -DOC_PATH = $(PREFIX)/share/doc/afl - -PROGRAMS = afl-network-client afl-network-server - -all: $(PROGRAMS) - -afl-network-client: afl-network-client.c - $(CC) -I../../include -o afl-network-client afl-network-client.c - -afl-network-server: afl-network-server.c - $(CC) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" - -clean: - rm -f $(PROGRAMS) *~ core - -install: all - install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH) - install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH) - install -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md - \ No newline at end of file +all: + @echo please use GNU make, thanks! diff --git a/examples/afl_network_proxy/README.md b/examples/afl_network_proxy/README.md index c33096be..84ebfa48 100644 --- a/examples/afl_network_proxy/README.md +++ b/examples/afl_network_proxy/README.md @@ -12,6 +12,14 @@ Note that the impact on fuzzing speed will be huge, expect a loss of 90%. ## how to get it running +### Compiling + +Just type `make` and let the autodetection do everything for you. + +Note that compression is supported but currently disabled. It seems that +sending 64kb of map data over TCP is faster than compressing it with the +fastest algorithm and options to 112 byte and sending this. Weird. + ### on the target Run `afl-network-server` with your target with the -m and -t values you need. @@ -40,16 +48,11 @@ The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to either. Note that also the outgoing interface can be specified with a '%' for `afl-network-client`, e.g. `fe80::1234%eth0`. +Also make sure your middle value of `/proc/sys/net/ipv4/tcp_rmem` is larger +than your MAP_SIZE (130kb is a good value). This is the default TCP window +size value. + ## 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 b9cd88f0..94f6bb42 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -41,6 +41,10 @@ #include #include +#ifdef USE_DEFLATE +#include +#endif + u8 *__afl_area_ptr; #ifdef __ANDROID__ @@ -206,7 +210,12 @@ int main(int argc, char *argv[]) { u8 * interface, *buf, *ptr; s32 s = -1; struct addrinfo hints, *hres, *aip; - u32 len, max_len = 65536; + u32 * lenptr, max_len = 65536; +#ifdef USE_DEFLATE + u8 * buf2; + u32 * lenptr1, *lenptr2, buf2_len, compress_len; + size_t decompress_len; +#endif if (argc < 3 || argc > 4) { @@ -235,8 +244,17 @@ int main(int argc, char *argv[]) { if ((__afl_map_size = atoi(ptr)) < 8) FATAL("illegal map size, may not be < 8 or >= 2^30: %s", ptr); - if ((buf = malloc(max_len)) == NULL) - PFATAL("can not allocate %u memory", max_len); + if ((buf = malloc(max_len + 4)) == NULL) + PFATAL("can not allocate %u memory", max_len + 4); + lenptr = (u32 *)buf; + +#ifdef USE_DEFLATE + buf2_len = (max_len > __afl_map_size ? max_len : __afl_map_size); + if ((buf2 = malloc(buf2_len + 8)) == NULL) + PFATAL("can not allocate %u memory", buf2_len + 8); + lenptr1 = (u32 *)buf2; + lenptr2 = (u32 *)(buf2 + 4); +#endif memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; @@ -258,28 +276,81 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Warning: binding to interface is not supported for your OS\n"); #endif + +#ifdef SO_PRIORITY + int priority = 7; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < + 0) { + + priority = 6; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, + sizeof(priority)) < 0) + WARNF("could not set priority on socket"); + + } + +#endif + if (connect(s, aip->ai_addr, aip->ai_addrlen) == -1) s = -1; } } +#ifdef USE_DEFLATE + struct libdeflate_compressor *compressor; + compressor = libdeflate_alloc_compressor(1); + struct libdeflate_decompressor *decompressor; + decompressor = libdeflate_alloc_decompressor(); + fprintf(stderr, "Compile with compression support\n"); +#endif + if (s == -1) FATAL("could not connect to target tcp://%s:%s", argv[1], argv[2]); + else + fprintf(stderr, "Connected to target tcp://%s:%s\n", argv[1], argv[2]); /* we initialize the shared memory map and start the forkserver */ __afl_map_shm(); __afl_start_forkserver(); - int i = 1, j, status, ret; + int i = 1, j, status, ret, received; + // fprintf(stderr, "Waiting for first testcase\n"); - while ((len = __afl_next_testcase(buf, max_len)) > 0) { + while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) { + + // fprintf(stderr, "Sending testcase with len %u\n", *lenptr); +#ifdef USE_DEFLATE + // we only compress the testcase if it does not fit in the TCP packet + if (*lenptr > 1500 - 20 - 32 - 4) { + + // set highest byte to signify compression + *lenptr1 = (*lenptr | 0xff000000); + *lenptr2 = (u32)libdeflate_deflate_compress(compressor, buf + 4, *lenptr, + buf2 + 8, buf2_len); + if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8) + PFATAL("sending test data failed"); + fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2); + for (u32 i = 0; i < *lenptr; i++) + fprintf(stderr, "%02x", buf[i + 4]); + fprintf(stderr, "\n"); + for (u32 i = 0; i < *lenptr2; i++) + fprintf(stderr, "%02x", buf2[i + 8]); + fprintf(stderr, "\n"); + + } else { - // fprintf(stderr, "Sending testcase with len %u\n", len); - 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"); +#endif + if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4) + PFATAL("sending test data failed"); +#ifdef USE_DEFLATE + // fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr); - int received = 0; + } + +#endif + + received = 0; while (received < 4 && (ret = recv(s, &status + received, 4 - received, 0)) > 0) received += ret; @@ -288,12 +359,37 @@ int main(int argc, char *argv[]) { // fprintf(stderr, "Received status\n"); received = 0; +#ifdef USE_DEFLATE + while (received < 4 && + (ret = recv(s, &compress_len + received, 4 - received, 0)) > 0) + received += ret; + if (received != 4) + FATAL("did not receive compress_len (%d, %d)", received, ret); + // fprintf(stderr, "Received status\n"); + + received = 0; + while (received < compress_len && + (ret = recv(s, buf2 + received, buf2_len - received, 0)) > 0) + received += ret; + if (received != compress_len) + FATAL("did not receive coverage data (%d, %d)", received, ret); + + if (libdeflate_deflate_decompress(decompressor, buf2, compress_len, + __afl_area_ptr, __afl_map_size, + &decompress_len) != LIBDEFLATE_SUCCESS || + decompress_len != __afl_map_size) + FATAL("decompression failed"); +// fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len); +// for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x", +// __afl_area_ptr[i]); fprintf(stderr, "\n"); +#else 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 coverage data (%d, %d)", received, ret); +#endif // fprintf(stderr, "Received coverage\n"); /* report the test case is done and wait for the next */ @@ -302,6 +398,11 @@ int main(int argc, char *argv[]) { } +#ifdef USE_DEFLATE + libdeflate_free_compressor(compressor); + libdeflate_free_decompressor(decompressor); +#endif + return 0; } diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index e069af3d..e4c3bc6d 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -61,13 +61,21 @@ #include #include +#ifdef USE_DEFLATE +#include +struct libdeflate_compressor * compressor; +struct libdeflate_decompressor *decompressor; +#endif + static u8 *in_file, /* Minimizer input test case */ *out_file; static u8 *in_data; /* Input data for trimming */ +static u8 *buf2; -static s32 in_len; -static u32 map_size = MAP_SIZE; +static s32 in_len; +static u32 map_size = MAP_SIZE; +static size_t buf2_len; static volatile u8 stop_soon; /* Ctrl-C pressed? */ @@ -335,25 +343,64 @@ static void usage(u8 *argv0) { int recv_testcase(int s, void **buf, size_t *max_len) { - int size, received = 0, ret; + u32 size; + s32 ret; + size_t received; + received = 0; while (received < 4 && (ret = recv(s, &size + received, 4 - received, 0)) > 0) received += ret; - if (received != 4) FATAL("did not receive size information"); - if (size < 1) FATAL("did not receive valid size information"); + if (size == 0) FATAL("did not receive valid size information"); // fprintf(stderr, "received size information of %d\n", size); - *buf = maybe_grow(buf, max_len, size); - // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); - received = 0; - while (received < size && - (ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0) - received += ret; + if ((size && 0xff000000) != 0xff000000) { + + *buf = maybe_grow(buf, max_len, size); + received = 0; + // fprintf(stderr, "unCOMPRESS (%u)\n", size); + while (received < size && + (ret = recv(s, ((char *)*buf) + received, size - received, 0)) > 0) + received += ret; + + } else { + +#ifdef USE_DEFLATE + u32 clen; + size = (size & 0x00ffffff); + *buf = maybe_grow(buf, max_len, size); + received = 0; + while (received < 4 && + (ret = recv(s, &clen + received, 4 - received, 0)) > 0) + received += ret; + if (received != 4) FATAL("did not receive size information"); + // fprintf(stderr, "received clen information of %d\n", clen); + if (clen < 1) + FATAL("did not receive valid compressed len information: %u", clen); + buf2 = maybe_grow((void **)&buf2, &buf2_len, clen); + received = 0; + while (received < clen && + (ret = recv(s, buf2 + received, clen - received, 0)) > 0) + received += ret; + if (received != clen) FATAL("did not receive compressed information"); + if (libdeflate_deflate_decompress(decompressor, buf2, clen, (char *)*buf, + *max_len, + &received) != LIBDEFLATE_SUCCESS) + FATAL("decompression failed"); + // fprintf(stderr, "DECOMPRESS (%u->%u):\n", clen, received); + // for (u32 i = 0; i < clen; i++) fprintf(stderr, "%02x", buf2[i]); + // fprintf(stderr, "\n"); + // for (u32 i = 0; i < received; i++) fprintf(stderr, "%02x", + // ((u8*)(*buf))[i]); fprintf(stderr, "\n"); +#else + FATAL("Received compressed data but not compiled with compression support"); +#endif + + } + // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); if (received != size) FATAL("did not receive testcase data %u != %u, %d", received, size, ret); - // fprintf(stderr, "received testcase\n"); return size; @@ -371,6 +418,10 @@ int main(int argc, char **argv_orig, char **envp) { int addrlen = sizeof(clientaddr); char str[INET6_ADDRSTRLEN]; char ** argv = argv_cpy_dup(argc, argv_orig); + u8 * send_buf; +#ifdef USE_DEFLATE + u32 *lenptr; +#endif afl_forkserver_t fsrv_var = {0}; afl_forkserver_t *fsrv = &fsrv_var; @@ -378,6 +429,8 @@ int main(int argc, char **argv_orig, char **envp) { map_size = get_map_size(); fsrv->map_size = map_size; + if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc"); + while ((opt = getopt(argc, argv, "+i:f:m:t:QUWh")) > 0) { switch (opt) { @@ -553,6 +606,21 @@ int main(int argc, char **argv_orig, char **envp) { } #endif + +#ifdef SO_PRIORITY + int priority = 7; + if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < + 0) { + + priority = 6; + if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < + 0) + WARNF("could not set priority on socket"); + + } + +#endif + memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin6_family = AF_INET6; serveraddr.sin6_port = htons(port); @@ -566,6 +634,14 @@ int main(int argc, char **argv_orig, char **envp) { afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); +#ifdef USE_DEFLATE + compressor = libdeflate_alloc_compressor(1); + decompressor = libdeflate_alloc_decompressor(); + buf2 = maybe_grow((void **)&buf2, &buf2_len, map_size + 16); + lenptr = (u32 *)(buf2 + 4); + fprintf(stderr, "Compiled with compression support\n"); +#endif + fprintf(stderr, "Waiting for incoming connection from afl-network-client on port %d " "...\n", @@ -574,15 +650,40 @@ int main(int argc, char **argv_orig, char **envp) { if ((s = accept(sock, NULL, NULL)) < 0) { PFATAL("accept() failed"); } fprintf(stderr, "Received connection, starting ...\n"); +#ifdef SO_PRIORITY + priority = 7; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) { + + priority = 6; + if (setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) + WARNF("could not set priority on socket"); + + } + +#endif + while ((in_len = recv_testcase(s, (void **)&in_data, &max_len)) > 0) { // 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"); + memcpy(send_buf + 4, fsrv->trace_bits, fsrv->map_size); + +#ifdef USE_DEFLATE + memcpy(buf2, &fsrv->child_status, 4); + *lenptr = (u32)libdeflate_deflate_compress( + compressor, send_buf + 4, fsrv->map_size, buf2 + 8, buf2_len - 8); + // fprintf(stderr, "COMPRESS (%u->%u): ", fsrv->map_size, *lenptr); + // for (u32 i = 0; i < fsrv->map_size; i++) fprintf(stderr, "%02x", + // fsrv->trace_bits[i]); fprintf(stderr, "\n"); + if (send(s, buf2, *lenptr + 8, 0) != 8 + *lenptr) + FATAL("could not send data"); +#else + memcpy(send_buf, &fsrv->child_status, 4); + if (send(s, send_buf, fsrv->map_size + 4, 0) != 4 + fsrv->map_size) + FATAL("could not send data"); +#endif + // fprintf(stderr, "sent result\n"); } @@ -595,6 +696,11 @@ int main(int argc, char **argv_orig, char **envp) { afl_fsrv_deinit(fsrv); if (fsrv->target_path) { ck_free(fsrv->target_path); } if (in_data) { ck_free(in_data); } +#if USE_DEFLATE + if (buf2) { ck_free(buf2); } + libdeflate_free_compressor(compressor); + libdeflate_free_decompressor(decompressor); +#endif argv_cpy_free(argv); -- 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(-) 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 From 73f7164048e005aa4a29e49eaf9e05b4fe8215b7 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 4 May 2020 09:53:59 +0200 Subject: add GNUmakefile --- examples/afl_network_proxy/GNUmakefile | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/afl_network_proxy/GNUmakefile diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile new file mode 100644 index 00000000..8eb91727 --- /dev/null +++ b/examples/afl_network_proxy/GNUmakefile @@ -0,0 +1,47 @@ +PREFIX ?= /usr/local +BIN_PATH = $(PREFIX)/bin +DOC_PATH = $(PREFIX)/share/doc/afl + +PROGRAMS = afl-network-client afl-network-server + +HASH=\# + +ifdef STATIC + CFLAGS += -static +endif + +ifdef USE_DEFLATE + CFLAGS += -ldeflate -DUSE_DEFLATE=1 + $(info activating libdeflate-dev for compressing) +endif + +# Disables because compression is slower +# sending 64kb instead of compressing to 112bytes is slower? weird ... +#ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" +# CFLAGS += -ldeflate -DUSE_DEFLATE=1 +# $(info libdeflate-dev was detected, using compressing) +#else +# $(warn did not find libdeflate-dev, cannot use compression) +#endif + +all: $(PROGRAMS) + +help: + @echo make options: + echo STATIC - build as static binaries + echo USE_DEFLATE - build with compression library + +afl-network-client: afl-network-client.c + $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c -ldeflate + +afl-network-server: afl-network-server.c + $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" -ldeflate + +clean: + rm -f $(PROGRAMS) *~ core + +install: all + install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH) + install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH) + install -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md + -- cgit 1.4.1 From 13a32e9595c09d14f3c5178e7480a3bb3b6c2587 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 4 May 2020 10:08:29 +0200 Subject: fix makefile --- examples/afl_network_proxy/GNUmakefile | 4 ++-- examples/afl_network_proxy/afl-network-server.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile index 8eb91727..014f4aef 100644 --- a/examples/afl_network_proxy/GNUmakefile +++ b/examples/afl_network_proxy/GNUmakefile @@ -32,10 +32,10 @@ help: echo USE_DEFLATE - build with compression library afl-network-client: afl-network-client.c - $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c -ldeflate + $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c afl-network-server: afl-network-server.c - $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" -ldeflate + $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" clean: rm -f $(PROGRAMS) *~ core diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index e4c3bc6d..ffe37447 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -400,7 +400,7 @@ int recv_testcase(int s, void **buf, size_t *max_len) { // fprintf(stderr, "receiving testcase %p %p max %u\n", buf, *buf, *max_len); if (received != size) - FATAL("did not receive testcase data %u != %u, %d", received, size, ret); + FATAL("did not receive testcase data %lu != %u, %d", received, size, ret); // fprintf(stderr, "received testcase\n"); return size; -- cgit 1.4.1 From 2d126dc750be641efa49e662d5ea9a9e76a6805d Mon Sep 17 00:00:00 2001 From: assafcarlsbad Date: Mon, 4 May 2020 11:14:49 +0300 Subject: Fix Unicorn support build script (#349) * Fix Unicorn support build script for WSL. Co-authored-by: Dominik Maier --- unicorn_mode/build_unicorn_support.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index 0961d6e1..aeb26945 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -209,9 +209,9 @@ cd ../samples/simple || exit 1 # Run afl-showmap on the sample application. If anything comes out then it must have worked! unset AFL_INST_RATIO -echo 0 | ../../../afl-showmap -U -m none -t 2000 -q -o .test-instr0 -- $PYTHONBIN simple_test_harness.py ./sample_inputs/sample1.bin || exit 1 +echo 0 | ../../../afl-showmap -U -m none -t 2000 -q -o ./.test-instr0 -- $PYTHONBIN ./simple_test_harness.py ./sample_inputs/sample1.bin || exit 1 -if [ -s .test-instr0 ] +if [ -s ./.test-instr0 ] then echo "[+] Instrumentation tests passed. " @@ -227,6 +227,6 @@ else fi -rm -f .test-instr0 +rm -f ./.test-instr0 exit $RETVAL -- cgit 1.4.1 From 96ef2d382159b926adc4a21f644d21ef960041c0 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 4 May 2020 10:24:29 +0200 Subject: makefile fix --- examples/afl_network_proxy/GNUmakefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile index 014f4aef..93eee4c1 100644 --- a/examples/afl_network_proxy/GNUmakefile +++ b/examples/afl_network_proxy/GNUmakefile @@ -11,7 +11,8 @@ ifdef STATIC endif ifdef USE_DEFLATE - CFLAGS += -ldeflate -DUSE_DEFLATE=1 + CFLAGS += -DUSE_DEFLATE=1 + LDFLAGS += -ldeflate $(info activating libdeflate-dev for compressing) endif @@ -32,10 +33,10 @@ help: echo USE_DEFLATE - build with compression library afl-network-client: afl-network-client.c - $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c + $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS) afl-network-server: afl-network-server.c - $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" + $(CC) $(CFLAGS) -I../../include -o afl-network-server afl-network-server.c ../../src/afl-forkserver.c ../../src/afl-sharedmem.c ../../src/afl-common.c -DBIN_PATH=\"$(BIN_PATH)\" $(LDFLAGS) clean: rm -f $(PROGRAMS) *~ core -- cgit 1.4.1 From e592b4bcf0f85ff128d684f83d8aa9328ccca39f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 4 May 2020 10:37:45 +0200 Subject: nw fixes --- examples/afl_network_proxy/afl-network-client.c | 28 +++++++++++++------------ examples/afl_network_proxy/afl-network-server.c | 6 +++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c index 94f6bb42..781ea328 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -302,7 +302,7 @@ int main(int argc, char *argv[]) { compressor = libdeflate_alloc_compressor(1); struct libdeflate_decompressor *decompressor; decompressor = libdeflate_alloc_decompressor(); - fprintf(stderr, "Compile with compression support\n"); + fprintf(stderr, "Compiled with compression support\n"); #endif if (s == -1) @@ -321,6 +321,7 @@ int main(int argc, char *argv[]) { // fprintf(stderr, "Sending testcase with len %u\n", *lenptr); #ifdef USE_DEFLATE + #ifdef COMPRESS_TESTCASES // we only compress the testcase if it does not fit in the TCP packet if (*lenptr > 1500 - 20 - 32 - 4) { @@ -330,24 +331,25 @@ int main(int argc, char *argv[]) { buf2 + 8, buf2_len); if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8) PFATAL("sending test data failed"); - fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2); - for (u32 i = 0; i < *lenptr; i++) - fprintf(stderr, "%02x", buf[i + 4]); - fprintf(stderr, "\n"); - for (u32 i = 0; i < *lenptr2; i++) - fprintf(stderr, "%02x", buf2[i + 8]); - fprintf(stderr, "\n"); + //fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2); + //for (u32 i = 0; i < *lenptr; i++) + // fprintf(stderr, "%02x", buf[i + 4]); + //fprintf(stderr, "\n"); + //for (u32 i = 0; i < *lenptr2; i++) + // fprintf(stderr, "%02x", buf2[i + 8]); + //fprintf(stderr, "\n"); } else { - + #endif #endif if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4) PFATAL("sending test data failed"); #ifdef USE_DEFLATE + #ifdef COMPRESS_TESTCASES // fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr); } - + #endif #endif received = 0; @@ -379,9 +381,9 @@ int main(int argc, char *argv[]) { &decompress_len) != LIBDEFLATE_SUCCESS || decompress_len != __afl_map_size) FATAL("decompression failed"); -// fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len); -// for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x", -// __afl_area_ptr[i]); fprintf(stderr, "\n"); + // fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len); + // for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x", + // __afl_area_ptr[i]); fprintf(stderr, "\n"); #else while (received < __afl_map_size && (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received, diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index ffe37447..01501cc9 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -354,7 +354,7 @@ int recv_testcase(int s, void **buf, size_t *max_len) { if (size == 0) FATAL("did not receive valid size information"); // fprintf(stderr, "received size information of %d\n", size); - if ((size && 0xff000000) != 0xff000000) { + if ((size & 0xff000000) != 0xff000000) { *buf = maybe_grow(buf, max_len, size); received = 0; @@ -367,13 +367,13 @@ int recv_testcase(int s, void **buf, size_t *max_len) { #ifdef USE_DEFLATE u32 clen; - size = (size & 0x00ffffff); + size -= 0xff000000; *buf = maybe_grow(buf, max_len, size); received = 0; while (received < 4 && (ret = recv(s, &clen + received, 4 - received, 0)) > 0) received += ret; - if (received != 4) FATAL("did not receive size information"); + if (received != 4) FATAL("did not receive clen1 information"); // fprintf(stderr, "received clen information of %d\n", clen); if (clen < 1) FATAL("did not receive valid compressed len information: %u", clen); -- cgit 1.4.1 From 945e00b73fde56f98235a03472b4af1539983f80 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 4 May 2020 12:51:38 +0200 Subject: final touches for afl_network_proxy --- examples/afl_network_proxy/GNUmakefile | 24 ++++++++---------------- examples/afl_network_proxy/README.md | 11 +++++++---- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile index 93eee4c1..99221d10 100644 --- a/examples/afl_network_proxy/GNUmakefile +++ b/examples/afl_network_proxy/GNUmakefile @@ -10,27 +10,19 @@ ifdef STATIC CFLAGS += -static endif -ifdef USE_DEFLATE - CFLAGS += -DUSE_DEFLATE=1 - LDFLAGS += -ldeflate - $(info activating libdeflate-dev for compressing) +ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" + CFLAGS += -ldeflate -DUSE_DEFLATE=1 + $(info libdeflate-dev was detected, using compressing) +else + $(warn did not find libdeflate-dev, cannot use compression) endif -# Disables because compression is slower -# sending 64kb instead of compressing to 112bytes is slower? weird ... -#ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" -# CFLAGS += -ldeflate -DUSE_DEFLATE=1 -# $(info libdeflate-dev was detected, using compressing) -#else -# $(warn did not find libdeflate-dev, cannot use compression) -#endif - all: $(PROGRAMS) help: @echo make options: - echo STATIC - build as static binaries - echo USE_DEFLATE - build with compression library + @echo STATIC - build as static binaries + @echo COMPRESS_TESTCASES - compress test cases afl-network-client: afl-network-client.c $(CC) $(CFLAGS) -I../../include -o afl-network-client afl-network-client.c $(LDFLAGS) @@ -44,5 +36,5 @@ clean: install: all install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(DOC_PATH) install -m 755 $(PROGRAMS) $${DESTDIR}$(BIN_PATH) - install -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md + install -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md diff --git a/examples/afl_network_proxy/README.md b/examples/afl_network_proxy/README.md index 84ebfa48..255be0d8 100644 --- a/examples/afl_network_proxy/README.md +++ b/examples/afl_network_proxy/README.md @@ -16,9 +16,12 @@ Note that the impact on fuzzing speed will be huge, expect a loss of 90%. Just type `make` and let the autodetection do everything for you. -Note that compression is supported but currently disabled. It seems that -sending 64kb of map data over TCP is faster than compressing it with the -fastest algorithm and options to 112 byte and sending this. Weird. +Note that you will get a 40-50% performance increase if you have libdeflate-dev +installed. The GNUmakefile will autodetect it if present. + +If your target has large test cases (10+kb) that are ascii only or large chunks +of zero blocks then set `CFLAGS=-DCOMPRESS_TESTCASES=1` to compress them. +For most targets this hurts performance though so it is disabled by default. ### on the target @@ -29,7 +32,7 @@ e.g.: $ afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@ ``` -### on the fuzzing master +### on the (afl-fuzz) master Just run afl-fuzz with your normal options, however the target should be `afl-network-client` with the IP and PORT of the `afl-network-server` and -- cgit 1.4.1 From 16c16b3e6e0cd678f5da76f757761fb821f1011f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 4 May 2020 18:01:47 +0200 Subject: ctx and ngram can be used together now --- docs/Changelog.md | 1 + docs/env_variables.md | 6 +- examples/afl_network_proxy/afl-network-client.c | 26 +-- llvm_mode/afl-clang-fast.c | 202 +++++++++++++++--------- llvm_mode/afl-llvm-pass.so.cc | 15 +- 5 files changed, 150 insertions(+), 100 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index cae99681..8c0624b6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ 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 + - CTX and NGRAM can now be used together - 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. diff --git a/docs/env_variables.md b/docs/env_variables.md index bdbb8520..ab5808ec 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -97,12 +97,14 @@ Then there are a few specific features that are only available in llvm_mode: - AFL_LLVM_INSTRUMENT - this configures the instrumentation mode. Available options: - DEFAULT - classic AFL (map[cur_loc ^ prev_loc >> 1]++) + CLASSIC - classic AFL (map[cur_loc ^ prev_loc >> 1]++) (default) CFG - InsTrim instrumentation (see below) LTO - LTO instrumentation (see below) CTX - context sensitive instrumentation (see below) NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) - Only one can be used. + In CLASSIC (default) can can also specify CTX and/nor NGRAM, seperate + the options with a comma "," then, e.g.: + AFL_LLVM_INSTRUMENT=CLASSIC,CTX,NGRAM-4 ### LTO diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c index 781ea328..cf09b2ad 100644 --- a/examples/afl_network_proxy/afl-network-client.c +++ b/examples/afl_network_proxy/afl-network-client.c @@ -321,7 +321,7 @@ int main(int argc, char *argv[]) { // fprintf(stderr, "Sending testcase with len %u\n", *lenptr); #ifdef USE_DEFLATE - #ifdef COMPRESS_TESTCASES +#ifdef COMPRESS_TESTCASES // we only compress the testcase if it does not fit in the TCP packet if (*lenptr > 1500 - 20 - 32 - 4) { @@ -331,25 +331,27 @@ int main(int argc, char *argv[]) { buf2 + 8, buf2_len); if (send(s, buf2, *lenptr2 + 8, 0) != *lenptr2 + 8) PFATAL("sending test data failed"); - //fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2); - //for (u32 i = 0; i < *lenptr; i++) + // fprintf(stderr, "COMPRESS (%u->%u):\n", *lenptr, *lenptr2); + // for (u32 i = 0; i < *lenptr; i++) // fprintf(stderr, "%02x", buf[i + 4]); - //fprintf(stderr, "\n"); - //for (u32 i = 0; i < *lenptr2; i++) + // fprintf(stderr, "\n"); + // for (u32 i = 0; i < *lenptr2; i++) // fprintf(stderr, "%02x", buf2[i + 8]); - //fprintf(stderr, "\n"); + // fprintf(stderr, "\n"); } else { - #endif + +#endif #endif if (send(s, buf, *lenptr + 4, 0) != *lenptr + 4) PFATAL("sending test data failed"); #ifdef USE_DEFLATE - #ifdef COMPRESS_TESTCASES +#ifdef COMPRESS_TESTCASES // fprintf(stderr, "unCOMPRESS (%u)\n", *lenptr); } - #endif + +#endif #endif received = 0; @@ -381,9 +383,9 @@ int main(int argc, char *argv[]) { &decompress_len) != LIBDEFLATE_SUCCESS || decompress_len != __afl_map_size) FATAL("decompression failed"); - // fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len); - // for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x", - // __afl_area_ptr[i]); fprintf(stderr, "\n"); + // fprintf(stderr, "DECOMPRESS (%u->%u): ", compress_len, decompress_len); + // for (u32 i = 0; i < __afl_map_size; i++) fprintf(stderr, "%02x", + // __afl_area_ptr[i]); fprintf(stderr, "\n"); #else while (received < __afl_map_size && (ret = recv(s, __afl_area_ptr + received, __afl_map_size - received, diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index c59b814d..9f85e5c6 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -43,7 +43,7 @@ static u8 * obj_path; /* Path to runtime libraries */ static u8 **cc_params; /* Parameters passed to the real CC */ static u32 cc_par_cnt = 1; /* Param count, including argv0 */ static u8 llvm_fullpath[PATH_MAX]; -static u8 instrument_mode; +static u8 instrument_mode, instrument_opt_mode, ngram_size; static u8 * lto_flag = AFL_CLANG_FLTO; static u8 * march_opt = CFLAGS_OPT; static u8 debug; @@ -60,14 +60,15 @@ enum { INSTRUMENT_INSTRIM = 2, INSTRUMENT_CFG = 2, INSTRUMENT_LTO = 3, - INSTRUMENT_CTX = 4, - INSTRUMENT_NGRAM = 5 // + ngram value of 2-16 = 7 - 21 + INSTRUMENT_OPT_CTX = 4, + INSTRUMENT_OPT_NGRAM = 8 }; -char instrument_mode_string[6][16] = { +char instrument_mode_string[10][16] = { - "DEFAULT", "PCGUARD", "CFG", "LTO", "CTX", + "CLASSIC", "PCGUARD", "CFG", "LTO", "CTX", "", + "", "", "NGRAM", "" }; @@ -562,59 +563,6 @@ 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 || - strncasecmp(ptr, "afl", strlen("afl")) == 0 || - strncasecmp(ptr, "classic", strlen("classic")) == 0) - instrument_mode = INSTRUMENT_DEFAULT; - if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || - strncasecmp(ptr, "instrim", strlen("instrim")) == 0) - instrument_mode = INSTRUMENT_CFG; - else if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 || - strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0) - instrument_mode = INSTRUMENT_PCGUARD; - else if (strncasecmp(ptr, "lto", strlen("lto")) == 0) - instrument_mode = INSTRUMENT_LTO; - else if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) { - - instrument_mode = INSTRUMENT_CTX; - setenv("AFL_LLVM_CTX", "1", 1); - - } else if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) { - - ptr += strlen("ngram"); - while (*ptr && (*ptr < '0' || *ptr > '9')) - ptr++; - if (!*ptr) - if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL) - FATAL( - "you must set the NGRAM size with (e.g. for value 2) " - "AFL_LLVM_INSTRUMENT=ngram-2"); - instrument_mode = INSTRUMENT_NGRAM + atoi(ptr); - if (instrument_mode < INSTRUMENT_NGRAM + 2 || - instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX) - FATAL( - "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX " - "(%u)", - NGRAM_SIZE_MAX); - - ptr = alloc_printf("%u", instrument_mode - INSTRUMENT_NGRAM); - setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1); - - } else if (strncasecmp(ptr, "classic", strlen("classic")) != 0 || - - strncasecmp(ptr, "default", strlen("default")) != 0 || - strncasecmp(ptr, "afl", strlen("afl")) != 0) - FATAL("unknown AFL_LLVM_INSTRUMENT value: %s", ptr); - - } - if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") || getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) { @@ -636,39 +584,116 @@ int main(int argc, char **argv, char **envp) { } - if (getenv("AFL_LLVM_CTX")) { + if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX; - if (instrument_mode == 0) - instrument_mode = INSTRUMENT_CTX; - else if (instrument_mode != INSTRUMENT_CTX) - FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_CTX together"); + if (getenv("AFL_LLVM_NGRAM_SIZE")) { + + instrument_opt_mode |= INSTRUMENT_OPT_NGRAM; + ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE")); + if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) + FATAL( + "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX " + "(%u)", + NGRAM_SIZE_MAX); } - if (getenv("AFL_LLVM_NGRAM_SIZE")) { + if (getenv("AFL_LLVM_INSTRUMENT")) { - if (instrument_mode == 0) { + u8 *ptr = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;"); - instrument_mode = INSTRUMENT_NGRAM + atoi(getenv("AFL_LLVM_NGRAM_SIZE")); - if (instrument_mode < INSTRUMENT_NGRAM + 2 || - instrument_mode > INSTRUMENT_NGRAM + NGRAM_SIZE_MAX) - FATAL( - "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX " - "(%u)", - NGRAM_SIZE_MAX); + while (ptr) { - } else if (instrument_mode != INSTRUMENT_NGRAM) + if (strncasecmp(ptr, "default", strlen("default")) == 0 || + strncasecmp(ptr, "afl", strlen("afl")) == 0 || + strncasecmp(ptr, "classic", strlen("classic")) == 0) { - FATAL( - "you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_NGRAM_SIZE " - "together"); + if (!instrument_mode || instrument_mode == INSTRUMENT_DEFAULT) + instrument_mode = INSTRUMENT_DEFAULT; + else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 || + strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0) { + + if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD) + instrument_mode = INSTRUMENT_PCGUARD; + else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || + strncasecmp(ptr, "instrim", strlen("instrim")) == 0) { + + if (!instrument_mode || instrument_mode == INSTRUMENT_CFG) + instrument_mode = INSTRUMENT_CFG; + else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "lto", strlen("lto")) == 0) { + + if (!instrument_mode || instrument_mode == INSTRUMENT_LTO) + instrument_mode = INSTRUMENT_LTO; + else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + + if (strncasecmp(ptr, "ctx", strlen("ctx")) == 0) { + + instrument_opt_mode |= INSTRUMENT_OPT_CTX; + setenv("AFL_LLVM_CTX", "1", 1); + + } + + if (strncasecmp(ptr, "ngram", strlen("ngram")) == 0) { + + ptr += strlen("ngram"); + while (*ptr && (*ptr < '0' || *ptr > '9')) + ptr++; + if (!*ptr) + if ((ptr = getenv("AFL_LLVM_NGRAM_SIZE")) != NULL) + FATAL( + "you must set the NGRAM size with (e.g. for value 2) " + "AFL_LLVM_INSTRUMENT=ngram-2"); + ngram_size = atoi(ptr); + if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX) + FATAL( + "NGRAM instrumentation option must be between 2 and " + "NGRAM_SIZE_MAX " + "(%u)", + NGRAM_SIZE_MAX); + instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM); + ptr = alloc_printf("%u", ngram_size); + setenv("AFL_LLVM_NGRAM_SIZE", ptr, 1); + + } + + ptr = strtok(NULL, ":,;"); + + } } - if (instrument_mode < INSTRUMENT_NGRAM) + if (!instrument_opt_mode) ptr = instrument_mode_string[instrument_mode]; + else if (instrument_opt_mode == INSTRUMENT_OPT_CTX) + ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]); + else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM) + ptr = alloc_printf("%s + NGRAM-%u", instrument_mode_string[instrument_mode], + ngram_size); else - ptr = alloc_printf("NGRAM-%u", instrument_mode - INSTRUMENT_NGRAM); + ptr = alloc_printf("%s + CTX + NGRAM-%u", + instrument_mode_string[instrument_mode], ngram_size); if (strstr(argv[0], "afl-clang-lto") != NULL) { @@ -690,9 +715,28 @@ int main(int argc, char **argv, char **envp) { #ifndef AFL_CLANG_FLTO if (instrument_mode == INSTRUMENT_LTO) - FATAL("instrumentation mode LTO specified but LLVM support not available"); + FATAL( + "instrumentation mode LTO specified but LLVM support not available " + "(requires LLVM 11)"); #endif + if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) + /*&& instrument_mode != INSTRUMENT_CFG*/ + FATAL( + "CTX and NGRAM instrumentation options can only be used with the " + "CLASSIC instrumentation mode!"); + + 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 (instrument_mode == INSTRUMENT_CFG && + getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") == NULL && ngram_size) + FATAL( + "NGRAM option together with CFG/INSTRIM instrumentation mode can only " + "be used if AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK is set"); + if (argc < 2 || strcmp(argv[1], "-h") == 0) { if (instrument_mode != INSTRUMENT_LTO) diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 3e9026c8..42a2f3af 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -182,7 +182,7 @@ bool AFLCoverage::runOnModule(Module &M) { #endif skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); - unsigned PrevLocSize; + unsigned PrevLocSize = 0; char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE"); @@ -216,9 +216,6 @@ bool AFLCoverage::runOnModule(Module &M) { if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize); #endif - if (ctx_str && ngram_size_str) - FATAL("you must decide between NGRAM and CTX instrumentation"); - /* Get globals for the SHM region and the previous location. Note that __afl_prev_loc is thread-local. */ @@ -437,8 +434,10 @@ bool AFLCoverage::runOnModule(Module &M) { PrevLocTrans = IRB.CreateXorReduce(PrevLoc); else #endif - if (ctx_str) - PrevLocTrans = IRB.CreateZExt(IRB.CreateXor(PrevLoc, PrevCtx), Int32Ty); + PrevLocTrans = PrevLoc; + if (ctx_str) + PrevLocTrans = + IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty); else PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); @@ -452,7 +451,9 @@ bool AFLCoverage::runOnModule(Module &M) { if (ngram_size) MapPtrIdx = IRB.CreateGEP( MapPtr, - IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, CurLoc), Int32Ty)); + IRB.CreateZExt( + IRB.CreateXor(PrevLocTrans, IRB.CreateZExt(CurLoc, Int32Ty)), + Int32Ty)); else #endif MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, CurLoc)); -- cgit 1.4.1 From 95a2d4923244473b59e2b1a6012ad2e186d3b2a4 Mon Sep 17 00:00:00 2001 From: David Mendenhall Date: Mon, 4 May 2020 11:30:06 -0700 Subject: Fix typo in README.lto.md --- llvm_mode/README.lto.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index bb66b5e7..d8e4766d 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -65,7 +65,7 @@ $ cd build $ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/ $ make -j $(nproc) $ export PATH=`pwd`/bin:$PATH -$ export LLVM_CONFIG=`pwd`/bin/llcm-config +$ export LLVM_CONFIG=`pwd`/bin/llvm-config $ cd /path/to/AFLplusplus/ $ make $ cd llvm_mode -- cgit 1.4.1 From 6e45e55d82eeed2075579a530f5aeea8d00af55b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 10:38:44 +0200 Subject: fix crash in AFL_LLVM_LAF_TRANSFORM_COMPARES --- docs/Changelog.md | 1 + llvm_mode/afl-llvm-rt.o.c | 15 ++++++--------- llvm_mode/compare-transform-pass.so.cc | 12 ++++++++---- test/test.sh | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 8c0624b6..ac68e8ff 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -21,6 +21,7 @@ sending a mail to . fuzzing speed - fixes to LTO mode if instrumented edges > MAP_SIZE - CTX and NGRAM can now be used together + - AFL_LLVM_LAF_TRANSFORM_COMPARES would sometimes crash, fixed - 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. diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 722ca421..56038f7a 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -67,22 +67,19 @@ u8 __afl_area_initial[MAP_SIZE]; u8 *__afl_area_ptr = __afl_area_initial; u8 *__afl_dictionary; +u32 __afl_final_loc; +u32 __afl_map_size = MAP_SIZE; +u32 __afl_dictionary_len; +u64 __afl_map_addr; + #ifdef __ANDROID__ PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; -u32 __afl_final_loc; u32 __afl_prev_ctx; u32 __afl_cmp_counter; -u32 __afl_dictionary_len; -u32 __afl_map_size = MAP_SIZE; -u64 __afl_map_addr; #else __thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; -__thread u32 __afl_final_loc; __thread u32 __afl_prev_ctx; __thread u32 __afl_cmp_counter; -__thread u32 __afl_dictionary_len; -__thread u32 __afl_map_size = MAP_SIZE; -__thread u64 __afl_map_addr; #endif struct cmp_map *__afl_cmp_map; @@ -152,7 +149,7 @@ static void __afl_map_shm(void) { if (getenv("AFL_DEBUG")) fprintf(stderr, - "DEBUG: id_str %s, __afl_map_addr 0x%lx, MAP_SIZE %u, " + "DEBUG: id_str %s, __afl_map_addr 0x%llx, MAP_SIZE %u, " "__afl_final_loc %u, max_size_forkserver %u/0x%x\n", id_str == NULL ? "" : id_str, __afl_map_addr, MAP_SIZE, __afl_final_loc, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE); diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index c871c1c4..9cf4169e 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -386,13 +386,13 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, TmpConstStr = Str1.str(); VarStr = Str2P; - constLen = isMemcmp ? sizedLen : GetStringLength(Str1P); + constLen = isMemcmp ? sizedLen : TmpConstStr.length(); } else { TmpConstStr = Str2.str(); VarStr = Str1P; - constLen = isMemcmp ? sizedLen : GetStringLength(Str2P); + constLen = isMemcmp ? sizedLen : TmpConstStr.length(); } @@ -401,8 +401,12 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, * runtime bounds checking, which makes debugging easier) */ TmpConstStr.append("\0", 1); ConstStr = StringRef(TmpConstStr); - - if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; } + // fprintf(stderr, "issized: %d, const > sized ? %u > %u\n", isSizedcmp, + // constLen, sizedLen); + if (isSizedcmp && constLen > sizedLen && sizedLen) constLen = sizedLen; + if (constLen > TmpConstStr.length()) constLen = TmpConstStr.length(); + if (!constLen) constLen = TmpConstStr.length(); + if (!constLen) continue; if (!be_quiet) errs() << callInst->getCalledFunction()->getName() << ": len " << constLen diff --git a/test/test.sh b/test/test.sh index e950e3de..90633a9f 100755 --- a/test/test.sh +++ b/test/test.sh @@ -81,7 +81,7 @@ test `uname -s` = 'Darwin' -o `uname -s` = 'FreeBSD' && { } || { AFL_GCC=afl-gcc } -command -v gcc || AFL_GCC=afl-clang +command -v gcc >/dev/null 2>&1 || AFL_GCC=afl-clang SYS=`uname -m` -- cgit 1.4.1 From 9d384b4e383e2b216847e2ed3aee432a25cd37d8 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 12:46:49 +0200 Subject: ctx and ngram fix --- llvm_mode/afl-llvm-pass.so.cc | 128 +++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 53 deletions(-) diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 42a2f3af..c0391b04 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -294,70 +294,52 @@ bool AFLCoverage::runOnModule(Module &M) { if (!isInWhitelist(&F)) continue; - if (ctx_str && F.size() > 1) { // Context sensitive coverage - // load the context ID of the previous function and write to to a local - // variable on the stack - auto bb = &F.getEntryBlock(); - BasicBlock::iterator IP = bb->getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - PrevCtx = IRB.CreateLoad(AFLContext); - PrevCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - - // does the function have calls? and is any of the calls larger than one - // basic block? - has_calls = 0; - for (auto &BB : F) { - - if (has_calls) break; - for (auto &IN : BB) { - - CallInst *callInst = nullptr; - if ((callInst = dyn_cast(&IN))) { - - Function *Callee = callInst->getCalledFunction(); - if (!Callee || Callee->size() < 2) - continue; - else { + for (auto &BB : F) { - has_calls = 1; - break; + BasicBlock::iterator IP = BB.getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); - } + // Context sensitive coverage + if (ctx_str && &BB == &F.getEntryBlock() && F.size() > 1) { - } + // load the context ID of the previous function and write to to a local + // variable on the stack + PrevCtx = IRB.CreateLoad(AFLContext); + PrevCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - } + // does the function have calls? and is any of the calls larger than one + // basic block? + for (auto &BB : F) { - } + if (has_calls) break; + for (auto &IN : BB) { - // if yes we store a context ID for this function in the global var - if (has_calls) { + CallInst *callInst = nullptr; + if ((callInst = dyn_cast(&IN))) { - ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size)); - StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); - StoreCtx->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); + Function *Callee = callInst->getCalledFunction(); + if (!Callee || Callee->size() < 2) + continue; + else { - } + has_calls = 1; + break; - } + } - for (auto &BB : F) { + } - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); + } - // in CTX mode we have to restore the original context for the caller - - // she might be calling other functions which need the correct CTX - if (ctx_str && has_calls) { + } - Instruction *Inst = BB.getTerminator(); - if (isa(Inst) || isa(Inst)) { + // if yes we store a context ID for this function in the global var + if (has_calls) { - IRBuilder<> Post_IRB(Inst); - StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext); - RestoreCtx->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); + ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size)); + StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); + StoreCtx->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); } @@ -407,7 +389,28 @@ bool AFLCoverage::runOnModule(Module &M) { } // fprintf(stderr, " == %d\n", more_than_one); - if (more_than_one != 1) continue; + if (more_than_one != 1) { + + // in CTX mode we have to restore the original context for the caller - + // she might be calling other functions which need the correct CTX + if (ctx_str && has_calls && F.size() > 1) { + + Instruction *Inst = BB.getTerminator(); + if (isa(Inst) || isa(Inst)) { + + IRBuilder<> Post_IRB(Inst); + StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext); + RestoreCtx->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + } + + continue; + + } + #endif ConstantInt *CurLoc; @@ -431,15 +434,17 @@ bool AFLCoverage::runOnModule(Module &M) { prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */ if (ngram_size) - PrevLocTrans = IRB.CreateXorReduce(PrevLoc); + PrevLocTrans = + IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty()); else #endif PrevLocTrans = PrevLoc; + if (ctx_str) PrevLocTrans = IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty); else - PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); + PrevLocTrans = IRB.CreateZExt(PrevLocTrans, IRB.getInt32Ty()); /* Load SHM pointer */ @@ -518,6 +523,23 @@ bool AFLCoverage::runOnModule(Module &M) { } + // in CTX mode we have to restore the original context for the caller - + // she might be calling other functions which need the correct CTX. + // Currently this is only needed for the Ubuntu clang-6.0 bug + if (ctx_str && has_calls && F.size() > 1) { + + Instruction *Inst = BB.getTerminator(); + if (isa(Inst) || isa(Inst)) { + + IRBuilder<> Post_IRB(Inst); + StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext); + RestoreCtx->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + } + inst_blocks++; } -- cgit 1.4.1 From d82ada89fee37068b0ff44f340338af3fc07cc37 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 14:08:24 +0200 Subject: support older llvm versions --- llvm_mode/compare-transform-pass.so.cc | 42 ++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index 9cf4169e..10413076 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -211,20 +211,24 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } // not literal? maybe global or local variable - if (!(HasStr1 ^ HasStr2)) { + if (!(HasStr1 || HasStr2)) { auto *Ptr = dyn_cast(Str2P); if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { if (auto *Var = dyn_cast(Ptr->getOperand(0))) { - if (auto *Array = - dyn_cast(Var->getInitializer())) { + if (Var->hasInitializer()) { - HasStr2 = true; - Str2 = Array->getAsString(); - valueMap[Str2P] = new std::string(Str2.str()); - // fprintf(stderr, "glo2 %s\n", Str2.str().c_str()); + if (auto *Array = + dyn_cast(Var->getInitializer())) { + + HasStr2 = true; + Str2 = Array->getAsString(); + valueMap[Str2P] = new std::string(Str2.str()); + fprintf(stderr, "glo2 %s\n", Str2.str().c_str()); + + } } @@ -239,13 +243,17 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, if (auto *Var = dyn_cast(Ptr->getOperand(0))) { - if (auto *Array = - dyn_cast(Var->getInitializer())) { + if (Var->hasInitializer()) { + + if (auto *Array = dyn_cast( + Var->getInitializer())) { + + HasStr1 = true; + Str1 = Array->getAsString(); + valueMap[Str1P] = new std::string(Str1.str()); + // fprintf(stderr, "glo1 %s\n", Str1.str().c_str()); - HasStr1 = true; - Str1 = Array->getAsString(); - valueMap[Str1P] = new std::string(Str1.str()); - // fprintf(stderr, "glo1 %s\n", Str1.str().c_str()); + } } @@ -260,13 +268,13 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } - if ((HasStr1 ^ HasStr2)) indirect = true; + if ((HasStr1 || HasStr2)) indirect = true; } if (isIntMemcpy) continue; - if (!(HasStr1 ^ HasStr2)) { + if (!(HasStr1 || HasStr2)) { // do we have a saved local variable initialization? std::string *val = valueMap[Str1P]; @@ -294,7 +302,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } /* handle cases of one string is const, one string is variable */ - if (!(HasStr1 ^ HasStr2)) continue; + if (!(HasStr1 || HasStr2)) continue; if (isMemcmp || isStrncmp || isStrncasecmp) { @@ -359,7 +367,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } - if (!(HasStr1 ^ HasStr2)) { + if (!(HasStr1 || HasStr2)) { // do we have a saved local or global variable initialization? std::string *val = valueMap[Str1P]; -- cgit 1.4.1 From d6346561dbe2a00472eda76e8a1276b77e0f67a7 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 15:37:02 +0200 Subject: ctx+ngram for instrim --- docs/Changelog.md | 3 +- llvm_mode/LLVMInsTrim.so.cc | 262 ++++++++++++++++++++++++++++++++++++++------ llvm_mode/afl-clang-fast.c | 14 +-- 3 files changed, 233 insertions(+), 46 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index ac68e8ff..e4ac8783 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -21,7 +21,8 @@ sending a mail to . fuzzing speed - fixes to LTO mode if instrumented edges > MAP_SIZE - CTX and NGRAM can now be used together - - AFL_LLVM_LAF_TRANSFORM_COMPARES would sometimes crash, fixed + - CTX and NGRAM are now also supported in CFG/INSTRIM mode + - AFL_LLVM_LAF_TRANSFORM_COMPARES could, fixed - 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. diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index c78250eb..ad046a8b 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -36,11 +36,12 @@ typedef long double max_align_t; #include #include -#include "config.h" -#include "debug.h" - #include "MarkNodes.h" #include "afl-llvm-common.h" +#include "llvm-ngram-coverage.h" + +#include "config.h" +#include "debug.h" using namespace llvm; @@ -94,9 +95,15 @@ struct InsTrim : public ModulePass { } +#if LLVM_VERSION_MAJOR >= 4 || \ + (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1) +#define AFL_HAVE_VECTOR_INTRINSICS 1 +#endif + bool runOnModule(Module &M) override { char be_quiet = 0; + int ngram_size = 0; if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) { @@ -108,6 +115,11 @@ struct InsTrim : public ModulePass { if (getenv("AFL_DEBUG") != NULL) debug = 1; + LLVMContext &C = M.getContext(); + + IntegerType *Int8Ty = IntegerType::getInt8Ty(C); + IntegerType *Int32Ty = IntegerType::getInt32Ty(C); + #if LLVM_VERSION_MAJOR < 9 char *neverZero_counters_str; if ((neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO")) != NULL) @@ -125,24 +137,107 @@ struct InsTrim : public ModulePass { if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL) function_minimum_size = 2; - // this is our default - MarkSetOpt = true; + unsigned PrevLocSize = 0; + char * ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); + if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE"); + char *ctx_str = getenv("AFL_LLVM_CTX"); + +#ifdef AFL_HAVE_VECTOR_INTRINSICS + /* Decide previous location vector size (must be a power of two) */ + VectorType *PrevLocTy; + + if (ngram_size_str) + if (sscanf(ngram_size_str, "%u", &ngram_size) != 1 || ngram_size < 2 || + ngram_size > NGRAM_SIZE_MAX) + FATAL( + "Bad value of AFL_NGRAM_SIZE (must be between 2 and NGRAM_SIZE_MAX " + "(%u))", + NGRAM_SIZE_MAX); + + if (ngram_size) + PrevLocSize = ngram_size - 1; + else +#else + if (ngram_size_str) + FATAL( + "Sorry, NGRAM branch coverage is not supported with llvm version %s!", + LLVM_VERSION_STRING); +#endif + PrevLocSize = 1; + +#ifdef AFL_HAVE_VECTOR_INTRINSICS + // IntegerType *Int64Ty = IntegerType::getInt64Ty(C); + uint64_t PrevLocVecSize = PowerOf2Ceil(PrevLocSize); + IntegerType *IntLocTy = + IntegerType::getIntNTy(C, sizeof(PREV_LOC_T) * CHAR_BIT); + if (ngram_size) PrevLocTy = VectorType::get(IntLocTy, PrevLocVecSize); +#endif - LLVMContext &C = M.getContext(); - IntegerType *Int8Ty = IntegerType::getInt8Ty(C); - IntegerType *Int32Ty = IntegerType::getInt32Ty(C); + /* Get globals for the SHM region and the previous location. Note that + __afl_prev_loc is thread-local. */ - GlobalVariable *CovMapPtr = new GlobalVariable( - M, PointerType::getUnqual(Int8Ty), false, GlobalValue::ExternalLinkage, - nullptr, "__afl_area_ptr"); + GlobalVariable *AFLMapPtr = + new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, + GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); + GlobalVariable *AFLPrevLoc; + GlobalVariable *AFLContext; + LoadInst * PrevCtx = NULL; // for CTX sensitive coverage - GlobalVariable *OldPrev = new GlobalVariable( + if (ctx_str) +#ifdef __ANDROID__ + AFLContext = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); +#else + AFLContext = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx", + 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); +#endif + +#ifdef AFL_HAVE_VECTOR_INTRINSICS + if (ngram_size) +#ifdef __ANDROID__ + AFLPrevLoc = new GlobalVariable( + M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, + /* Initializer */ nullptr, "__afl_prev_loc"); +#else + AFLPrevLoc = new GlobalVariable( + M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, + /* Initializer */ nullptr, "__afl_prev_loc", + /* InsertBefore */ nullptr, GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 0, /* IsExternallyInitialized */ false); +#endif + else +#endif +#ifdef __ANDROID__ + AFLPrevLoc = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); +#else + AFLPrevLoc = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); +#endif + +#ifdef AFL_HAVE_VECTOR_INTRINSICS + /* Create the vector shuffle mask for updating the previous block history. + Note that the first element of the vector will store cur_loc, so just set + it to undef to allow the optimizer to do its thing. */ + + SmallVector PrevLocShuffle = {UndefValue::get(Int32Ty)}; + + for (unsigned I = 0; I < PrevLocSize - 1; ++I) + PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, I)); + + for (unsigned I = PrevLocSize; I < PrevLocVecSize; ++I) + PrevLocShuffle.push_back(ConstantInt::get(Int32Ty, PrevLocSize)); + + Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle); +#endif + + // this is our default + MarkSetOpt = true; ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); ConstantInt *One = ConstantInt::get(Int8Ty, 1); - ConstantInt *One32 = ConstantInt::get(Int32Ty, 1); u64 total_rs = 0; u64 total_hs = 0; @@ -240,13 +335,30 @@ struct InsTrim : public ModulePass { } - if (function_minimum_size < 2) { + for (BasicBlock &BB : F) { + + if (MS.find(&BB) == MS.end()) { continue; } + IRBuilder<> IRB(&*BB.getFirstInsertionPt()); + + if (ngram_size) { + + LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc); + PrevLoc->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); - for (BasicBlock &BB : F) { + Value *ShuffledPrevLoc = IRB.CreateShuffleVector( + PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask); + Value *UpdatedPrevLoc = IRB.CreateInsertElement( + ShuffledPrevLoc, ConstantInt::get(Int32Ty, genLabel()), + (uint64_t)0); - if (MS.find(&BB) == MS.end()) { continue; } - IRBuilder<> IRB(&*BB.getFirstInsertionPt()); - IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), OldPrev); + IRB.CreateStore(UpdatedPrevLoc, AFLPrevLoc) + ->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } else { + + IRB.CreateStore(ConstantInt::get(Int32Ty, genLabel()), AFLPrevLoc); } @@ -254,18 +366,67 @@ struct InsTrim : public ModulePass { } + int has_calls = 0; for (BasicBlock &BB : F) { - if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; } + auto PI = pred_begin(&BB); + auto PE = pred_end(&BB); + IRBuilder<> IRB(&*BB.getFirstInsertionPt()); + Value * L = NULL; + unsigned int cur_loc; + + // Context sensitive coverage + if (ctx_str && &BB == &F.getEntryBlock()) { + + PrevCtx = IRB.CreateLoad(AFLContext); + PrevCtx->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + // does the function have calls? and is any of the calls larger than + // one basic block? + has_calls = 0; + for (auto &BB : F) { + + if (has_calls) break; + for (auto &IN : BB) { + + CallInst *callInst = nullptr; + if ((callInst = dyn_cast(&IN))) { + + Function *Callee = callInst->getCalledFunction(); + if (!Callee || Callee->size() < 2) + continue; + else { + + has_calls = 1; + break; + + } + + } - auto PI = pred_begin(&BB); - auto PE = pred_end(&BB); - IRBuilder<> IRB(&*BB.getFirstInsertionPt()); - Value * L = NULL; + } + + } + + // if yes we store a context ID for this function in the global var + if (has_calls) { + + ConstantInt *NewCtx = ConstantInt::get(Int32Ty, genLabel()); + StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); + StoreCtx->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + } // END of ctx_str + + if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; } - if (function_minimum_size < 2 && PI == PE) { + if (PI == PE) { - L = ConstantInt::get(Int32Ty, genLabel()); + cur_loc = genLabel(); + L = ConstantInt::get(Int32Ty, cur_loc); } else { @@ -276,6 +437,7 @@ struct InsTrim : public ModulePass { BasicBlock *PBB = *PI; auto It = PredMap.insert({PBB, genLabel()}); unsigned Label = It.first->second; + cur_loc = Label; PN->addIncoming(ConstantInt::get(Int32Ty, Label), PBB); } @@ -285,15 +447,37 @@ struct InsTrim : public ModulePass { } /* Load prev_loc */ - LoadInst *PrevLoc = IRB.CreateLoad(OldPrev); + LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc); PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *PrevLocCasted = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); + Value *PrevLocTrans; + +#ifdef AFL_HAVE_VECTOR_INTRINSICS + /* "For efficiency, we propose to hash the tuple as a key into the + hit_count map as (prev_block_trans << 1) ^ curr_block_trans, where + prev_block_trans = (block_trans_1 ^ ... ^ block_trans_(n-1)" */ + + if (ngram_size) + PrevLocTrans = + IRB.CreateZExt(IRB.CreateXorReduce(PrevLoc), IRB.getInt32Ty()); + else +#endif + PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); + + if (ctx_str) + PrevLocTrans = + IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty); /* Load SHM pointer */ - LoadInst *MapPtr = IRB.CreateLoad(CovMapPtr); + LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr); MapPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *MapPtrIdx = - IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocCasted, L)); + Value *MapPtrIdx; +#ifdef AFL_HAVE_VECTOR_INTRINSICS + if (ngram_size) + MapPtrIdx = IRB.CreateGEP( + MapPtr, IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, L), Int32Ty)); + else +#endif + MapPtrIdx = IRB.CreateGEP(MapPtr, IRB.CreateXor(PrevLocTrans, L)); /* Update bitmap */ LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); @@ -329,12 +513,20 @@ struct InsTrim : public ModulePass { IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - // save the actually location ID to OldPrev if function_minimum_size > 1 - if (function_minimum_size > 1) { + if (ctx_str && has_calls) { + + // in CTX mode we have to restore the original context for the + // caller - she might be calling other functions which need the + // correct CTX + Instruction *Inst = BB.getTerminator(); + if (isa(Inst) || isa(Inst)) { - Value *Shr = IRB.CreateLShr(L, One32); - IRB.CreateStore(Shr, OldPrev) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + IRBuilder<> Post_IRB(Inst); + StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext); + RestoreCtx->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } } diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 9f85e5c6..4b9999a6 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -720,23 +720,17 @@ int main(int argc, char **argv, char **envp) { "(requires LLVM 11)"); #endif - if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) - /*&& instrument_mode != INSTRUMENT_CFG*/ + if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC && + instrument_mode != INSTRUMENT_CFG) FATAL( - "CTX and NGRAM instrumentation options can only be used with the " - "CLASSIC instrumentation mode!"); + "CTX and NGRAM instrumentation options can only be used with CFG " + "(recommended) and CLASSIC instrumentation modes!"); 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 (instrument_mode == INSTRUMENT_CFG && - getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") == NULL && ngram_size) - FATAL( - "NGRAM option together with CFG/INSTRIM instrumentation mode can only " - "be used if AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK is set"); - if (argc < 2 || strcmp(argv[1], "-h") == 0) { if (instrument_mode != INSTRUMENT_LTO) -- cgit 1.4.1 From 664a180d72a29ac1abfc41022cdb0808b812e696 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 15:39:15 +0200 Subject: cleanup todo list --- TODO.md | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO.md b/TODO.md index 12614f05..f326b6c7 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,6 @@ ## Roadmap 2.65+ - - implement ngram and ctx in InsTrim - AFL_MAP_SIZE for afl-llvm-pass, qemu_mode and unicorn_mode - random crc32 HASH_CONST per run? because with 65536 paths we have collisions - namespace for targets? e.g. network -- cgit 1.4.1 From a38980c80babbb75038766c49774effc0bfa8222 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 17:57:56 +0200 Subject: unsized string compare fix --- llvm_mode/compare-transform-pass.so.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index 10413076..2111b646 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -408,6 +408,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, * the StringRef (in comparison to std::string a StringRef has built-in * runtime bounds checking, which makes debugging easier) */ TmpConstStr.append("\0", 1); + if (!sizedLen) constLen++; ConstStr = StringRef(TmpConstStr); // fprintf(stderr, "issized: %d, const > sized ? %u > %u\n", isSizedcmp, // constLen, sizedLen); -- cgit 1.4.1 From 00683d06c2dc4a021929f25c86b8b426542c4e40 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 20:10:54 +0200 Subject: fix LTO mode --- TODO.md | 3 ++- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 16 ++++++---------- llvm_mode/afl-llvm-pass.so.cc | 3 +-- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/TODO.md b/TODO.md index f326b6c7..dd88dcc2 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,8 @@ ## Roadmap 2.65+ - - AFL_MAP_SIZE for afl-llvm-pass, qemu_mode and unicorn_mode + - InsTrim mode for LTO solution + - AFL_MAP_SIZE for qemu_mode and unicorn_mode - random crc32 HASH_CONST per run? because with 65536 paths we have collisions - namespace for targets? e.g. network - libradamsa as a custom module? diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 2811d98e..838e45af 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -690,8 +690,7 @@ bool AFLLTOPass::runOnModule(Module &M) { if (map_addr) { GlobalVariable *AFLMapAddrFixed = new GlobalVariable( - M, Int64Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr", - 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); + M, Int64Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr"); ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr); StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed); StoreMapAddr->setMetadata(M.getMDKindID("nosanitize"), @@ -706,8 +705,7 @@ bool AFLLTOPass::runOnModule(Module &M) { if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3); GlobalVariable *AFLFinalLoc = new GlobalVariable( - M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", - 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); + M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc"); ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc); StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), @@ -756,10 +754,9 @@ bool AFLLTOPass::runOnModule(Module &M) { } - GlobalVariable *AFLDictionaryLen = new GlobalVariable( - M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, - "__afl_dictionary_len", 0, GlobalVariable::GeneralDynamicTLSModel, - 0, false); + GlobalVariable *AFLDictionaryLen = + new GlobalVariable(M, Int32Ty, false, GlobalValue::ExternalLinkage, + 0, "__afl_dictionary_len"); ConstantInt *const_len = ConstantInt::get(Int32Ty, offset); StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen); StoreDictLen->setMetadata(M.getMDKindID("nosanitize"), @@ -770,8 +767,7 @@ bool AFLLTOPass::runOnModule(Module &M) { M, ArrayTy, true, GlobalValue::ExternalLinkage, ConstantDataArray::get(C, *(new ArrayRef((char *)ptr, offset))), - "__afl_internal_dictionary", 0, - GlobalVariable::GeneralDynamicTLSModel, 0, false); + "__afl_internal_dictionary"); AFLInternalDictionary->setInitializer(ConstantDataArray::get( C, *(new ArrayRef((char *)ptr, offset)))); AFLInternalDictionary->setConstant(true); diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index c0391b04..0d9e0aba 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -583,8 +583,7 @@ bool AFLCoverage::runOnModule(Module &M) { GlobalVariable *AFLFinalLoc = new GlobalVariable( M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, - "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, - false); + "__afl_final_loc"); ConstantInt *const_loc = ConstantInt::get(Int32Ty, map_size); StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), -- cgit 1.4.1 From ad3960580d4b462e53c98f82283cd11037558642 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 20:19:04 +0200 Subject: fixed typos --- docs/Changelog.md | 4 ++-- docs/env_variables.md | 7 ++++--- examples/afl_network_proxy/GNUmakefile | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index e4ac8783..54564a5d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -22,9 +22,9 @@ sending a mail to . - fixes to LTO mode if instrumented edges > MAP_SIZE - CTX and NGRAM can now be used together - CTX and NGRAM are now also supported in CFG/INSTRIM mode - - AFL_LLVM_LAF_TRANSFORM_COMPARES could, fixed + - AFL_LLVM_LAF_TRANSFORM_COMPARES could crash, fixed - added AFL_LLVM_SKIP_NEVERZERO to skip the never zero coverage counter - implmentation. For targets with little or no loops or heavy called + implementation. For targets with few or no loops or heavily called functions. Gives a small performance boost. - qemu_mode: - add information on PIE/PIC load addresses for 32 bit diff --git a/docs/env_variables.md b/docs/env_variables.md index ab5808ec..ed81c8a3 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -102,9 +102,10 @@ Then there are a few specific features that are only available in llvm_mode: LTO - LTO instrumentation (see below) CTX - context sensitive instrumentation (see below) NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) - In CLASSIC (default) can can also specify CTX and/nor NGRAM, seperate - the options with a comma "," then, e.g.: - AFL_LLVM_INSTRUMENT=CLASSIC,CTX,NGRAM-4 + In CLASSIC (default) and CFG/INSTRIM you can also specify CTX and/or + NGRAM, seperate the options with a comma "," then, e.g.: + AFL_LLVM_INSTRUMENT=CFG,CTX,NGRAM-4 + Not that this is a good idea to use both CTX and NGRAM :) ### LTO diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile index 99221d10..eafc5249 100644 --- a/examples/afl_network_proxy/GNUmakefile +++ b/examples/afl_network_proxy/GNUmakefile @@ -12,7 +12,7 @@ endif ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" CFLAGS += -ldeflate -DUSE_DEFLATE=1 - $(info libdeflate-dev was detected, using compressing) + $(info libdeflate-dev was detected, using compression) else $(warn did not find libdeflate-dev, cannot use compression) endif -- cgit 1.4.1 From 128e4d55651731a876cd33bee900021cf61ab39b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 20:23:16 +0200 Subject: more typos fixed --- examples/afl_untracer/afl-untracer.c | 4 ++-- llvm_mode/afl-clang-fast.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index f812958c..d319b530 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -65,7 +65,7 @@ #include #include #else -#error "Unsupproted platform" +#error "Unsupported platform" #endif #define MEMORY_MAP_DECREMENT 0x200000000000 @@ -667,7 +667,7 @@ int main(int argc, char *argv[]) { fuzz(); // we can use _exit which is faster because our target library - // was loaded via dlopen and there cannot have deconstructors + // was loaded via dlopen and therefore cannot have deconstructors // registered. _exit(0); diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 4b9999a6..2d1b427c 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -717,7 +717,7 @@ int main(int argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_LTO) FATAL( "instrumentation mode LTO specified but LLVM support not available " - "(requires LLVM 11)"); + "(requires LLVM 11 or higher)"); #endif if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC && -- cgit 1.4.1 From dc795331910bb0f0b31a3eb66ccb71432d0a4e22 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 20:29:40 +0200 Subject: more typos fixed --- examples/afl_network_proxy/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/afl_network_proxy/README.md b/examples/afl_network_proxy/README.md index 255be0d8..42c0b71b 100644 --- a/examples/afl_network_proxy/README.md +++ b/examples/afl_network_proxy/README.md @@ -26,7 +26,7 @@ For most targets this hurts performance though so it is disabled by default. ### on the target Run `afl-network-server` with your target with the -m and -t values you need. -Important is the -i parameter which is the TCP port to liste on. +Important is the -i parameter which is the TCP port to listen on. e.g.: ``` $ afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@ @@ -40,9 +40,9 @@ increase the -t value: ``` $ afl-fuzz -i in -o out -t 2000+ -- afl-network-client TARGET-IP 1111 ``` -Note the '+' on the -t parameter value. the afl-network-server will take -care of proper timeouts hence afl-fuzz should not. The '+' increases the timout -and the value itself should be 500-1000 higher than the one on +Note the '+' on the -t parameter value. The afl-network-server will take +care of proper timeouts hence afl-fuzz should not. The '+' increases the +timeout and the value itself should be 500-1000 higher than the one on afl-network-server. ### networking @@ -51,9 +51,9 @@ The TARGET can be an IPv4 or IPv6 address, or a host name that resolves to either. Note that also the outgoing interface can be specified with a '%' for `afl-network-client`, e.g. `fe80::1234%eth0`. -Also make sure your middle value of `/proc/sys/net/ipv4/tcp_rmem` is larger -than your MAP_SIZE (130kb is a good value). This is the default TCP window -size value. +Also make sure your default TCP window size is larger than your MAP_SIZE +(130kb is a good value). +On Linux that is the middle value of `/proc/sys/net/ipv4/tcp_rmem` ## how to compile and install -- cgit 1.4.1 From 0e5027d8d82526ee30f23efdc77abd2876cda1d0 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 5 May 2020 21:46:31 +0200 Subject: maybe_grow->ck_maybe_grow --- examples/afl_network_proxy/GNUmakefile | 3 ++- examples/afl_network_proxy/afl-network-server.c | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile index eafc5249..cf1cbad5 100644 --- a/examples/afl_network_proxy/GNUmakefile +++ b/examples/afl_network_proxy/GNUmakefile @@ -11,7 +11,8 @@ ifdef STATIC endif ifeq "$(shell echo '$(HASH)include @int main() { struct libdeflate_compressor *d = libdeflate_alloc_compressor(1); return 0;}' | tr @ '\n' | $(CC) $(CFLAGS) -x c - -o .test2 -ldeflate 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1" - CFLAGS += -ldeflate -DUSE_DEFLATE=1 + CFLAGS += -DUSE_DEFLATE=1 + LDFLAGS += -ldeflate $(info libdeflate-dev was detected, using compression) else $(warn did not find libdeflate-dev, cannot use compression) diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c index 01501cc9..2de91cbd 100644 --- a/examples/afl_network_proxy/afl-network-server.c +++ b/examples/afl_network_proxy/afl-network-server.c @@ -356,7 +356,7 @@ int recv_testcase(int s, void **buf, size_t *max_len) { if ((size & 0xff000000) != 0xff000000) { - *buf = maybe_grow(buf, max_len, size); + *buf = ck_maybe_grow(buf, max_len, size); received = 0; // fprintf(stderr, "unCOMPRESS (%u)\n", size); while (received < size && @@ -368,7 +368,7 @@ int recv_testcase(int s, void **buf, size_t *max_len) { #ifdef USE_DEFLATE u32 clen; size -= 0xff000000; - *buf = maybe_grow(buf, max_len, size); + *buf = ck_maybe_grow(buf, max_len, size); received = 0; while (received < 4 && (ret = recv(s, &clen + received, 4 - received, 0)) > 0) @@ -377,7 +377,7 @@ int recv_testcase(int s, void **buf, size_t *max_len) { // fprintf(stderr, "received clen information of %d\n", clen); if (clen < 1) FATAL("did not receive valid compressed len information: %u", clen); - buf2 = maybe_grow((void **)&buf2, &buf2_len, clen); + buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, clen); received = 0; while (received < clen && (ret = recv(s, buf2 + received, clen - received, 0)) > 0) @@ -566,7 +566,7 @@ int main(int argc, char **argv_orig, char **envp) { sharedmem_t shm = {0}; fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); - in_data = maybe_grow((void **)&in_data, &max_len, 65536); + in_data = ck_maybe_grow((void **)&in_data, &max_len, 65536); atexit(at_exit_handler); setup_signal_handlers(); @@ -637,7 +637,7 @@ int main(int argc, char **argv_orig, char **envp) { #ifdef USE_DEFLATE compressor = libdeflate_alloc_compressor(1); decompressor = libdeflate_alloc_decompressor(); - buf2 = maybe_grow((void **)&buf2, &buf2_len, map_size + 16); + buf2 = ck_maybe_grow((void **)&buf2, &buf2_len, map_size + 16); lenptr = (u32 *)(buf2 + 4); fprintf(stderr, "Compiled with compression support\n"); #endif -- cgit 1.4.1 From e31b816aa0948e66902828595fe1b437cb4cd496 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Tue, 5 May 2020 22:46:48 +0200 Subject: fix unit tests when printf is a macro --- test/unittests/unit_list.c | 1 + test/unittests/unit_maybe_alloc.c | 1 + test/unittests/unit_preallocable.c | 1 + 3 files changed, 3 insertions(+) diff --git a/test/unittests/unit_list.c b/test/unittests/unit_list.c index df4864e4..86d4748b 100644 --- a/test/unittests/unit_list.c +++ b/test/unittests/unit_list.c @@ -33,6 +33,7 @@ void __wrap_exit(int status) { } /* ignore all printfs */ +#undef printf extern int printf(const char *format, ...); extern int __real_printf(const char *format, ...); int __wrap_printf(const char *format, ...); diff --git a/test/unittests/unit_maybe_alloc.c b/test/unittests/unit_maybe_alloc.c index 8cd8b11a..4e093cfe 100644 --- a/test/unittests/unit_maybe_alloc.c +++ b/test/unittests/unit_maybe_alloc.c @@ -33,6 +33,7 @@ void __wrap_exit(int status) { int __wrap_printf(const char *format, ...); /* ignore all printfs */ +#undef printf extern int printf(const char *format, ...); extern int __real_printf(const char *format, ...); int __wrap_printf(const char *format, ...) { diff --git a/test/unittests/unit_preallocable.c b/test/unittests/unit_preallocable.c index 8d619b78..888bb485 100644 --- a/test/unittests/unit_preallocable.c +++ b/test/unittests/unit_preallocable.c @@ -33,6 +33,7 @@ void __wrap_exit(int status) { } /* ignore all printfs */ +#undef printf extern int printf(const char *format, ...); extern int __real_printf(const char *format, ...); int __wrap_printf(const char *format, ...); -- cgit 1.4.1 From a31b58eeeaaf67f2d2eaaf676dee60c427278cae Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Tue, 5 May 2020 22:59:26 +0200 Subject: add one more alternative to python requirements: python-dev --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 98092f11..df1434a0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -307,7 +307,7 @@ test_python: else test_python: - @echo "[-] You seem to need to install the package python3-dev or python2-dev (and perhaps python[23]-apt), but it is optional so we continue" + @echo "[-] You seem to need to install the package python3-dev, python2-dev or python-dev (and perhaps python[23]-apt), but it is optional so we continue" endif -- cgit 1.4.1 From a13958b32b6a1d8cba6f82b0d1ad03801721e3ef Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 5 May 2020 23:44:02 +0200 Subject: updated unicornafl --- unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index 11bd2155..c0cc9e02 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -d4cc77cce71c15bb3d1f552d703a77e2a17cf42d +94c1976 diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index d4cc77cc..94c19769 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit d4cc77cce71c15bb3d1f552d703a77e2a17cf42d +Subproject commit 94c1976975518691a03602f7ec5a817e2f341183 -- cgit 1.4.1