aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile9
-rw-r--r--TODO.md19
-rw-r--r--docs/Changelog.md13
-rw-r--r--docs/env_variables.md11
-rw-r--r--examples/afl_network_proxy/GNUmakefile41
-rw-r--r--examples/afl_network_proxy/Makefile2
-rw-r--r--examples/afl_network_proxy/README.md61
-rw-r--r--examples/afl_network_proxy/afl-network-client.c413
-rw-r--r--examples/afl_network_proxy/afl-network-server.c710
-rw-r--r--examples/afl_proxy/Makefile7
-rw-r--r--examples/afl_proxy/README.md9
-rw-r--r--examples/afl_proxy/afl-proxy.c238
-rw-r--r--examples/afl_untracer/Makefile10
-rw-r--r--examples/afl_untracer/README.md20
-rw-r--r--examples/afl_untracer/afl-untracer.c699
-rw-r--r--examples/afl_untracer/ghidra_get_patchpoints.java84
-rw-r--r--examples/afl_untracer/ida_get_patchpoints.py59
-rw-r--r--examples/afl_untracer/libtestinstr.c35
-rw-r--r--examples/afl_untracer/patches.txt23
-rw-r--r--include/forkserver.h1
-rw-r--r--llvm_mode/GNUmakefile115
-rw-r--r--llvm_mode/LLVMInsTrim.so.cc267
-rw-r--r--llvm_mode/README.lto.md2
-rw-r--r--llvm_mode/README.md21
-rw-r--r--llvm_mode/README.neverzero.md10
-rw-r--r--llvm_mode/afl-clang-fast.c192
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc30
-rw-r--r--llvm_mode/afl-llvm-pass.so.cc156
-rw-r--r--llvm_mode/afl-llvm-rt.o.c15
-rw-r--r--llvm_mode/compare-transform-pass.so.cc55
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-inl.h16
-rw-r--r--qemu_mode/patches/syscall.diff11
-rw-r--r--src/afl-common.c7
-rw-r--r--src/afl-forkserver.c15
-rw-r--r--src/afl-tmin.c2
-rwxr-xr-xtest/test.sh3
-rw-r--r--test/unittests/unit_list.c1
-rw-r--r--test/unittests/unit_maybe_alloc.c1
-rw-r--r--test/unittests/unit_preallocable.c1
-rw-r--r--unicorn_mode/UNICORNAFL_VERSION2
-rwxr-xr-xunicorn_mode/build_unicorn_support.sh8
-rw-r--r--unicorn_mode/samples/persistent/Makefile3
-rw-r--r--unicorn_mode/samples/persistent/harness.c4
-rwxr-xr-xunicorn_mode/samples/persistent/persistent_targetbin0 -> 20048 bytes
m---------unicorn_mode/unicornafl0
45 files changed, 3083 insertions, 318 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 8ea64109..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
@@ -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/TODO.md b/TODO.md
index d31178c8..dd88dcc2 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,9 +1,9 @@
# TODO list for AFL++
-## Roadmap 2.65
+## Roadmap 2.65+
- - AFL_MAP_SIZE for afl-llvm-pass, qemu_mode and unicorn_mode
- - fix stability calculation bug
+ - 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?
@@ -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.
-
diff --git a/docs/Changelog.md b/docs/Changelog.md
index dadfa7e0..54564a5d 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -20,6 +20,12 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
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
+ - CTX and NGRAM are now also supported in CFG/INSTRIM mode
+ - AFL_LLVM_LAF_TRANSFORM_COMPARES could crash, fixed
+ - added AFL_LLVM_SKIP_NEVERZERO to skip the never zero coverage counter
+ 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
- better dependency checks
@@ -28,6 +34,13 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- unicorn_mode:
- better submodule handling
- afl-showmap: fix for -Q mode
+ - 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:
- forkserver communication now also used for error reporting
- fix 32 bit build options
diff --git a/docs/env_variables.md b/docs/env_variables.md
index 41c8f12a..ed81c8a3 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -97,12 +97,15 @@ 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) 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
@@ -204,6 +207,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/examples/afl_network_proxy/GNUmakefile b/examples/afl_network_proxy/GNUmakefile
new file mode 100644
index 00000000..cf1cbad5
--- /dev/null
+++ b/examples/afl_network_proxy/GNUmakefile
@@ -0,0 +1,41 @@
+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
+
+ifeq "$(shell echo '$(HASH)include <libdeflate.h>@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 += -DUSE_DEFLATE=1
+ LDFLAGS += -ldeflate
+ $(info libdeflate-dev was detected, using compression)
+else
+ $(warn did not find libdeflate-dev, cannot use compression)
+endif
+
+all: $(PROGRAMS)
+
+help:
+ @echo make options:
+ @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)
+
+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)\" $(LDFLAGS)
+
+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 -T -m 644 README.md $${DESTDIR}$(DOC_PATH)/README.network_proxy.md
+
diff --git a/examples/afl_network_proxy/Makefile b/examples/afl_network_proxy/Makefile
new file mode 100644
index 00000000..0b306dde
--- /dev/null
+++ b/examples/afl_network_proxy/Makefile
@@ -0,0 +1,2 @@
+all:
+ @echo please use GNU make, thanks!
diff --git a/examples/afl_network_proxy/README.md b/examples/afl_network_proxy/README.md
new file mode 100644
index 00000000..42c0b71b
--- /dev/null
+++ b/examples/afl_network_proxy/README.md
@@ -0,0 +1,61 @@
+# 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
+
+### Compiling
+
+Just type `make` and let the autodetection do everything for you.
+
+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
+
+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 listen on.
+e.g.:
+```
+$ afl-network-server -i 1111 -m 25M -t 1000 -- /bin/target -f @@
+```
+
+### 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
+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
+timeout 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`.
+
+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
+
+`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..cf09b2ad
--- /dev/null
+++ b/examples/afl_network_proxy/afl-network-client.c
@@ -0,0 +1,413 @@
+/*
+ american fuzzy lop++ - afl-network-client
+ ---------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de>
+
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#ifdef USE_DEFLATE
+#include <libdeflate.h>
+#endif
+
+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 = 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;
+
+ /* 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(int status) {
+
+ 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 * 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) {
+
+ 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 + 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;
+ 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
+
+#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, "Compiled 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, received;
+
+ // fprintf(stderr, "Waiting for first testcase\n");
+ while ((*lenptr = __afl_next_testcase(buf + 4, max_len)) > 0) {
+
+ // 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) {
+
+ // 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 {
+
+#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;
+ 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");
+
+ 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 */
+ __afl_end_testcase(status);
+ // fprintf(stderr, "Waiting for next testcase %d\n", ++i);
+
+ }
+
+#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
new file mode 100644
index 00000000..2de91cbd
--- /dev/null
+++ b/examples/afl_network_proxy/afl-network-server.c
@@ -0,0 +1,710 @@
+/*
+ american fuzzy lop++ - network proxy server
+ -------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Forkserver design by Jann Horn <jannhorn@googlemail.com>
+
+ Now maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
+
+ 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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifdef USE_DEFLATE
+#include <libdeflate.h>
+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 size_t buf2_len;
+
+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) {
+
+ 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 == 0) FATAL("did not receive valid size information");
+ // fprintf(stderr, "received size information of %d\n", size);
+
+ if ((size & 0xff000000) != 0xff000000) {
+
+ *buf = ck_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 -= 0xff000000;
+ *buf = ck_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 clen1 information");
+ // fprintf(stderr, "received clen information of %d\n", clen);
+ if (clen < 1)
+ FATAL("did not receive valid compressed len information: %u", clen);
+ buf2 = ck_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 %lu != %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);
+ u8 * send_buf;
+#ifdef USE_DEFLATE
+ u32 *lenptr;
+#endif
+
+ 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;
+
+ if ((send_buf = malloc(map_size + 4)) == NULL) PFATAL("malloc");
+
+ 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 = ck_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
+
+#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);
+ 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);
+
+#ifdef USE_DEFLATE
+ compressor = libdeflate_alloc_compressor(1);
+ decompressor = libdeflate_alloc_decompressor();
+ buf2 = ck_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",
+ port);
+
+ 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);
+
+ 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");
+
+ }
+
+ 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); }
+#if USE_DEFLATE
+ if (buf2) { ck_free(buf2); }
+ libdeflate_free_compressor(compressor);
+ libdeflate_free_decompressor(decompressor);
+#endif
+
+ argv_cpy_free(argv);
+
+ exit(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..36121e17
--- /dev/null
+++ b/examples/afl_proxy/afl-proxy.c
@@ -0,0 +1,238 @@
+/*
+ american fuzzy lop++ - afl-proxy skeleton example
+ ---------------------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de>
+
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+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[]) {
+
+ /* This is were the testcase data is written into */
+ 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; // default is 65536
+
+ /* 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_untracer/Makefile b/examples/afl_untracer/Makefile
new file mode 100644
index 00000000..5c525877
--- /dev/null
+++ b/examples/afl_untracer/Makefile
@@ -0,0 +1,10 @@
+all: afl-untracer libtestinstr.so
+
+afl-untracer: afl-untracer.c
+ $(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 libtestinstr.so *~ core
diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md
new file mode 100644
index 00000000..4ff96423
--- /dev/null
+++ b/examples/afl_untracer/README.md
@@ -0,0 +1,20 @@
+# afl-untracer
+
+afl-untracer is an example skeleton file which can easily be used to fuzz
+a closed source library.
+
+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).
+
+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
+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
new file mode 100644
index 00000000..d319b530
--- /dev/null
+++ b/examples/afl_untracer/afl-untracer.c
@@ -0,0 +1,699 @@
+/*
+ american fuzzy lop++ - afl-untracer skeleton example
+ ---------------------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de>
+
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#if defined(__linux__)
+#include <sys/ucontext.h>
+#elif defined(__APPLE__) && defined(__LP64__)
+#include <mach-o/dyld_images.h>
+#elif defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#else
+#error "Unsupported platform"
+#endif
+
+#define MEMORY_MAP_DECREMENT 0x200000000000
+#define MAX_LIB_COUNT 128
+
+// 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!
+
+/* 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
+
+typedef struct library_list {
+
+ u8 *name;
+ u64 addr_start, addr_end;
+
+} library_list_t;
+
+#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() {
+
+#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");
+
+ if (debug) fprintf(stderr, "Library list:\n");
+ while (fgets(buf, sizeof(buf), f)) {
+
+ if (strstr(buf, " r-x")) {
+
+ 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);
+ 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++;
+
+ }
+
+ }
+
+ }
+
+ if (debug) fprintf(stderr, "\n");
+
+#elif defined(__FreeBSD__)
+ 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; }
+
+ 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
+
+}
+
+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) do_exit = 1;
+ // fprintf(stderr, "write0 %d\n", do_exit);
+
+}
+
+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) do_exit = 1;
+ // fprintf(stderr, "read %d\n", do_exit);
+
+ /* we have a testcase - read it if we read from stdin */
+ 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, &pid, 4) != 4) do_exit = 1;
+ // fprintf(stderr, "write1 %d\n", do_exit);
+
+ return status;
+
+}
+
+static void __afl_end_testcase(int status) {
+
+ if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
+ // fprintf(stderr, "write2 %d\n", do_exit);
+ if (do_exit) exit(0);
+
+}
+
+#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 = 0;
+
+ 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);
+ 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");
+
+ }
+
+ // 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);
+
+ if (bitmap_index >= __afl_map_size)
+ FATAL("Too many basic blocks to instrument");
+
+ uint32_t *shadow = SHADOW(lib_addr + 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];
+ *shadow = (bitmap_index << 8) | orig_byte;
+ lib_addr[offset] = 0xcc; // replace instruction with debug trap
+ 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
+#error "non x86_64 not supported yet"
+ //__arm__:
+ // linux thumb: 0xde01
+ // linux arm: 0xe7f001f0
+ //__aarch64__:
+ // linux aarch64: 0xd4200000
+#endif
+
+ bitmap_index++;
+
+ }
+
+ 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);
+
+ 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);
+
+}
+
+/* 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;
+ // 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];
+#elif defined(__FreeBSD__) && defined(__LP64__)
+ ctx->uc_mcontext.mc_rip -= 1;
+ addr = ctx->uc_mcontext.mc_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 (unlikely(si->si_addr))
+ faultaddr = (u8 *)si->si_addr - 1;
+ else
+ faultaddr = (u8 *)addr;
+ // 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);
+
+ // Index zero is invalid so that it is still possible to catch actual trap
+ // instructions in instrumented libraries.
+ if (unlikely(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_function)(u8 *buf, int len);
+
+/* the MAIN function */
+int main(int argc, char *argv[]) {
+
+ 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;
+ inputfile = argv[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!
+
+ 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
+
+ /* setup instrumentation, shared memory and forkserver */
+ read_library_information();
+ setup_trap_instrumentation();
+ __afl_map_shm();
+ __afl_start_forkserver();
+
+ while (1) {
+
+ 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 {
+
+ pid = getpid();
+ while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
+
+ // in this function the fuzz magic happens, this is STEP 3
+ fuzz();
+
+ // we can use _exit which is faster because our target library
+ // was loaded via dlopen and therefore cannot have deconstructors
+ // registered.
+ _exit(0);
+
+ }
+
+ }
+
+ }
+
+ return 0;
+
+}
+
+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
+
+}
+
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
new file mode 100644
index 00000000..c7e8f899
--- /dev/null
+++ b/examples/afl_untracer/ida_get_patchpoints.py
@@ -0,0 +1,59 @@
+#
+# 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)
+ 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)
+ if not f:
+ 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 - subtract_addr)
+ #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)))
diff --git a/examples/afl_untracer/libtestinstr.c b/examples/afl_untracer/libtestinstr.c
new file mode 100644
index 00000000..96b1cf21
--- /dev/null
+++ b/examples/afl_untracer/libtestinstr.c
@@ -0,0 +1,35 @@
+/*
+ american fuzzy lop++ - a trivial program to test the build
+ --------------------------------------------------------
+ Originally written by Michal Zalewski
+ Copyright 2014 Google Inc. All rights reserved.
+ Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+ http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void testinstr(char *buf, int len) {
+
+ if (len < 1) return;
+ buf[len] = 0;
+
+ // we support three input cases
+ if (buf[0] == '0')
+ printf("Looks like a zero to me!\n");
+ else if (buf[0] == '1')
+ printf("Pretty sure that is a one!\n");
+ else
+ printf("Neither one or zero? How quaint!\n");
+
+}
+
diff --git a/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/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index 69b0875e..93886e47 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,79 @@ 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
+ else
+ # hope for the best
+ $(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
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
@@ -114,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
@@ -141,24 +190,11 @@ 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
-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 +202,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 +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 "[!] Retrying 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 +325,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 +358,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/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc
index 98263ef1..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 <string>
#include <fstream>
-#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;
@@ -56,6 +57,7 @@ struct InsTrim : public ModulePass {
protected:
uint32_t function_minimum_size = 1;
uint32_t debug = 0;
+ char * skip_nozero = NULL;
private:
std::mt19937 generator;
@@ -93,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) {
@@ -107,11 +115,17 @@ 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)
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) {
@@ -123,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<Constant *, 32> 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;
@@ -238,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);
}
@@ -252,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<CallInst>(&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 {
@@ -274,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);
}
@@ -283,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);
@@ -304,8 +490,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
{
@@ -328,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<ReturnInst>(Inst) || isa<ResumeInst>(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/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
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/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..2d1b427c 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,54 +563,6 @@ int main(int argc, char **argv, char **envp) {
instrument_mode = INSTRUMENT_PCGUARD;
#endif
- 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")) {
@@ -631,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) {
@@ -685,9 +715,22 @@ 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 or higher)");
#endif
+ if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC &&
+ instrument_mode != INSTRUMENT_CFG)
+ FATAL(
+ "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 (argc < 2 || strcmp(argv[1], "-h") == 0) {
if (instrument_mode != INSTRUMENT_LTO)
@@ -726,6 +769,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..838e45af 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));
@@ -682,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"),
@@ -698,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"),
@@ -748,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"),
@@ -762,8 +767,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
M, ArrayTy, true, GlobalValue::ExternalLinkage,
ConstantDataArray::get(C,
*(new ArrayRef<char>((char *)ptr, offset))),
- "__afl_internal_dictionary", 0,
- GlobalVariable::GeneralDynamicTLSModel, 0, false);
+ "__afl_internal_dictionary");
AFLInternalDictionary->setInitializer(ConstantDataArray::get(
C, *(new ArrayRef<char>((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 9314c3d1..0d9e0aba 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,8 +180,9 @@ 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;
+ unsigned PrevLocSize = 0;
char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE");
if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE");
@@ -215,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. */
@@ -296,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<CallInst>(&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<CallInst>(&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<ReturnInst>(Inst) || isa<ResumeInst>(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));
}
@@ -409,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<ReturnInst>(Inst) || isa<ResumeInst>(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;
@@ -433,13 +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
- 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());
+ PrevLocTrans = IRB.CreateZExt(PrevLocTrans, IRB.getInt32Ty());
/* Load SHM pointer */
@@ -451,7 +456,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));
@@ -467,6 +474,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 +492,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));
@@ -517,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<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
+
+ IRBuilder<> Post_IRB(Inst);
+ StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
+ RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ }
+
+ }
+
inst_blocks++;
}
@@ -560,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"),
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index 8867ae36..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%x, 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 ? "<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..2111b646 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<ConstantExpr>(Str2P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
- if (auto *Array =
- dyn_cast<ConstantDataArray>(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<ConstantDataArray>(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<GlobalVariable>(Ptr->getOperand(0))) {
- if (auto *Array =
- dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+ if (Var->hasInitializer()) {
+
+ if (auto *Array = dyn_cast<ConstantDataArray>(
+ 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];
@@ -386,13 +394,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();
}
@@ -400,9 +408,14 @@ 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);
-
- 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/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:
diff --git a/src/afl-common.c b/src/afl-common.c
index dda62219..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_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
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index d5a60077..c1623f22 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,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, &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 +829,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 +861,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 +873,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 +890,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;
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':
diff --git a/test/test.sh b/test/test.sh
index b8d4208f..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`
@@ -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
} || {
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, ...);
diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION
index 0afcf291..c0cc9e02 100644
--- a/unicorn_mode/UNICORNAFL_VERSION
+++ b/unicorn_mode/UNICORNAFL_VERSION
@@ -1 +1 @@
-25ae270
+94c1976
diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh
index 965d7614..aeb26945 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!"
@@ -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
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
--- /dev/null
+++ b/unicorn_mode/samples/persistent/persistent_target
Binary files differ
diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl
-Subproject 25ae270c1b949a5d1c2c5460b778f0a35bfe67d
+Subproject 94c1976975518691a03602f7ec5a817e2f34118