diff options
author | van Hauser <vh@thc.org> | 2020-04-26 16:51:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-26 16:51:21 +0200 |
commit | 62ec52dd956d62957b431ef804b7956124823f00 (patch) | |
tree | 706a66892726df089a9d8bf6e8a6e8b1665ff5a8 | |
parent | ce9c6df45639db922feafb55259e20c7e82af0bf (diff) | |
parent | ea876e59a8c1abc979ea05aa4dbe660608aaa9ba (diff) | |
download | afl++-62ec52dd956d62957b431ef804b7956124823f00.tar.gz |
Merge pull request #336 from AFLplusplus/dev
pull again ...
42 files changed, 927 insertions, 1369 deletions
diff --git a/.travis.yml b/.travis.yml index 89d72c34..a360bd42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ jobs: - arch: arm64 env: - - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_STOP_MANUALLY=1 + - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 # - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_EXIT_WHEN_DONE=1 # TODO: test AFL_BENCH_UNTIL_CRASH once we have a target that crashes # - AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_NO_UI=1 AFL_BENCH_JUST_ONE=1 diff --git a/GNUmakefile b/GNUmakefile index 2337b9e0..8811da03 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -88,24 +88,50 @@ ifneq "$(shell command -v python3m 2>/dev/null)" "" endif endif -ifneq "$(shell command -v python3 2>/dev/null)" "" - ifneq "$(shell command -v python3-config 2>/dev/null)" "" - PYTHON_INCLUDE ?= $(shell python3-config --includes) - PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1)) - # Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag. - ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1" - PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags) - else - PYTHON_LIB ?= $(shell python3-config --ldflags) +ifeq "$(PYTHON_INCLUDE)" "" + ifneq "$(shell command -v python3 2>/dev/null)" "" + ifneq "$(shell command -v python3-config 2>/dev/null)" "" + PYTHON_INCLUDE ?= $(shell python3-config --includes) + PYTHON_VERSION ?= $(strip $(shell python3 --version 2>&1)) + # Starting with python3.8, we need to pass the `embed` flag. Earier versions didn't know this flag. + ifeq "$(shell python3-config --embed --libs 2>/dev/null | grep -q lpython && echo 1 )" "1" + PYTHON_LIB ?= $(shell python3-config --libs --embed --ldflags) + else + PYTHON_LIB ?= $(shell python3-config --ldflags) + endif + endif + endif +endif + +ifeq "$(PYTHON_INCLUDE)" "" + ifneq "$(shell command -v python 2>/dev/null)" "" + ifneq "$(shell command -v python-config 2>/dev/null)" "" + PYTHON_INCLUDE ?= $(shell python-config --includes) + PYTHON_LIB ?= $(shell python-config --ldflags) + PYTHON_VERSION ?= $(strip $(shell python --version 2>&1)) endif endif endif -ifneq "$(shell command -v python 2>/dev/null)" "" - ifneq "$(shell command -v python-config 2>/dev/null)" "" - PYTHON_INCLUDE ?= $(shell python-config --includes) - PYTHON_LIB ?= $(shell python-config --ldflags) - PYTHON_VERSION ?= $(strip $(shell python --version 2>&1)) +# Old Ubuntu and others dont have python/python3-config so we hardcode 3.7 +ifeq "$(PYTHON_INCLUDE)" "" + ifneq "$(shell command -v python3.7 2>/dev/null)" "" + ifneq "$(shell command -v python3.7-config 2>/dev/null)" "" + PYTHON_INCLUDE ?= $(shell python3.7-config --includes) + PYTHON_LIB ?= $(shell python3.7-config --ldflags) + PYTHON_VERSION ?= $(strip $(shell python3.7 --version 2>&1)) + endif + endif +endif + +# Old Ubuntu and others dont have python/python2-config so we hardcode 2.7 +ifeq "$(PYTHON_INCLUDE)" "" + ifneq "$(shell command -v python2.7 2>/dev/null)" "" + ifneq "$(shell command -v python2.7-config 2>/dev/null)" "" + PYTHON_INCLUDE ?= $(shell python2.7-config --includes) + PYTHON_LIB ?= $(shell python2.7-config --ldflags) + PYTHON_VERSION ?= $(strip $(shell python2.7 --version 2>&1)) + endif endif endif @@ -333,27 +359,27 @@ document: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/ $(CC) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o -o afl-fuzz-document $(PYFLAGS) $(LDFLAGS) test/unittests/unit_maybe_alloc.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_maybe_alloc.c $(AFL_FUZZ_FILES) - $(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_maybe_alloc.c -o test/unittests/unit_maybe_alloc.o test/unittests/unit_preallocable.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_preallocable.c $(AFL_FUZZ_FILES) - $(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_preallocable.c -o test/unittests/unit_preallocable.o unit_maybe_alloc: test/unittests/unit_maybe_alloc.o - $(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_maybe_alloc.o -o test/unittests/unit_maybe_alloc $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_maybe_alloc test/unittests/unit_list.o : $(COMM_HDR) include/list.h test/unittests/unit_list.c $(AFL_FUZZ_FILES) - $(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -c test/unittests/unit_list.c -o test/unittests/unit_list.o unit_list: test/unittests/unit_list.o - $(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_list.o -o test/unittests/unit_list $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_list test/unittests/preallocable.o : $(COMM_HDR) include/afl-prealloc.h test/unittests/preallocable.c $(AFL_FUZZ_FILES) - $(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CFLAGS_FLTO) -c test/unittests/preallocable.c -o test/unittests/preallocable.o + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(CFLAGS_FLTO) -c test/unittests/preallocable.c -o test/unittests/preallocable.o unit_preallocable: test/unittests/unit_preallocable.o - $(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) $(ASAN_CFLAGS) -Wl,--wrap=exit -Wl,--wrap=printf test/unittests/unit_preallocable.o -o test/unittests/unit_preallocable $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_preallocable unit_clean: @@ -426,7 +452,7 @@ clean: $(MAKE) -C src/third_party/libradamsa/ clean rm -rf qemu_mode/qemu-3.1.1 ifeq "$(IN_REPO)" "1" - $(MAKE) -C unicorn_mode/unicornafl clean || true + test -d unicorn_mode/unicornafl && $(MAKE) -C unicorn_mode/unicornafl clean || true else rm -rf qemu_mode/qemu-3.1.1.tar.xz rm -rf unicorn_mode/unicornafl diff --git a/README.md b/README.md index 9ec7b6e7..222afab7 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ afl++ has many build options. The easiest is to build and install everything: ```shell -$ sudo apt install build-essential libtool-bin python3 automake bison libglib2.0-dev libpixman-1-dev clang python-setuptools +$ sudo apt install build-essential libtool-bin python3 automake bison libglib2.0-dev libpixman-1-dev clang python-setuptools llvm $ make distrib $ sudo make install ``` diff --git a/docs/Changelog.md b/docs/Changelog.md index 8f584393..71de0984 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,14 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. ### Version ++2.64d (develop): + - afl-fuzz: + - AFL_MAP_SIZE was not working correctly + - better python detection + - llvm_mode: + - if LLVM 11 is installed the posix shm_open+mmap is used and a fixed + address for the shared memory map is used as this increases the + fuzzing speed + - fixes to LTO mode if instrumented edges > MAP_SIZE - qemu_mode: - add information on PIE/PIC load addresses for 32 bit - better dependency checks @@ -18,6 +26,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - unicorn_mode: - better submodule handling - all: + - forkserver communication now also used for error reporting - fix 32 bit build options - make clean now leaves qemu-3.1.1.tar.xz and the unicornafl directory intact if in a git/svn checkout - unless "deepclean" is used diff --git a/docs/env_variables.md b/docs/env_variables.md index 21bf9fad..41c8f12a 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -123,6 +123,10 @@ Then there are a few specific features that are only available in llvm_mode: These are used if several seperated instrumentation are performed which are then later combined. + - AFL_LLVM_MAP_ADDR sets the fixed map address to a different address than + the default 0x10000. A value of 0 or empty sets the map address to be + dynamic (the original afl way, which is slower) + - AFL_LLVM_MAP_DYNAMIC sets the shared memory address to be dynamic - AFL_LLVM_LTO_STARTID sets the starting location ID for the instrumentation. This defaults to 1 - AFL_LLVM_LTO_DONTWRITEID prevents that the highest location ID written diff --git a/gcc_plugin/Makefile b/gcc_plugin/Makefile index 3da2e4f6..e81924e0 100644 --- a/gcc_plugin/Makefile +++ b/gcc_plugin/Makefile @@ -68,8 +68,7 @@ LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-lrt) CFLAGS += $(CFLAGS_ADD) LDFLAGS += $(LDFLAGS_ADD) -PROGS = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o - +PROGS = ../afl-gcc-pass.so ../afl-gcc-fast ../afl-gcc-rt.o all: test_shm test_deps $(PROGS) afl-gcc-fast.8 test_build all_done diff --git a/gcc_plugin/afl-gcc-fast.c b/gcc_plugin/afl-gcc-fast.c index 0e51ee62..164c72c2 100644 --- a/gcc_plugin/afl-gcc-fast.c +++ b/gcc_plugin/afl-gcc-fast.c @@ -123,11 +123,17 @@ static void edit_params(u32 argc, char **argv) { u8 *alt_cxx = getenv("AFL_CXX"); cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX; - } else { + } else if (!strcmp(name, "afl-gcc-fast")) { u8 *alt_cc = getenv("AFL_CC"); cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)AFL_GCC_CC; + } else { + + fprintf(stderr, "Name of the binary: %s\n", argv[0]); + FATAL( + "Name of the binary is not a known name, expected afl-(gcc|g++)-fast"); + } char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path); diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 428bfa8e..2203cfdf 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -614,11 +614,6 @@ typedef struct afl_state { } afl_state_t; -/* A global pointer to all instances is needed (for now) for signals to arrive - */ - -extern list_t afl_states; - struct custom_mutator { const char *name; @@ -800,6 +795,14 @@ struct custom_mutator { void afl_state_init(afl_state_t *, uint32_t map_size); void afl_state_deinit(afl_state_t *); + +/* Set stop_soon flag on all childs, kill all childs */ +void afl_states_stop(void); +/* Set clear_screen flag on all states */ +void afl_states_clear_screen(void); +/* Sets the skip flag on all states */ +void afl_states_request_skip(void); + void read_afl_environment(afl_state_t *, char **); /**** Prototypes ****/ diff --git a/include/common.h b/include/common.h index 70ff0744..4aed9572 100644 --- a/include/common.h +++ b/include/common.h @@ -115,7 +115,7 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms); u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms, volatile u8 *stop_soon_p); -u32 get_map_size(); +u32 get_map_size(void); #endif diff --git a/include/config.h b/include/config.h index f11ac919..c21d775a 100644 --- a/include/config.h +++ b/include/config.h @@ -400,14 +400,5 @@ #endif #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ -/* Extended forkserver option values */ - -#define FS_OPT_ENABLED 0x8f000001 -#define FS_OPT_MAPSIZE 0x40000000 -#define FS_OPT_SNAPSHOT 0x20000000 -#define FS_OPT_AUTODICT 0x10000000 -#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1) -#define FS_OPT_SET_MAPSIZE(x) (x <= 1 || x > 0x1000000 ? 0 : ((x - 1) << 1)) - #endif /* ! _HAVE_CONFIG_H */ diff --git a/include/types.h b/include/types.h index f2a12953..e7ff131d 100644 --- a/include/types.h +++ b/include/types.h @@ -30,6 +30,29 @@ typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; +/* Extended forkserver option values */ + +/* Reporting errors */ +#define FS_OPT_ERROR 0xf800008f +#define FS_OPT_GET_ERROR(x) ((x & 0x00ffff00) >> 8) +#define FS_OPT_SET_ERROR(x) ((x & 0x0000ffff) << 8) +#define FS_ERROR_MAP_SIZE 1 +#define FS_ERROR_MAP_ADDR 2 +#define FS_ERROR_SHM_OPEN 4 +#define FS_ERROR_SHMAT 8 +#define FS_ERROR_MMAP 16 + +/* Reporting options */ +#define FS_OPT_ENABLED 0x8f000001 +#define FS_OPT_MAPSIZE 0x40000000 +#define FS_OPT_SNAPSHOT 0x20000000 +#define FS_OPT_AUTODICT 0x10000000 +// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22 +#define FS_OPT_MAX_MAPSIZE ((0x00fffffe >> 1) + 1) +#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1) +#define FS_OPT_SET_MAPSIZE(x) \ + (x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1)) + /* Ugh. There is an unintended compiler / glibc #include glitch caused by @@ -108,7 +131,7 @@ typedef int64_t s64; }) #ifdef AFL_LLVM_PASS -#if defined(__linux__) +#if defined(__linux__) || !defined(__ANDROID__) #define AFL_SR(s) (srandom(s)) #define AFL_R(x) (random() % (x)) #else @@ -116,7 +139,7 @@ typedef int64_t s64; #define AFL_R(x) (arc4random_uniform(x)) #endif #else -#if defined(__linux__) +#if defined(__linux__) || !defined(__ANDROID__) #define SR(s) (srandom(s)) #define R(x) (random() % (x)) #else diff --git a/libdislocator/Makefile b/libdislocator/Makefile index 37fd4fd6..f9c4cb65 100644 --- a/libdislocator/Makefile +++ b/libdislocator/Makefile @@ -39,5 +39,5 @@ clean: install: all install -m 755 -d $${DESTDIR}$(HELPER_PATH) install -m 755 ../libdislocator.so $${DESTDIR}$(HELPER_PATH) - install -m 644 README.dislocator.md $${DESTDIR}$(HELPER_PATH) + install -m 644 -T README.md $${DESTDIR}$(HELPER_PATH)/README.dislocator.md diff --git a/libdislocator/libdislocator.so.c b/libdislocator/libdislocator.so.c index 8098de91..73ddc292 100644 --- a/libdislocator/libdislocator.so.c +++ b/libdislocator/libdislocator.so.c @@ -37,7 +37,7 @@ #include <sys/param.h> #endif -#ifdef __linux__ +#if defined(__linux__) && !defined(__ANDROID__) #include <unistd.h> #include <sys/syscall.h> #ifdef __NR_getrandom @@ -466,11 +466,13 @@ void *reallocarray(void *ptr, size_t elem_len, size_t elem_cnt) { #if !defined(__ANDROID__) size_t malloc_usable_size(void *ptr) { + #else size_t malloc_usable_size(const void *ptr) { + #endif - return ptr ? PTR_L(ptr) : 0; + return ptr ? PTR_L(ptr) : 0; } @@ -498,3 +500,4 @@ __attribute__((constructor)) void __dislocator_init(void) { align_allocations = !!getenv("AFL_ALIGNED_ALLOC"); } + diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 67c31f14..69b0875e 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -1,4 +1,3 @@ -# # american fuzzy lop++ - LLVM instrumentation # ----------------------------------------- # @@ -68,6 +67,7 @@ endif ifeq "$(LLVM_MAJOR)" "11" $(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation) LLVM_LTO = 1 + TEST_MMAP = 1 endif ifeq "$(LLVM_LTO)" "0" @@ -193,13 +193,13 @@ ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int ma else SHMAT_OK=0 CFLAGS+=-DUSEMMAP=1 - LDFLAGS += -lrt + LDFLAGS += -Wno-deprecated-declarations endif ifeq "$(TEST_MMAP)" "1" SHMAT_OK=0 CFLAGS+=-DUSEMMAP=1 - LDFLAGS += -lrt + LDFLAGS += -Wno-deprecated-declarations endif PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so @@ -270,42 +270,45 @@ ifeq "$(LLVM_LTO)" "1" endif endif -../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps - -$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) +afl-llvm-common.o: afl-llvm-common.cc afl-llvm-common.h + $(CXX) $(CFLAGS) `$(LLVM_CONFIG) --cxxflags` -fno-rtti -fPIC -std=$(LLVM_STDCXX) -c $< -o $@ + +../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc afl-llvm-common.o | test_deps + -$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) afl-llvm-common.o -../afl-llvm-pass.so: afl-llvm-pass.so.cc | test_deps +../afl-llvm-pass.so: afl-llvm-pass.so.cc afl-llvm-common.o | test_deps ifeq "$(LLVM_MIN_4_0_1)" "0" $(info [!] N-gram branch coverage instrumentation is not available for llvm version $(LLVMVER)) endif - $(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) + $(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o -../afl-llvm-lto-whitelist.so: afl-llvm-lto-whitelist.so.cc +../afl-llvm-lto-whitelist.so: afl-llvm-lto-whitelist.so.cc afl-llvm-common.o ifeq "$(LLVM_LTO)" "1" - $(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) + $(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o endif -../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc +../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) + $(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 endif # laf -../split-switches-pass.so: split-switches-pass.so.cc | test_deps - $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) -../compare-transform-pass.so: compare-transform-pass.so.cc | test_deps - $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) -../split-compares-pass.so: split-compares-pass.so.cc | test_deps - $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) +../split-switches-pass.so: split-switches-pass.so.cc afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o +../compare-transform-pass.so: compare-transform-pass.so.cc afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o +../split-compares-pass.so: split-compares-pass.so.cc afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o # /laf -../cmplog-routines-pass.so: cmplog-routines-pass.cc | test_deps - $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) +../cmplog-routines-pass.so: cmplog-routines-pass.cc afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o -../cmplog-instructions-pass.so: cmplog-instructions-pass.cc | test_deps - $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) +../cmplog-instructions-pass.so: cmplog-instructions-pass.cc afl-llvm-common.o | test_deps + $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o ../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps $(CC) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@ diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index 8b23942c..98263ef1 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -40,6 +40,7 @@ typedef long double max_align_t; #include "debug.h" #include "MarkNodes.h" +#include "afl-llvm-common.h" using namespace llvm; @@ -53,9 +54,8 @@ namespace { struct InsTrim : public ModulePass { protected: - std::list<std::string> myWhitelist; - uint32_t function_minimum_size = 1; - uint32_t debug = 0; + uint32_t function_minimum_size = 1; + uint32_t debug = 0; private: std::mt19937 generator; @@ -69,24 +69,10 @@ struct InsTrim : public ModulePass { public: static char ID; - InsTrim() : ModulePass(ID), generator(0) { - - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); - getline(fileStream, line); - while (fileStream) { - myWhitelist.push_back(line); - getline(fileStream, line); + InsTrim() : ModulePass(ID), generator(0) { - } - - } + initWhitelist(); } @@ -107,28 +93,6 @@ struct InsTrim : public ModulePass { } - // ripped from aflgo - static bool isBlacklisted(const Function *F) { - - static const char *Blacklist[] = { - - "asan.", - "llvm.", - "sancov.", - "__ubsan_handle_", - - }; - - for (auto const &BlacklistFunc : Blacklist) { - - if (F->getName().startswith(BlacklistFunc)) { return true; } - - } - - return false; - - } - bool runOnModule(Module &M) override { char be_quiet = 0; @@ -194,138 +158,11 @@ struct InsTrim : public ModulePass { } + if (!isInWhitelist(&F)) continue; + // if the function below our minimum size skip it (1 or 2) if (F.size() < function_minimum_size) { continue; } - if (!myWhitelist.empty()) { - - bool instrumentBlock = false; - DebugLoc Loc; - StringRef instFilename; - unsigned int instLine = 0; - -#if LLVM_VERSION_MAJOR >= 4 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - for (auto &BB : F) { - - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - if (!Loc) Loc = IP->getDebugLoc(); - - } - - if (Loc) { - - DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); - - instLine = cDILoc->getLine(); - instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); - - } - - } - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#else - for (auto &BB : F) { - - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - if (Loc.isUnknown()) Loc = IP->getDebugLoc(); - - } - - if (!Loc.isUnknown()) { - - DILocation cDILoc(Loc.getAsMDNode(C)); - - instLine = cDILoc.getLineNumber(); - instFilename = cDILoc.getFilename(); - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#endif - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. */ - if (!instrumentBlock) { - - if (!be_quiet) { - - if (!instFilename.str().empty()) - SAYF(cYEL "[!] " cBRI - "Not in whitelist, skipping %s line %u...\n", - instFilename.str().c_str(), instLine); - else - SAYF(cYEL "[!] " cBRI - "No filename information found, skipping it"); - - } - - continue; - - } - - } - - if (isBlacklisted(&F)) continue; - std::unordered_set<BasicBlock *> MS; if (!MarkSetOpt) { diff --git a/llvm_mode/NOTES b/llvm_mode/NOTES deleted file mode 100644 index 9aee7f46..00000000 --- a/llvm_mode/NOTES +++ /dev/null @@ -1,88 +0,0 @@ - -markNodes - -> - -whitelist: - set meta information/context to functions? ask llvm-dev - setAttribute/hasAttribute? - -afl-ld: - handle(=instrument) .a archives on the cmdline - -afl-pass-lto-instrument.so: - either a or b: - a) use instrim - b) start in main() or _init() and first otherwise (warn!) - keep list of done functions - final: go through function list and instrument those missing - - - ---------------------------- - - - -for (auto &module : Ctx.getModules()) { - auto &functionList = module->getModule()->getFunctionList(); - for (auto &function : functionList) { - for (auto &bb : function) { - for (auto &instruction : bb) { - if (CallInst *callInst = dyn_cast<CallInst>(&instruction)) { - if (Function *calledFunction = callInst->getCalledFunction()) { - if (calledFunction->getName().startswith("llvm.dbg.declare")) { - - -for (auto &U : F.getUsers()) { <- unbekannt - if (auto CS = CallSite(U)) { - if (CS->getCalledFunction() == F) - -getCalledValue()->stripPointerCasts() - -> for indirect calls - - -CallGraph(M) - - - -#include "llvm/IR/CallSite.h" - -unsigned int indirect_call_cnt = 0; - - printf("Function: %s\n", F.getName().str().c_str()); - int cnt=0; - for (auto *U : F.users()) { -// auto *I = dyn_cast<Instruction>(U); -// if (I) { -// if (cast<CallInst>(I)->getCalledFunction()->getName() == F.getName()) { -// printf("DIRECT CALL %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), cast<CallInst>(I)->getCalledFunction()->getName().str().c_str(), F.getName().str().c_str()); -// } -printf("Callsite #%d\n", ++cnt); - CallSite CS(U); - auto *I = CS.getInstruction(); - if (I) { - Value *called = CS.getCalledValue()->stripPointerCasts(); - Function* f = dyn_cast<Function>(called); - if (f->getName().size() > 0) { - printf("test %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), f->getName().str().c_str(), F.getName().str().c_str()); - if (f->getName() == F.getName()) { - printf("CALL %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), f->getName().str().c_str(), F.getName().str().c_str()); - } - } else - printf("FOO %s->...->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), F.getName().str().c_str()); - if (cast<CallInst>(I)->getCalledFunction()->getName() == F.getName()) { - printf("DIRECT %s->%s->%s\n", cast<CallInst>(I)->getParent()->getParent()->getName().str().c_str(), cast<CallInst>(I)->getCalledFunction()->getName().str().c_str(), F.getName().str().c_str()); - } - } else { - printf("WE MISSED SOMETHING HERE!!\n"); - indirect_call_cnt++; - } - } - -oder: - for (auto *U : F.users()) { - if (auto CS = CallSite(U->getUser())) { - if (CS->isCallee(&U)) { - // foo - } - } - } diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index 9af9ffff..bb66b5e7 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -95,6 +95,17 @@ target binary based on string compare and memory compare functions. afl-fuzz will automatically get these transmitted when starting to fuzz. This improves coverage on a lot of targets. +## Fixed memory map + +To speed up fuzzing, the shared memory map is hard set to a specific address, +by default 0x10000. In most cases this will work without any problems. +On unusual operating systems/processors/kernels or weird libraries this might +fail so to change the fixed address at compile time set +AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address +to be dynamic - the original afl way, which is slower). +AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which +is safer but also slower). + ## Potential issues ### compiling libraries fails @@ -110,12 +121,22 @@ Solution: ``` AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure --disable-shared ``` -and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it ... +and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it. +Other targets ignore environment variables and need the parameters set via +`./configure --cc=... --cxx= --ranlib= ...` etc. (I am looking at you ffmpeg!). ### compiling programs still fail afl-clang-lto is still work in progress. -Please report issues at: + +Known issues: + * Anything that llvm11 cannot compile, afl-clang-lto can not compile either - obviously + * Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously + +Hence if building a target with afl-clang-lto fails try to build it with llvm11 +and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and +`CXXFLAGS=-flto=full`). +If this succeeeds then there is an issue with afl-clang-lto. Please report at [https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226) ## Upcoming Work diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc new file mode 100644 index 00000000..9b7a444a --- /dev/null +++ b/llvm_mode/afl-llvm-common.cc @@ -0,0 +1,202 @@ +#define AFL_LLVM_PASS + +#include "config.h" +#include "debug.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> + +#include <list> +#include <string> +#include <fstream> + +#include "afl-llvm-common.h" + +using namespace llvm; + +static std::list<std::string> myWhitelist; + +char *getBBName(const llvm::BasicBlock *BB) { + + static char *name; + + if (!BB->getName().empty()) { + + name = strdup(BB->getName().str().c_str()); + return name; + + } + + std::string Str; + raw_string_ostream OS(Str); + + BB->printAsOperand(OS, false); + name = strdup(OS.str().c_str()); + return name; + +} + +/* Function that we never instrument or analyze */ +/* Note: this blacklist check is also called in isInWhitelist() */ +bool isBlacklisted(const llvm::Function *F) { + + static const char *Blacklist[] = { + + "asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign.", "__afl_", + "_fini", "__libc_csu", "__asan", "__msan", "msan." + + }; + + for (auto const &BlacklistFunc : Blacklist) { + + if (F->getName().startswith(BlacklistFunc)) { return true; } + + } + + return false; + +} + +void initWhitelist() { + + char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); + if (instWhiteListFilename) { + + std::string line; + std::ifstream fileStream; + fileStream.open(instWhiteListFilename); + if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); + getline(fileStream, line); + while (fileStream) { + + myWhitelist.push_back(line); + getline(fileStream, line); + + } + + } + +} + +bool isInWhitelist(llvm::Function *F) { + + // is this a function with code? If it is external we dont instrument it + // anyway and cant be in the whitelist. Or if it is blacklisted. + if (!F->size() || isBlacklisted(F)) return false; + + // if we do not have a whitelist return true + if (myWhitelist.empty()) return true; + + // let's try to get the filename for the function + auto bb = &F->getEntryBlock(); + BasicBlock::iterator IP = bb->getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + DebugLoc Loc = IP->getDebugLoc(); + +#if LLVM_VERSION_MAJOR >= 4 || \ + (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) + if (Loc) { + + DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); + + unsigned int instLine = cDILoc->getLine(); + StringRef instFilename = cDILoc->getFilename(); + + if (instFilename.str().empty()) { + + /* If the original location is empty, try using the inlined location + */ + DILocation *oDILoc = cDILoc->getInlinedAt(); + if (oDILoc) { + + instFilename = oDILoc->getFilename(); + instLine = oDILoc->getLine(); + + } + + } + + (void)instLine; + + /* Continue only if we know where we actually are */ + if (!instFilename.str().empty()) { + + for (std::list<std::string>::iterator it = myWhitelist.begin(); + it != myWhitelist.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. */ + if (instFilename.str().length() >= it->length()) { + + if (instFilename.str().compare( + instFilename.str().length() - it->length(), it->length(), + *it) == 0) { + + return true; + + } + + } + + } + + } + + } + +#else + if (!Loc.isUnknown()) { + + DILocation cDILoc(Loc.getAsMDNode(C)); + + unsigned int instLine = cDILoc.getLineNumber(); + StringRef instFilename = cDILoc.getFilename(); + + (void)instLine; + /* Continue only if we know where we actually are */ + if (!instFilename.str().empty()) { + + for (std::list<std::string>::iterator it = myWhitelist.begin(); + it != myWhitelist.end(); ++it) { + + /* We don't check for filename equality here because + * filenames might actually be full paths. Instead we + * check that the actual filename ends in the filename + * specified in the list. */ + if (instFilename.str().length() >= it->length()) { + + if (instFilename.str().compare( + instFilename.str().length() - it->length(), it->length(), + *it) == 0) { + + return true; + + } + + } + + } + + } + + } + +#endif + else { + + // we could not find out the location. in this case we say it is not + // in the whitelist + + return false; + + } + + // + return false; + +} + diff --git a/llvm_mode/afl-llvm-common.h b/llvm_mode/afl-llvm-common.h new file mode 100644 index 00000000..5b5e08d0 --- /dev/null +++ b/llvm_mode/afl-llvm-common.h @@ -0,0 +1,41 @@ +#ifndef __AFLLLVMCOMMON_H +#define __AFLLLVMCOMMON_H + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <list> +#include <string> +#include <fstream> +#include <sys/time.h> + +#include "llvm/Config/llvm-config.h" +#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 +typedef long double max_align_t; +#endif + +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" + +#if LLVM_VERSION_MAJOR > 3 || \ + (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/CFG.h" +#else +#include "llvm/DebugInfo.h" +#include "llvm/Support/CFG.h" +#endif + +char *getBBName(const llvm::BasicBlock *BB); +bool isBlacklisted(const llvm::Function *F); +void initWhitelist(); +bool isInWhitelist(llvm::Function *F); + +#endif + diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index ece3201f..118ada52 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -31,6 +31,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <string.h> #include <list> #include <string> @@ -56,6 +57,7 @@ #include "llvm/Pass.h" #include <set> +#include "afl-llvm-common.h" using namespace llvm; @@ -103,57 +105,12 @@ class AFLLTOPass : public ModulePass { } - // Get the internal llvm name of a basic block - // This is an ugly debug support so it is commented out :-) - /* - static char *getBBName(const BasicBlock *BB) { - - static char *name; - - if (!BB->getName().empty()) { - - name = strdup(BB->getName().str().c_str()); - return name; - - } - - std::string Str; - raw_string_ostream OS(Str); - - BB->printAsOperand(OS, false); - - name = strdup(OS.str().c_str()); - - return name; - - } - - */ - - static bool isBlacklisted(const Function *F) { - - static const char *Blacklist[] = { - - "asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign.", - "__afl_", "_fini", "__libc_csu" - - }; - - for (auto const &BlacklistFunc : Blacklist) { - - if (F->getName().startswith(BlacklistFunc)) { return true; } - - } - - return false; - - } - bool runOnModule(Module &M) override; protected: 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; }; @@ -165,9 +122,11 @@ bool AFLLTOPass::runOnModule(Module &M) { std::vector<std::string> dictionary; std::vector<CallInst *> calls; DenseMap<Value *, std::string *> valueMap; + char * ptr; IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); + IntegerType *Int64Ty = IntegerType::getInt64Ty(C); if (getenv("AFL_DEBUG")) debug = 1; @@ -186,12 +145,63 @@ bool AFLLTOPass::runOnModule(Module &M) { getenv("AFL_LLVM_LTO_AUTODICTIONARY")) autodictionary = 1; + if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; + + if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) { + + uint64_t val; + if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) { + + map_addr = 0; + + } else if (map_addr == 0) { + + FATAL( + "AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used together"); + + } else if (strncmp(ptr, "0x", 2) != 0) { + + map_addr = 0x10000; // the default + + } else { + + val = strtoull(ptr, NULL, 16); + if (val < 0x100 || val > 0xffffffff00000000) { + + FATAL( + "AFL_LLVM_MAP_ADDR must be a value between 0x100 and " + "0xffffffff00000000"); + + } + + map_addr = val; + + } + + } + + if (debug) { fprintf(stderr, "map address is %lu\n", map_addr); } + /* Get globals for the SHM region and the previous location. Note that __afl_prev_loc is thread-local. */ - GlobalVariable *AFLMapPtr = - new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, - GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); + GlobalVariable *AFLMapPtr = NULL; + ; + Value *MapPtrFixed = NULL; + + if (!map_addr) { + + AFLMapPtr = + new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, + GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); + + } else { + + ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr); + MapPtrFixed = + ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Ty)); + + } ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); ConstantInt *One = ConstantInt::get(Int8Ty, 1); @@ -202,6 +212,8 @@ bool AFLLTOPass::runOnModule(Module &M) { for (auto &F : M) { + // fprintf(stderr, "DEBUG: Function %s\n", F.getName().str().c_str()); + if (F.size() < 2) continue; if (isBlacklisted(&F)) continue; @@ -579,10 +591,20 @@ bool AFLLTOPass::runOnModule(Module &M) { /* Load SHM pointer */ - LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr); - MapPtr->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); + Value *MapPtrIdx; + + if (map_addr) { + + MapPtrIdx = IRB.CreateGEP(MapPtrFixed, CurLoc); + + } else { + + LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr); + MapPtr->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); + + } /* Update bitmap */ @@ -612,7 +634,8 @@ bool AFLLTOPass::runOnModule(Module &M) { // save highest location ID to global variable // do this after each function to fail faster - if (!be_quiet && afl_global_id > MAP_SIZE) { + if (!be_quiet && afl_global_id > MAP_SIZE && + afl_global_id > FS_OPT_MAX_MAPSIZE) { uint32_t pow2map = 1, map = afl_global_id; while ((map = map >> 1)) @@ -627,7 +650,7 @@ bool AFLLTOPass::runOnModule(Module &M) { } - if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL || dictionary.size()) { + if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) { // yes we could create our own function, insert it into ctors ... // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o @@ -656,24 +679,31 @@ bool AFLLTOPass::runOnModule(Module &M) { BasicBlock::iterator IP = bb->getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); + if (map_addr) { + + GlobalVariable *AFLMapAddrFixed = new GlobalVariable( + M, Int64Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr", + 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); + ConstantInt *MapAddr = ConstantInt::get(Int64Ty, map_addr); + StoreInst * StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed); + StoreMapAddr->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) { uint32_t write_loc = afl_global_id; if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3); - if (write_loc <= MAP_SIZE && write_loc <= 0x800000) { - - GlobalVariable *AFLFinalLoc = new GlobalVariable( - M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, - "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, - false); - ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc); - StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); - StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); - - } + GlobalVariable *AFLFinalLoc = new GlobalVariable( + M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", + 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); + ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc); + StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); + StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); } diff --git a/llvm_mode/afl-llvm-lto-whitelist.so.cc b/llvm_mode/afl-llvm-lto-whitelist.so.cc index 48df76c3..5e157472 100644 --- a/llvm_mode/afl-llvm-lto-whitelist.so.cc +++ b/llvm_mode/afl-llvm-lto-whitelist.so.cc @@ -46,6 +46,8 @@ #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/IR/CFG.h" +#include "afl-llvm-common.h" + using namespace llvm; namespace { @@ -86,25 +88,6 @@ class AFLwhitelist : public ModulePass { } - // ripped from aflgo - static bool isBlacklisted(const Function *F) { - - static const SmallVector<std::string, 5> Blacklist = { - - "asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign." - - }; - - for (auto const &BlacklistFunc : Blacklist) { - - if (F->getName().startswith(BlacklistFunc)) { return true; } - - } - - return false; - - } - bool runOnModule(Module &M) override; // StringRef getPassName() const override { diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 71abcd05..9314c3d1 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -61,6 +61,7 @@ typedef long double max_align_t; #include "llvm/Support/CFG.h" #endif +#include "afl-llvm-common.h" #include "llvm-ngram-coverage.h" using namespace llvm; @@ -73,60 +74,17 @@ class AFLCoverage : public ModulePass { static char ID; AFLCoverage() : ModulePass(ID) { - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); - getline(fileStream, line); - while (fileStream) { - - myWhitelist.push_back(line); - getline(fileStream, line); - - } - - } - - } - - // ripped from aflgo - static bool isBlacklisted(const Function *F) { - - static const char *Blacklist[] = { - - "asan.", - "llvm.", - "sancov.", - "__ubsan_handle_", - - }; - - for (auto const &BlacklistFunc : Blacklist) { - - if (F->getName().startswith(BlacklistFunc)) { return true; } - - } - - return false; + initWhitelist(); } bool runOnModule(Module &M) override; - // StringRef getPassName() const override { - - // return "American Fuzzy Lop Instrumentation"; - // } - protected: - std::list<std::string> myWhitelist; - uint32_t ngram_size = 0; - uint32_t debug = 0; - uint32_t map_size = MAP_SIZE; - char * ctx_str = NULL; + uint32_t ngram_size = 0; + uint32_t debug = 0; + uint32_t map_size = MAP_SIZE; + char * ctx_str = NULL; }; @@ -336,9 +294,7 @@ bool AFLCoverage::runOnModule(Module &M) { fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(), F.size()); - if (isBlacklisted(&F)) continue; - - // AllocaInst *CallingContext = nullptr; + 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 @@ -393,115 +349,6 @@ bool AFLCoverage::runOnModule(Module &M) { BasicBlock::iterator IP = BB.getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); - if (!myWhitelist.empty()) { - - bool instrumentBlock = false; - - /* Get the current location using debug information. - * For now, just instrument the block if we are not able - * to determine our location. */ - DebugLoc Loc = IP->getDebugLoc(); -#if LLVM_VERSION_MAJOR >= 4 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - if (Loc) { - - DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); - - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); - - } - - } - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#else - if (!Loc.isUnknown()) { - - DILocation cDILoc(Loc.getAsMDNode(C)); - - unsigned int instLine = cDILoc.getLineNumber(); - StringRef instFilename = cDILoc.getFilename(); - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#endif - - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. */ - if (!instrumentBlock) continue; - - } - // 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) { @@ -630,54 +477,11 @@ bool AFLCoverage::runOnModule(Module &M) { * Counter + 1 -> {Counter, OverflowFlag} * Counter + OverflowFlag -> Counter */ - /* // we keep the old solutions just in case - // Solution #1 - if (neverZero_counters_str[0] == '1') { - - CallInst *AddOv = - IRB.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow, Counter, - ConstantInt::get(Int8Ty, 1)); - AddOv->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); Value *SumWithOverflowBit = AddOv; Incr = - IRB.CreateAdd(IRB.CreateExtractValue(SumWithOverflowBit, 0), // sum - IRB.CreateZExt( // convert from one bit - type to 8 bits type IRB.CreateExtractValue(SumWithOverflowBit, 1), // - overflow Int8Ty)); - // Solution #2 - - } else if (neverZero_counters_str[0] == '2') { - - auto cf = IRB.CreateICmpEQ(Counter, - ConstantInt::get(Int8Ty, 255)); Value *HowMuch = - IRB.CreateAdd(ConstantInt::get(Int8Ty, 1), cf); Incr = - IRB.CreateAdd(Counter, HowMuch); - // Solution #3 - - } else if (neverZero_counters_str[0] == '3') { - - */ - // this is the solution we choose because llvm9 should do the right - // thing here + auto cf = IRB.CreateICmpEQ(Incr, Zero); auto carry = IRB.CreateZExt(cf, Int8Ty); Incr = IRB.CreateAdd(Incr, carry); -/* - // Solution #4 - - } else if (neverZero_counters_str[0] == '4') { - - auto cf = IRB.CreateICmpULT(Incr, ConstantInt::get(Int8Ty, 1)); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); - - } else { - - fprintf(stderr, "Error: unknown value for AFL_NZERO_COUNTS: %s - (valid is 1-4)\n", neverZero_counters_str); exit(-1); - - } -*/ #if LLVM_VERSION_MAJOR < 9 } diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index f286e66a..8867ae36 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -52,6 +52,10 @@ #define CONST_PRIO 5 +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE MAP_FIXED +#endif + #include <sys/mman.h> #include <fcntl.h> @@ -69,12 +73,16 @@ 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; @@ -83,44 +91,113 @@ struct cmp_map *__afl_cmp_map; static u8 is_persistent; +/* 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) { - u8 *id_str = getenv(SHM_ENV_VAR); + char *id_str = getenv(SHM_ENV_VAR); + + if (__afl_final_loc) { + + __afl_map_size = __afl_final_loc; + if (__afl_final_loc > MAP_SIZE) { + + char *ptr; + u32 val = 0; + if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) val = atoi(ptr); + if (val < __afl_final_loc) { + + if (__afl_final_loc > 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_final_loc); + 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_final_loc); + + } + + } + + } + + } /* If we're running under AFL, attach to the appropriate region, replacing the early-stage __afl_area_initial region that is needed to allow some really hacky .init code to work correctly in projects such as OpenSSL. */ + if (getenv("AFL_DEBUG")) + fprintf(stderr, + "DEBUG: id_str %s, __afl_map_addr 0x%x, 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); + if (id_str) { #ifdef USEMMAP const char * shm_file_path = id_str; int shm_fd = -1; unsigned char *shm_base = NULL; - unsigned int map_size = MAP_SIZE - - if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) map_size = - __afl_final_loc; /* 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, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + if (__afl_map_addr) { + + shm_base = + mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE, + MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0); + + } else { + + 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"); + if (__afl_map_addr) + send_forkserver_error(FS_ERROR_MAP_ADDR); + else + send_forkserver_error(FS_ERROR_MMAP); exit(2); } @@ -129,18 +206,40 @@ static void __afl_map_shm(void) { #else u32 shm_id = atoi(id_str); - __afl_area_ptr = shmat(shm_id, NULL, 0); + __afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0); + #endif /* Whooooops. */ - if (__afl_area_ptr == (void *)-1) _exit(1); + if (__afl_area_ptr == (void *)-1) { + + if (__afl_map_addr) + send_forkserver_error(FS_ERROR_MAP_ADDR); + else + send_forkserver_error(FS_ERROR_SHMAT); + _exit(1); + + } /* Write something into the bitmap so that even with low AFL_INST_RATIO, our parent doesn't give up on us. */ __afl_area_ptr[0] = 1; + } else if (__afl_map_addr) { + + __afl_area_ptr = + mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE, + MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (__afl_area_ptr == MAP_FAILED) { + + fprintf(stderr, "can not aquire mmap for address %p\n", + (void *)__afl_map_addr); + exit(1); + + } + } id_str = getenv(CMPLOG_SHM_ENV_VAR); @@ -193,13 +292,9 @@ static void __afl_start_snapshots(void) { static u8 tmp[4] = {0, 0, 0, 0}; s32 child_pid; u32 status = 0; - u32 map_size = MAP_SIZE; u32 already_read_first = 0; u32 was_killed; - if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) - map_size = __afl_final_loc; - u8 child_stopped = 0; void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); @@ -208,8 +303,8 @@ static void __afl_start_snapshots(void) { assume we're not running in forkserver mode and just execute program. */ status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT); - if (map_size <= 0x800000) - status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; memcpy(tmp, &status, 4); @@ -362,19 +457,15 @@ static void __afl_start_forkserver(void) { u8 tmp[4] = {0, 0, 0, 0}; s32 child_pid; u32 status = 0; - u32 map_size = MAP_SIZE; u32 already_read_first = 0; u32 was_killed; - if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) - map_size = __afl_final_loc; - u8 child_stopped = 0; void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); - if (map_size <= 0x800000) - status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) + status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; if (status) status |= (FS_OPT_ENABLED); memcpy(tmp, &status, 4); @@ -512,12 +603,8 @@ static void __afl_start_forkserver(void) { int __afl_persistent_loop(unsigned int max_cnt) { - static u8 first_pass = 1; - static u32 cycle_cnt; - unsigned int map_size = MAP_SIZE; - - if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) - map_size = __afl_final_loc; + static u8 first_pass = 1; + static u32 cycle_cnt; if (first_pass) { @@ -528,7 +615,7 @@ int __afl_persistent_loop(unsigned int max_cnt) { if (is_persistent) { - memset(__afl_area_ptr, 0, map_size); + memset(__afl_area_ptr, 0, __afl_map_size); __afl_area_ptr[0] = 1; memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); diff --git a/llvm_mode/cmplog-instructions-pass.cc b/llvm_mode/cmplog-instructions-pass.cc index b0ab475d..628151c6 100644 --- a/llvm_mode/cmplog-instructions-pass.cc +++ b/llvm_mode/cmplog-instructions-pass.cc @@ -47,6 +47,7 @@ #endif #include <set> +#include "afl-llvm-common.h" using namespace llvm; @@ -58,22 +59,7 @@ class CmpLogInstructions : public ModulePass { static char ID; CmpLogInstructions() : ModulePass(ID) { - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); - getline(fileStream, line); - while (fileStream) { - - myWhitelist.push_back(line); - getline(fileStream, line); - - } - - } + initWhitelist(); } @@ -91,8 +77,7 @@ class CmpLogInstructions : public ModulePass { } protected: - std::list<std::string> myWhitelist; - int be_quiet = 0; + int be_quiet = 0; private: bool hookInstrs(Module &M); @@ -185,118 +170,9 @@ bool CmpLogInstructions::hookInstrs(Module &M) { /* iterate over all functions, bbs and instruction and add suitable calls */ for (auto &F : M) { - for (auto &BB : F) { - - if (!myWhitelist.empty()) { - - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - - bool instrumentBlock = false; - - /* Get the current location using debug information. - * For now, just instrument the block if we are not able - * to determine our location. */ - DebugLoc Loc = IP->getDebugLoc(); -#if LLVM_VERSION_MAJOR >= 4 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - if (Loc) { - - DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); - - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); - - } - - } - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } + if (!isInWhitelist(&F)) continue; - } - - } - - } - -#else - if (!Loc.isUnknown()) { - - DILocation cDILoc(Loc.getAsMDNode(C)); - - unsigned int instLine = cDILoc.getLineNumber(); - StringRef instFilename = cDILoc.getFilename(); - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#endif - - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. */ - if (!instrumentBlock) continue; - - } + for (auto &BB : F) { for (auto &IN : BB) { diff --git a/llvm_mode/cmplog-routines-pass.cc b/llvm_mode/cmplog-routines-pass.cc index f58e351c..b74fb712 100644 --- a/llvm_mode/cmplog-routines-pass.cc +++ b/llvm_mode/cmplog-routines-pass.cc @@ -47,6 +47,7 @@ #endif #include <set> +#include "afl-llvm-common.h" using namespace llvm; @@ -58,22 +59,7 @@ class CmpLogRoutines : public ModulePass { static char ID; CmpLogRoutines() : ModulePass(ID) { - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); - getline(fileStream, line); - while (fileStream) { - - myWhitelist.push_back(line); - getline(fileStream, line); - - } - - } + initWhitelist(); } @@ -91,8 +77,7 @@ class CmpLogRoutines : public ModulePass { } protected: - std::list<std::string> myWhitelist; - int be_quiet = 0; + int be_quiet = 0; private: bool hookRtns(Module &M); @@ -132,118 +117,9 @@ bool CmpLogRoutines::hookRtns(Module &M) { /* iterate over all functions, bbs and instruction and add suitable calls */ for (auto &F : M) { - for (auto &BB : F) { - - if (!myWhitelist.empty()) { - - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - - bool instrumentBlock = false; - - /* Get the current location using debug information. - * For now, just instrument the block if we are not able - * to determine our location. */ - DebugLoc Loc = IP->getDebugLoc(); -#if LLVM_VERSION_MAJOR >= 4 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - if (Loc) { - - DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); - - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); - - } - - } - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } + if (!isInWhitelist(&F)) continue; - } - - } - - } - -#else - if (!Loc.isUnknown()) { - - DILocation cDILoc(Loc.getAsMDNode(C)); - - unsigned int instLine = cDILoc.getLineNumber(); - StringRef instFilename = cDILoc.getFilename(); - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#endif - - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. */ - if (!instrumentBlock) continue; - - } + for (auto &BB : F) { for (auto &IN : BB) { diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index 84a9b8d9..c871c1c4 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -47,6 +47,7 @@ #endif #include <set> +#include "afl-llvm-common.h" using namespace llvm; @@ -58,22 +59,7 @@ class CompareTransform : public ModulePass { static char ID; CompareTransform() : ModulePass(ID) { - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); - getline(fileStream, line); - while (fileStream) { - - myWhitelist.push_back(line); - getline(fileStream, line); - - } - - } + initWhitelist(); } @@ -91,8 +77,7 @@ class CompareTransform : public ModulePass { } protected: - std::list<std::string> myWhitelist; - int be_quiet = 0; + int be_quiet = 0; private: bool transformCmps(Module &M, const bool processStrcmp, @@ -140,118 +125,9 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, * strcmp/memcmp/strncmp/strcasecmp/strncasecmp */ for (auto &F : M) { - for (auto &BB : F) { - - if (!myWhitelist.empty()) { - - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - - bool instrumentBlock = false; - - /* Get the current location using debug information. - * For now, just instrument the block if we are not able - * to determine our location. */ - DebugLoc Loc = IP->getDebugLoc(); -#if LLVM_VERSION_MAJOR >= 4 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - if (Loc) { - - DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); - - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); + if (!isInWhitelist(&F)) continue; - } - - } - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#else - if (!Loc.isUnknown()) { - - DILocation cDILoc(Loc.getAsMDNode(C)); - - unsigned int instLine = cDILoc.getLineNumber(); - StringRef instFilename = cDILoc.getFilename(); - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#endif - - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. */ - if (!instrumentBlock) continue; - - } + for (auto &BB : F) { for (auto &IN : BB) { diff --git a/llvm_mode/split-compares-pass.so.cc b/llvm_mode/split-compares-pass.so.cc index 7c657ebf..9c91e44f 100644 --- a/llvm_mode/split-compares-pass.so.cc +++ b/llvm_mode/split-compares-pass.so.cc @@ -46,6 +46,7 @@ #endif using namespace llvm; +#include "afl-llvm-common.h" namespace { @@ -55,40 +56,7 @@ class SplitComparesTransform : public ModulePass { static char ID; SplitComparesTransform() : ModulePass(ID) { - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); - getline(fileStream, line); - while (fileStream) { - - myWhitelist.push_back(line); - getline(fileStream, line); - - } - - } - - } - - static bool isBlacklisted(const Function *F) { - - static const char *Blacklist[] = { - - "asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign." - - }; - - for (auto const &BlacklistFunc : Blacklist) { - - if (F->getName().startswith(BlacklistFunc)) { return true; } - - } - - return false; + initWhitelist(); } @@ -105,8 +73,7 @@ class SplitComparesTransform : public ModulePass { } protected: - std::list<std::string> myWhitelist; - int be_quiet = 0; + int be_quiet = 0; private: int enableFPSplit; @@ -136,121 +103,10 @@ bool SplitComparesTransform::simplifyCompares(Module &M) { * all integer comparisons with >= and <= predicates to the icomps vector */ for (auto &F : M) { - if (isBlacklisted(&F)) continue; + if (!isInWhitelist(&F)) continue; for (auto &BB : F) { - if (!myWhitelist.empty()) { - - bool instrumentBlock = false; - - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - - /* Get the current location using debug information. - * For now, just instrument the block if we are not able - * to determine our location. */ - DebugLoc Loc = IP->getDebugLoc(); -#if LLVM_VERSION_MAJOR >= 4 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - if (Loc) { - - DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); - - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); - - } - - } - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#else - if (!Loc.isUnknown()) { - - DILocation cDILoc(Loc.getAsMDNode(C)); - - unsigned int instLine = cDILoc.getLineNumber(); - StringRef instFilename = cDILoc.getFilename(); - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#endif - - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. */ - if (!instrumentBlock) continue; - - } - for (auto &IN : BB) { CmpInst *selectcmpInst = nullptr; diff --git a/llvm_mode/split-switches-pass.so.cc b/llvm_mode/split-switches-pass.so.cc index 980dcb12..3444d6a1 100644 --- a/llvm_mode/split-switches-pass.so.cc +++ b/llvm_mode/split-switches-pass.so.cc @@ -49,6 +49,7 @@ #endif #include <set> +#include "afl-llvm-common.h" using namespace llvm; @@ -60,40 +61,7 @@ class SplitSwitchesTransform : public ModulePass { static char ID; SplitSwitchesTransform() : ModulePass(ID) { - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { - - std::string line; - std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); - getline(fileStream, line); - while (fileStream) { - - myWhitelist.push_back(line); - getline(fileStream, line); - - } - - } - - } - - static bool isBlacklisted(const Function *F) { - - static const char *Blacklist[] = { - - "asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign." - - }; - - for (auto const &BlacklistFunc : Blacklist) { - - if (F->getName().startswith(BlacklistFunc)) { return true; } - - } - - return false; + initWhitelist(); } @@ -125,8 +93,7 @@ class SplitSwitchesTransform : public ModulePass { typedef std::vector<CaseExpr> CaseVector; protected: - std::list<std::string> myWhitelist; - int be_quiet = 0; + int be_quiet = 0; private: bool splitSwitches(Module &M); @@ -346,122 +313,12 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { * all switches to switches vector for later processing */ for (auto &F : M) { - if (isBlacklisted(&F)) continue; + if (!isInWhitelist(&F)) continue; for (auto &BB : F) { SwitchInst *switchInst = nullptr; - if (!myWhitelist.empty()) { - - bool instrumentBlock = false; - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - - /* Get the current location using debug information. - * For now, just instrument the block if we are not able - * to determine our location. */ - DebugLoc Loc = IP->getDebugLoc(); -#if LLVM_VERSION_MAJOR >= 4 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7) - if (Loc) { - - DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode()); - - unsigned int instLine = cDILoc->getLine(); - StringRef instFilename = cDILoc->getFilename(); - - if (instFilename.str().empty()) { - - /* If the original location is empty, try using the inlined location - */ - DILocation *oDILoc = cDILoc->getInlinedAt(); - if (oDILoc) { - - instFilename = oDILoc->getFilename(); - instLine = oDILoc->getLine(); - - } - - } - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#else - if (!Loc.isUnknown()) { - - DILocation cDILoc(Loc.getAsMDNode(C)); - - unsigned int instLine = cDILoc.getLineNumber(); - StringRef instFilename = cDILoc.getFilename(); - - (void)instLine; - - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list<std::string>::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { - - /* We don't check for filename equality here because - * filenames might actually be full paths. Instead we - * check that the actual filename ends in the filename - * specified in the list. */ - if (instFilename.str().length() >= it->length()) { - - if (instFilename.str().compare( - instFilename.str().length() - it->length(), - it->length(), *it) == 0) { - - instrumentBlock = true; - break; - - } - - } - - } - - } - - } - -#endif - - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. */ - if (!instrumentBlock) continue; - - } - if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) { if (switchInst->getNumCases() < 1) continue; diff --git a/src/afl-common.c b/src/afl-common.c index 1dae8509..dda62219 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -67,10 +67,11 @@ char *afl_environment_variables[] = { "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES", - "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_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_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 @@ -917,7 +918,7 @@ u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms, } -u32 get_map_size() { +u32 get_map_size(void) { uint32_t map_size = MAP_SIZE; char * ptr; @@ -927,7 +928,8 @@ u32 get_map_size() { map_size = atoi(ptr); if (map_size < 8 || map_size > (1 << 29)) { - FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30", map_size); + FATAL("illegal AFL_MAP_SIZE %u, must be between %u and %u", map_size, 8, + 1 << 29); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 0c795f9c..d5a60077 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -53,7 +53,7 @@ /* Describe integer as memory size. */ -list_t fsrv_list = {.element_prealloc_count = 0}; +static list_t fsrv_list = {.element_prealloc_count = 0}; static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { @@ -67,7 +67,6 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { // this structure needs default so we initialize it if this was not done // already - fsrv->out_fd = -1; fsrv->out_dir_fd = -1; fsrv->dev_null_fd = -1; @@ -83,7 +82,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { /* exec related stuff */ fsrv->child_pid = -1; - fsrv->map_size = MAP_SIZE; + fsrv->map_size = get_map_size(); fsrv->use_fauxsrv = 0; fsrv->last_run_timed_out = 0; @@ -201,6 +200,44 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { } +/* Report on the error received via the forkserver controller and exit */ +static void report_error_and_exit(int error) { + + switch (error) { + + case FS_ERROR_MAP_SIZE: + FATAL( + "AFL_MAP_SIZE is not set and fuzzing target reports that the " + "required size is very large. Solution: Run the fuzzing target " + "stand-alone with the environment variable AFL_DEBUG=1 set and set " + "the value for __afl_final_loc in the AFL_MAP_SIZE environment " + "variable for afl-fuzz."); + break; + case FS_ERROR_MAP_ADDR: + FATAL( + "the fuzzing target reports that hardcoded map address might be the " + "reason the mmap of the shared memory failed. Solution: recompile " + "the target with either afl-clang-lto and the environment variable " + "AFL_LLVM_MAP_DYNAMIC set or recompile with afl-clang-fast."); + break; + case FS_ERROR_SHM_OPEN: + FATAL("the fuzzing target reports that the shm_open() call failed."); + break; + case FS_ERROR_SHMAT: + FATAL("the fuzzing target reports that the shmat() call failed."); + break; + case FS_ERROR_MMAP: + FATAL( + "the fuzzing target reports that the mmap() call to the share memory " + "failed."); + break; + default: + FATAL("unknown error code %u from fuzzing target!", error); + + } + +} + /* Spins up fork server (instrumented mode only). The idea is explained here: http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html @@ -400,6 +437,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { OKF("All right - fork server is up."); } + if ((status & FS_OPT_ERROR) == FS_OPT_ERROR) + report_error_and_exit(FS_OPT_GET_ERROR(status)); + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { if (!be_quiet && getenv("AFL_DEBUG")) { @@ -434,9 +474,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, FATAL( "Target's coverage map size of %u is larger than the one this " - "afl++ is set with (%u) (change MAP_SIZE_POW2 in config.h and " - "recompile or set AFL_MAP_SIZE)\n", - tmp_map_size, fsrv->map_size); + "afl++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart " + " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " + "afl-fuzz", + tmp_map_size, fsrv->map_size, tmp_map_size); } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 69fe6562..2289183c 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -721,7 +721,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #else snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir, - afl->unique_crashes, afl->kill_signal); + afl->unique_crashes, afl->last_kill_signal); #endif /* ^!SIMPLE_FILES */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 4dd31ac9..32481887 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1903,7 +1903,7 @@ void fix_up_sync(afl_state_t *afl) { static void handle_resize(int sig) { - LIST_FOREACH(&afl_states, afl_state_t, { el->clear_screen = 1; }); + afl_states_clear_screen(); } @@ -1954,14 +1954,7 @@ void check_asan_opts(void) { static void handle_stop_sig(int sig) { - LIST_FOREACH(&afl_states, afl_state_t, { - - el->stop_soon = 1; - - if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL); - if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL); - - }); + afl_states_stop(); } @@ -1969,7 +1962,7 @@ static void handle_stop_sig(int sig) { static void handle_skipreq(int sig) { - LIST_FOREACH(&afl_states, afl_state_t, { el->skip_requested = 1; }); + afl_states_request_skip(); } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index b38c9ec5..4f5389e3 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -71,7 +71,7 @@ static void init_mopt_globals(afl_state_t *afl) { /* A global pointer to all instances is needed (for now) for signals to arrive */ -list_t afl_states = {.element_prealloc_count = 0}; +static list_t afl_states = {.element_prealloc_count = 0}; /* Initializes an afl_state_t. */ @@ -81,7 +81,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { and out_size are NULL/0 by default. */ memset(afl, 0, sizeof(afl_state_t)); - if (!map_size) { afl->shm.map_size = MAP_SIZE; } + afl->shm.map_size = map_size ? map_size : MAP_SIZE; afl->w_init = 0.9; afl->w_end = 0.3; @@ -398,3 +398,34 @@ void afl_state_deinit(afl_state_t *afl) { } +void afl_states_stop(void) { + + /* We may be inside a signal handler. + Set flags first, send kill signals to child proceses later. */ + LIST_FOREACH(&afl_states, afl_state_t, { + + el->stop_soon = 1; + + }); + + LIST_FOREACH(&afl_states, afl_state_t, { + + if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL); + if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL); + + }); + +} + +void afl_states_clear_screen(void) { + + LIST_FOREACH(&afl_states, afl_state_t, { el->clear_screen = 1; }); + +} + +void afl_states_request_skip(void) { + + LIST_FOREACH(&afl_states, afl_state_t, { el->skip_requested = 1; }); + +} + diff --git a/src/afl-gcc.c b/src/afl-gcc.c index 6c6bd1f1..7eb01c0c 100644 --- a/src/afl-gcc.c +++ b/src/afl-gcc.c @@ -149,11 +149,16 @@ static void edit_params(u32 argc, char **argv) { u8 *alt_cxx = getenv("AFL_CXX"); cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"clang++"; - } else { + } else if (!strcmp(name, "afl-clang")) { u8 *alt_cc = getenv("AFL_CC"); cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"clang"; + } else { + + fprintf(stderr, "Name of the binary: %s\n", argv[0]); + FATAL("Name of the binary is not a known name, expected afl-clang(++)"); + } } else { @@ -166,13 +171,25 @@ static void edit_params(u32 argc, char **argv) { #ifdef __APPLE__ - if (!strcmp(name, "afl-g++")) + if (!strcmp(name, "afl-g++")) { + cc_params[0] = getenv("AFL_CXX"); - else if (!strcmp(name, "afl-gcj")) + + } else if (!strcmp(name, "afl-gcj")) { + cc_params[0] = getenv("AFL_GCJ"); - else + + } else if (!strcmp(name, "afl-gcc")) { + cc_params[0] = getenv("AFL_CC"); + } else { + + fprintf(stderr, "Name of the binary: %s\n", argv[0]); + FATAL("Name of the binary is not a known name, expected afl-gcc/g++/gcj"); + + } + if (!cc_params[0]) { SAYF("\n" cLRD "[-] " cRST @@ -199,11 +216,16 @@ static void edit_params(u32 argc, char **argv) { u8 *alt_cc = getenv("AFL_GCJ"); cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcj"; - } else { + } else if (!strcmp(name, "afl-gcc")) { u8 *alt_cc = getenv("AFL_CC"); cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcc"; + } else { + + fprintf(stderr, "Name of the binary: %s\n", argv[0]); + FATAL("Name of the binary is not a known name, expected afl-gcc/g++/gcj"); + } #endif /* __APPLE__ */ diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c index 90754b75..e024eb18 100644 --- a/src/afl-sharedmem.c +++ b/src/afl-sharedmem.c @@ -127,12 +127,12 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) { } /* map the shared memory segment to the address space of the process */ - shm->map = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, - map_size->g_shm_fd, 0); - if (map_size->map == MAP_FAILED) { + shm->map = + mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm->g_shm_fd, 0); + if (shm->map == MAP_FAILED) { - close(map_size->g_shm_fd); - map_size->g_shm_fd = -1; + close(shm->g_shm_fd); + shm->g_shm_fd = -1; PFATAL("mmap() failed"); } diff --git a/test/test-compcov.c b/test/test-compcov.c index f1743265..c8dd674e 100644 --- a/test/test-compcov.c +++ b/test/test-compcov.c @@ -25,11 +25,10 @@ int main(int argc, char **argv) { printf("your string was bugmenot\n"); else if (strcmp(input, "BUFFEROVERFLOW") == 0) { - buf = malloc(16); + buf = (char *)malloc(16); strcpy(buf, "TEST"); strcat(buf, input); printf("This will only crash with libdislocator: %s\n", buf); - return 0; } else if (*(unsigned int *)input == 0xabadcafe) diff --git a/test/test.sh b/test/test.sh index 5af35ec3..b8d4208f 100755 --- a/test/test.sh +++ b/test/test.sh @@ -951,7 +951,15 @@ test "1" = "`../afl-fuzz | grep -i 'without python' >/dev/null; echo $?`" && { test -e test-custom-mutator.c -a -e ${CUSTOM_MUTATOR_PATH}/example.c -a -e ${CUSTOM_MUTATOR_PATH}/example.py && { unset AFL_CC # Compile the vulnerable program - ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 + test -e ../afl-clang-fast && { + ../afl-clang-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 + } || { + test -e ../afl-gcc-fast && { + ../afl-gcc-fast -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 + } || { + ../afl-gcc -o test-custom-mutator test-custom-mutator.c > /dev/null 2>&1 + } + } # Compile the custom mutator make -C ../examples/custom_mutators libexamplemutator.so > /dev/null 2>&1 test -e test-custom-mutator -a -e ${CUSTOM_MUTATOR_PATH}/libexamplemutator.so && { diff --git a/test/travis/bionic/Dockerfile b/test/travis/bionic/Dockerfile new file mode 100644 index 00000000..3883f775 --- /dev/null +++ b/test/travis/bionic/Dockerfile @@ -0,0 +1,43 @@ +# This is the Dockerfile for testing problems in Travis build +# configuration #1. +# This needs not to be rebuild everytime, most of the time it needs just to +# be build once and then started when debugging issues and execute: +# cd /AFLplusplus/ +# git pull +# make distrib +# +FROM ubuntu:bionic +LABEL "about"="travis image 1" +RUN apt-get update && apt-get -y install \ + automake \ + bison \ + build-essential \ + clang \ + flex \ + git \ + python3.7 python3.7-dev \ + libtool libtool-bin \ + libglib2.0-dev \ + python-setuptools \ + wget \ + ca-certificates \ + libpixman-1-dev \ + gcc-7 gcc-7-plugin-dev libc++-7-dev \ + findutils \ + libcmocka-dev \ + joe nano vim locate \ + && rm -rf /var/lib/apt/lists/* + +ENV AFL_NO_UI=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 + +RUN cd / && \ + git clone https://github.com/AFLplusplus/AFLplusplus && \ + cd AFLplusplus && \ + git checkout dev && \ + cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \ + cd ../unicorn_mode && git submodule init && git submodule update || true && \ + cd /AFLplusplus && ASAN_BUILD=1 make source-only || true + +WORKDIR /AFLplusplus +CMD ["/bin/bash"] diff --git a/test/travis/trusty/Dockerfile b/test/travis/trusty/Dockerfile new file mode 100644 index 00000000..7b86f3e7 --- /dev/null +++ b/test/travis/trusty/Dockerfile @@ -0,0 +1,48 @@ +# This is the Dockerfile for testing problems in Travis builds +# configuration #3. +# This needs not to be rebuild everytime, most of the time it needs just to +# be build once and then started when debugging issues and execute: +# cd /AFLplusplus/ +# git pull +# make distrib +# +FROM ubuntu:trusty +LABEL "about"="travis image 3" +RUN apt-get update && apt-get -y install \ + automake \ + bison \ + build-essential \ + clang \ + flex \ + git \ + python2.7 python2.7-dev \ + libtool \ + libglib2.0-dev \ + python-setuptools \ + wget \ + ca-certificates \ + libpixman-1-dev \ + gcc-4.8 gcc-4.8-plugin-dev \ + libc++-dev \ + findutils \ + libcmocka-dev \ + joe nano vim locate \ + && rm -rf /var/lib/apt/lists/* + +ENV TERM linux +ENV DEBIAN_FRONTEND noninteractive +ENV LLVM_CONFIG=llvm-config-3.4 +ENV AFL_NO_UI=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 + +RUN cd / && \ + git clone https://github.com/AFLplusplus/AFLplusplus && \ + cd AFLplusplus && \ + git checkout dev && \ + cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \ + cd ../unicorn_mode && git submodule init && git submodule update || true && \ + cd /AFLplusplus && ASAN_BUILD=1 make source-only || true + +WORKDIR /AFLplusplus +CMD ["/bin/bash"] + diff --git a/test/travis/xenial/Dockerfile b/test/travis/xenial/Dockerfile new file mode 100644 index 00000000..a5f8d359 --- /dev/null +++ b/test/travis/xenial/Dockerfile @@ -0,0 +1,45 @@ +# This is the Dockerfile for testing problems in Travis builds +# configuration #2. +# This needs not to be rebuild everytime, most of the time it needs just to +# be build once and then started when debugging issues and execute: +# cd /AFLplusplus/ +# git pull +# make distrib +# +FROM ubuntu:xenial +LABEL "about"="travis image 2" +RUN apt-get update && apt-get -y install \ + automake \ + bison \ + build-essential \ + clang-6.0 \ + flex \ + git \ + python3 python3-dev \ + libtool libtool-bin \ + libglib2.0-dev \ + python-setuptools \ + wget \ + ca-certificates \ + libpixman-1-dev \ + gcc-5 gcc-5-plugin-dev \ + libc++-dev \ + findutils \ + libcmocka-dev \ + joe nano vim locate \ + && rm -rf /var/lib/apt/lists/* + +ENV LLVM_CONFIG=llvm-config-6.0 +ENV AFL_NO_UI=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 + +RUN cd / && \ + git clone https://github.com/AFLplusplus/AFLplusplus && \ + cd AFLplusplus && \ + git checkout dev && \ + cd qemu_mode && wget http://download.qemu-project.org/qemu-3.1.1.tar.xz && \ + cd ../unicorn_mode && git submodule init && git submodule update || true && \ + cd /AFLplusplus && ASAN_BUILD=1 make source-only || true + +WORKDIR /AFLplusplus +CMD ["/bin/bash"] diff --git a/test/unittests/unit_list.c b/test/unittests/unit_list.c index 90700a11..df4864e4 100644 --- a/test/unittests/unit_list.c +++ b/test/unittests/unit_list.c @@ -40,7 +40,7 @@ int __wrap_printf(const char *format, ...) { return 1; } -list_t testlist; +static list_t testlist = {.element_prealloc_count = 0}; static void test_contains(void **state) { diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index b2ac48f9..965d7614 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -107,7 +107,7 @@ for i in $PYTHONBIN automake autoconf git $MAKECMD $TARCMD; do done -if ! type $EASY_INSTALL > /dev/null; then +if ! command -v $EASY_INSTALL >/dev/null; then # work around for installs with executable easy_install EASY_INSTALL_FOUND=0 @@ -123,7 +123,7 @@ if ! type $EASY_INSTALL > /dev/null; then fi done - if [ '!' $EASY_INSTALL_FOUND ]; then + if [ "0" = $EASY_INSTALL_FOUND ]; then echo "[-] Error: Python setup-tools not found. Run 'sudo apt-get install python-setuptools'." PREREQ_NOTFOUND=1 @@ -182,7 +182,8 @@ echo "[+] Configuration complete." echo "[*] Attempting to build unicornafl (fingers crossed!)..." $MAKECMD clean # make doesn't seem to work for unicorn -UNICORN_QEMU_FLAGS="--python=$PYTHONBIN" $MAKECMD -j$CORES || exit 1 +# Fixed to 1 core for now as there is a race condition in the makefile +UNICORN_QEMU_FLAGS="--python=$PYTHONBIN" $MAKECMD -j1 || exit 1 echo "[+] Build process successful!" |