aboutsummaryrefslogtreecommitdiff
path: root/llvm_mode
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-06-09 19:25:09 +0200
committerGitHub <noreply@github.com>2020-06-09 19:25:09 +0200
commit12bdefe00e38cdc3dd8cb028eeac325ab2e94e16 (patch)
tree0d321d362a19ff19a4a98dcd1b9b72601945695f /llvm_mode
parent748238d6ab4aeb7f34958d4c37c5ef200ad22463 (diff)
parent81829d132bebcb42c0e289bb5788b8f2b29c1599 (diff)
downloadafl++-12bdefe00e38cdc3dd8cb028eeac325ab2e94e16.tar.gz
Merge pull request #392 from AFLplusplus/dev
Push to master
Diffstat (limited to 'llvm_mode')
-rw-r--r--llvm_mode/GNUmakefile27
-rw-r--r--llvm_mode/README.lto.md76
-rw-r--r--llvm_mode/README.persistent_mode.md2
-rw-r--r--llvm_mode/README.whitelist.md4
-rw-r--r--llvm_mode/afl-clang-fast.c9
-rw-r--r--llvm_mode/afl-ld-lto.c358
-rw-r--r--llvm_mode/afl-llvm-common.cc19
-rw-r--r--llvm_mode/afl-llvm-lto-whitelist.so.cc6
-rw-r--r--llvm_mode/afl-llvm-rt.o.c90
9 files changed, 546 insertions, 45 deletions
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index 50a6be2b..ca1e8e08 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -68,7 +68,7 @@ endif
ifeq "$(LLVM_MAJOR)" "11"
$(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
LLVM_LTO = 1
- TEST_MMAP = 1
+ #TEST_MMAP = 1
endif
ifeq "$(LLVM_LTO)" "0"
@@ -226,13 +226,17 @@ endif
ifeq "$(shell uname)" "OpenBSD"
CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so
+ CLANG_CFL += -mno-retpoline
+ CFLAGS += -mno-retpoline
+ # Needed for unwind symbols
+ LDFLAGS += -lc++abi
endif
ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 ; rm -f .test2 )" "1"
SHMAT_OK=1
else
SHMAT_OK=0
- CFLAGS+=-DUSEMMAP=1
+ #CFLAGS+=-DUSEMMAP=1
LDFLAGS += -Wno-deprecated-declarations
endif
@@ -242,7 +246,7 @@ ifeq "$(TEST_MMAP)" "1"
LDFLAGS += -Wno-deprecated-declarations
endif
- PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.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
+ PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.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
# If prerequisites are not given, warn, do not build anything, and exit with code 0
ifeq "$(LLVMVER)" ""
@@ -300,7 +304,7 @@ afl-common.o: ../src/afl-common.c
$(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS)
../afl-clang-fast: afl-clang-fast.c afl-common.o | test_deps
- $(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\" -Dxxx
+ $(CC) $(CFLAGS) $< afl-common.o -o $@ $(LDFLAGS) -DCFLAGS_OPT=\"$(CFLAGS_OPT)\"
ln -sf afl-clang-fast ../afl-clang-fast++
ifneq "$(AFL_CLANG_FLTO)" ""
ifeq "$(LLVM_LTO)" "1"
@@ -326,6 +330,11 @@ ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
endif
+../afl-ld-lto: afl-ld-lto.c
+ifeq "$(LLVM_LTO)" "1"
+ $(CC) $(CFLAGS) $< -o $@
+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
@@ -354,16 +363,21 @@ endif
../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
+document:
+ $(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o
+ @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) -Wno-unused-result -m32 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-32.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+ @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS) -Wno-unused-result -m64 -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt-64.o 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+
../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@
../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
- @$(CC_SAVE) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+ @$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
- @$(CC_SAVE) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+ @$(CLANG_BIN) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
@@ -383,6 +397,7 @@ install: all
install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-lto-instrim.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
+ if [ -f ../afl-ld-lto ]; then set -e; install -m 755 ../afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md
index 48c587eb..517cb62a 100644
--- a/llvm_mode/README.lto.md
+++ b/llvm_mode/README.lto.md
@@ -14,9 +14,11 @@ This version requires a current llvm 11 compiled from the github master.
4. AUTODICTIONARY feature! see below
-5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib` also
- note that if that target uses _init functions or early constructors then
- also set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise
+5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`.
+ Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`.
+
+6. If a target uses _init functions or early constructors then additionally
+ set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise!
## Introduction and problem description
@@ -61,7 +63,8 @@ AUTODICTIONARY: 11 strings found
## Getting llvm 11
-### Installing llvm 11
+### Installing llvm 11 from the llvm repository
+
Installing the llvm snapshot builds is easy and mostly painless:
In the follow line change `NAME` for your Debian or Ubuntu release name
@@ -80,7 +83,7 @@ apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
```
-### Building llvm 11
+### Building llvm 11 yourself
Building llvm from github takes quite some long time and is not painless:
```
@@ -117,6 +120,9 @@ export AFL_LLVM_INSTRUMENT=CFG
make
```
+NOTE: some targets also need to set the linker, try both `afl-clang-lto` and
+`afl-ld-lto` for this for `LD=` for `configure`.
+
## AUTODICTIONARY feature
Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the
@@ -135,6 +141,51 @@ 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).
+## Solving difficult targets
+
+Some targets are difficult because the configure script does unusual stuff that
+is unexpected for afl. See the next chapter `Potential issues` how to solve
+these.
+
+An example of a hard to solve target is ffmpeg. Here is how to successfully
+instrument it:
+
+1. Get and extract the current ffmpeg and change to it's directory
+
+2. Running configure with --cc=clang fails and various other items will fail
+ when compiling, so we have to trick configure:
+
+```
+./configure --enable-lto --disable-shared
+```
+
+3. Now the configuration is done - and we edit the settings in `./ffbuild/config.mak`
+ (-: the original line, +: what to change it into):
+```
+-CC=gcc
++CC=afl-clang-lto
+-CXX=g++
++CXX=afl-clang-lto++
+-AS=gcc
++AS=llvm-as
+-LD=gcc
++LD=afl-clang-lto++
+-DEPCC=gcc
++DEPCC=afl-clang-lto
+-DEPAS=gcc
++DEPAS=afl-clang-lto++
+-AR=ar
++AR=llvm-ar
+-AR_CMD=ar
++AR_CMD=llvm-ar
+-NM_CMD=nm -g
++NM_CMD=llvm-nm -g
+-RANLIB=ranlib -D
++RANLIB=llvm-ranlib -D
+```
+
+4. Then type make, wait for a long time and you are done :)
+
## Potential issues
### compiling libraries fails
@@ -154,6 +205,16 @@ and on some target you have to to AR=/RANLIB= even for make as the configure scr
Other targets ignore environment variables and need the parameters set via
`./configure --cc=... --cxx= --ranlib= ...` etc. (I am looking at you ffmpeg!).
+
+If you see this message
+```
+assembler command failed ...
+```
+then try setting `llvm-as` for configure:
+```
+AS=llvm-as ...
+```
+
### compiling programs still fail
afl-clang-lto is still work in progress.
@@ -166,11 +227,12 @@ 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`).
-An example that does not build with llvm 11 and LTO is ffmpeg.
-
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)
+Even some targets where clang-11 fails can be build if the fail is just in
+`./configure`, see `Solving difficult targets` above.
+
### Target crashes immediately
If the target is using early constructors (priority values smaller than 6)
diff --git a/llvm_mode/README.persistent_mode.md b/llvm_mode/README.persistent_mode.md
index 7aae8faa..83cc7f4d 100644
--- a/llvm_mode/README.persistent_mode.md
+++ b/llvm_mode/README.persistent_mode.md
@@ -55,7 +55,7 @@ The speed increase is usually x10 to x20.
## 3) deferred initialization
AFL tries to optimize performance by executing the targeted binary just once,
-stopping it just before main(), and then cloning this "master" process to get
+stopping it just before main(), and then cloning this "main" process to get
a steady supply of targets to fuzz.
Although this approach eliminates much of the OS-, linker- and libc-level
diff --git a/llvm_mode/README.whitelist.md b/llvm_mode/README.whitelist.md
index 72fb5d09..6393fae8 100644
--- a/llvm_mode/README.whitelist.md
+++ b/llvm_mode/README.whitelist.md
@@ -73,3 +73,7 @@ For old LLVM versions this feature might require to be compiled with debug
information (-g), however at least from llvm version 6.0 onwards this is not
required anymore (and might hurt performance and crash detection, so better not
use -g).
+
+## 4) UNIX-style filename pattern matching
+You can add UNIX-style pattern matching in the whitelist entries. See `man
+fnmatch` for the syntax. We do not set any of the `fnmatch` flags.
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index 0b081ae6..75504ea5 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -176,7 +176,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
"Using afl-clang-lto is not possible because Makefile magic did not "
"identify the correct -flto flag");
- if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++")) {
+ if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++") ||
+ !strcmp(name, "afl-clang++")) {
u8 *alt_cxx = getenv("AFL_CXX");
if (USE_BINDIR)
@@ -188,7 +189,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} else if (!strcmp(name, "afl-clang-fast") ||
- !strcmp(name, "afl-clang-lto")) {
+ !strcmp(name, "afl-clang-lto") || !strcmp(name, "afl-clang")) {
u8 *alt_cc = getenv("AFL_CC");
if (USE_BINDIR)
@@ -494,14 +495,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] =
"-D__AFL_FUZZ_INIT()="
"int __afl_sharedmem_fuzzing = 1;"
- "extern unsigned int __afl_fuzz_len;"
+ "extern unsigned int *__afl_fuzz_len;"
"extern unsigned char *__afl_fuzz_ptr;"
"unsigned char *__afl_fuzz_alt_ptr;";
cc_params[cc_par_cnt++] =
"-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
"(__afl_fuzz_alt_ptr = malloc(1 * 1024 * 1024)))";
cc_params[cc_par_cnt++] =
- "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? __afl_fuzz_len : read(0, "
+ "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : read(0, "
"__afl_fuzz_alt_ptr, 1 * 1024 * 1024))";
cc_params[cc_par_cnt++] =
diff --git a/llvm_mode/afl-ld-lto.c b/llvm_mode/afl-ld-lto.c
new file mode 100644
index 00000000..1b59bb4a
--- /dev/null
+++ b/llvm_mode/afl-ld-lto.c
@@ -0,0 +1,358 @@
+/*
+ american fuzzy lop++ - wrapper for llvm 11+ lld
+ -----------------------------------------------
+
+ Written by Marc Heuse <mh@mh-sec.de> for afl++
+
+ Maintained by Marc Heuse <mh@mh-sec.de>,
+ Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
+ Andrea Fioraldi <andreafioraldi@gmail.com>
+ Dominik Maier <domenukk@gmail.com>
+
+ 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
+
+ The sole purpose of this wrapper is to preprocess clang LTO files when
+ linking with lld and performing the instrumentation on the whole program.
+
+*/
+
+#define AFL_MAIN
+#define _GNU_SOURCE
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+
+#include <dirent.h>
+
+#define MAX_PARAM_COUNT 4096
+
+static u8 **ld_params; /* Parameters passed to the real 'ld' */
+
+static u8 *afl_path = AFL_PATH;
+static u8 *real_ld = AFL_REAL_LD;
+
+static u8 be_quiet, /* Quiet mode (no stderr output) */
+ debug, /* AFL_DEBUG */
+ passthrough, /* AFL_LD_PASSTHROUGH - no link+optimize*/
+ just_version; /* Just show version? */
+
+static u32 ld_param_cnt = 1; /* Number of params to 'ld' */
+
+/* Examine and modify parameters to pass to 'ld', 'llvm-link' and 'llmv-ar'.
+ Note that the file name is always the last parameter passed by GCC,
+ so we exploit this property to keep the code "simple". */
+static void edit_params(int argc, char **argv) {
+
+ u32 i, instrim = 0, gold_pos = 0, gold_present = 0, rt_present = 0,
+ rt_lto_present = 0, inst_present = 0;
+ char *ptr;
+
+ ld_params = ck_alloc(4096 * sizeof(u8 *));
+
+ ld_params[0] = (u8 *)real_ld;
+
+ if (!passthrough) {
+
+ for (i = 1; i < argc; i++) {
+
+ if (strstr(argv[i], "/afl-llvm-rt-lto.o") != NULL) rt_lto_present = 1;
+ if (strstr(argv[i], "/afl-llvm-rt.o") != NULL) rt_present = 1;
+ if (strstr(argv[i], "/afl-llvm-lto-instr") != NULL) inst_present = 1;
+
+ }
+
+ for (i = 1; i < argc && !gold_pos; i++) {
+
+ if (strcmp(argv[i], "-plugin") == 0) {
+
+ if (strncmp(argv[i], "-plugin=", strlen("-plugin=")) == 0) {
+
+ if (strcasestr(argv[i], "LLVMgold.so") != NULL)
+ gold_present = gold_pos = i + 1;
+
+ } else if (i < argc && strcasestr(argv[i + 1], "LLVMgold.so") != NULL) {
+
+ gold_present = gold_pos = i + 2;
+
+ }
+
+ }
+
+ }
+
+ if (!gold_pos) {
+
+ for (i = 1; i + 1 < argc && !gold_pos; i++) {
+
+ if (argv[i][0] != '-') {
+
+ if (argv[i - 1][0] == '-') {
+
+ switch (argv[i - 1][1]) {
+
+ case 'b':
+ break;
+ case 'd':
+ break;
+ case 'e':
+ break;
+ case 'F':
+ break;
+ case 'f':
+ break;
+ case 'I':
+ break;
+ case 'l':
+ break;
+ case 'L':
+ break;
+ case 'm':
+ break;
+ case 'o':
+ break;
+ case 'O':
+ break;
+ case 'p':
+ if (index(argv[i - 1], '=') == NULL) gold_pos = i;
+ break;
+ case 'R':
+ break;
+ case 'T':
+ break;
+ case 'u':
+ break;
+ case 'y':
+ break;
+ case 'z':
+ break;
+ case '-': {
+
+ if (strcmp(argv[i - 1], "--oformat") == 0) break;
+ if (strcmp(argv[i - 1], "--output") == 0) break;
+ if (strncmp(argv[i - 1], "--opt-remarks-", 14) == 0) break;
+ gold_pos = i;
+ break;
+
+ }
+
+ default:
+ gold_pos = i;
+
+ }
+
+ } else
+
+ gold_pos = i;
+
+ }
+
+ }
+
+ }
+
+ if (!gold_pos) gold_pos = 1;
+
+ }
+
+ if (getenv("AFL_LLVM_INSTRIM"))
+ instrim = 1;
+ else if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) &&
+ (strcasestr(ptr, "CFG") == 0 || strcasestr(ptr, "INSTRIM") == 0))
+ instrim = 1;
+
+ if (debug)
+ SAYF(cMGN "[D] " cRST
+ "passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s "
+ "inst_present=%s rt_present=%s rt_lto_present=%s\n",
+ passthrough ? "true" : "false", instrim, gold_pos,
+ gold_present ? "true" : "false", inst_present ? "true" : "false",
+ rt_present ? "true" : "false", rt_lto_present ? "true" : "false");
+
+ for (i = 1; i < argc; i++) {
+
+ if (ld_param_cnt >= MAX_PARAM_COUNT)
+ FATAL(
+ "Too many command line parameters because of unpacking .a archives, "
+ "this would need to be done by hand ... sorry! :-(");
+
+ if (strcmp(argv[i], "--afl") == 0) {
+
+ if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
+ exit(0);
+
+ }
+
+ if (i == gold_pos && !passthrough) {
+
+ ld_params[ld_param_cnt++] = alloc_printf("-L%s/../lib", LLVM_BINDIR);
+
+ if (!gold_present) {
+
+ ld_params[ld_param_cnt++] = "-plugin";
+ ld_params[ld_param_cnt++] =
+ alloc_printf("%s/../lib/LLVMgold.so", LLVM_BINDIR);
+
+ }
+
+ ld_params[ld_param_cnt++] = "--allow-multiple-definition";
+
+ if (!inst_present) {
+
+ if (instrim)
+ ld_params[ld_param_cnt++] =
+ alloc_printf("-mllvm=-load=%s/afl-llvm-lto-instrim.so", afl_path);
+ else
+ ld_params[ld_param_cnt++] = alloc_printf(
+ "-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", afl_path);
+
+ }
+
+ if (!rt_present)
+ ld_params[ld_param_cnt++] = alloc_printf("%s/afl-llvm-rt.o", afl_path);
+ if (!rt_lto_present)
+ ld_params[ld_param_cnt++] =
+ alloc_printf("%s/afl-llvm-rt-lto.o", afl_path);
+
+ }
+
+ ld_params[ld_param_cnt++] = argv[i];
+
+ }
+
+ ld_params[ld_param_cnt] = NULL;
+
+}
+
+/* Main entry point */
+
+int main(int argc, char **argv) {
+
+ s32 pid, i, status;
+ u8 * ptr;
+ char thecwd[PATH_MAX];
+
+ if ((ptr = getenv("AFL_LD_CALLER")) != NULL) {
+
+ FATAL("ld loop detected! Set AFL_REAL_LD!\n");
+
+ }
+
+ if (isatty(2) && !getenv("AFL_QUIET") && !getenv("AFL_DEBUG")) {
+
+ SAYF(cCYA "afl-ld-to" VERSION cRST
+ " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
+
+ } else
+
+ be_quiet = 1;
+
+ if (getenv("AFL_DEBUG") != NULL) debug = 1;
+ if (getenv("AFL_PATH") != NULL) afl_path = getenv("AFL_PATH");
+ if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1;
+ if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD");
+
+ if (!afl_path || !*afl_path) afl_path = "/usr/local/lib/afl";
+
+ setenv("AFL_LD_CALLER", "1", 1);
+
+ if (debug) {
+
+ (void)getcwd(thecwd, sizeof(thecwd));
+
+ SAYF(cMGN "[D] " cRST "cd \"%s\";", thecwd);
+ for (i = 0; i < argc; i++)
+ SAYF(" \"%s\"", argv[i]);
+ SAYF("\n");
+
+ }
+
+ if (argc < 2) {
+
+ SAYF(
+ "\n"
+ "This is a helper application for afl-clang-lto. It is a wrapper "
+ "around GNU "
+ "llvm's 'lld',\n"
+ "executed by the toolchain whenever using "
+ "afl-clang-lto/afl-clang-lto++.\n"
+ "You probably don't want to run this program directly but rather pass "
+ "it as LD parameter to configure scripts\n\n"
+
+ "Environment variables:\n"
+ " AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n"
+ " AFL_REAL_LD point to the real llvm 11 lld if necessary\n"
+
+ "\nafl-ld-to was compiled with the fixed real 'ld' of %s and the "
+ "binary path of %s\n\n",
+ real_ld, LLVM_BINDIR);
+
+ exit(1);
+
+ }
+
+ edit_params(argc, argv); // here most of the magic happens :-)
+
+ if (debug) {
+
+ SAYF(cMGN "[D]" cRST " cd \"%s\";", thecwd);
+ for (i = 0; i < ld_param_cnt; i++)
+ SAYF(" \"%s\"", ld_params[i]);
+ SAYF("\n");
+
+ }
+
+ if (!(pid = fork())) {
+
+ if (strlen(real_ld) > 1) execvp(real_ld, (char **)ld_params);
+ execvp("ld", (char **)ld_params); // fallback
+ FATAL("Oops, failed to execute 'ld' - check your PATH");
+
+ }
+
+ if (pid < 0) PFATAL("fork() failed");
+
+ if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
+ if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status);
+
+ if (!just_version) {
+
+ if (status == 0) {
+
+ if (!be_quiet) OKF("Linker was successful");
+
+ } else {
+
+ SAYF(cLRD "[-] " cRST
+ "Linker failed, please investigate and send a bug report. Most "
+ "likely an 'ld' option is incompatible with %s.\n",
+ AFL_CLANG_FLTO);
+
+ }
+
+ }
+
+ exit(WEXITSTATUS(status));
+
+}
+
diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc
index 35eabbf0..6c7222cd 100644
--- a/llvm_mode/afl-llvm-common.cc
+++ b/llvm_mode/afl-llvm-common.cc
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
+#include <fnmatch.h>
#include <list>
#include <string>
@@ -152,12 +153,13 @@ bool isInWhitelist(llvm::Function *F) {
/* 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. */
+ * specified in the list. We also allow UNIX-style pattern
+ * matching */
+
if (instFilename.str().length() >= it->length()) {
- if (instFilename.str().compare(
- instFilename.str().length() - it->length(), it->length(),
- *it) == 0) {
+ if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
+ 0) {
return true;
@@ -189,12 +191,13 @@ bool isInWhitelist(llvm::Function *F) {
/* 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. */
+ * specified in the list. We also allow UNIX-style pattern
+ * matching */
+
if (instFilename.str().length() >= it->length()) {
- if (instFilename.str().compare(
- instFilename.str().length() - it->length(), it->length(),
- *it) == 0) {
+ if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
+ 0) {
return true;
diff --git a/llvm_mode/afl-llvm-lto-whitelist.so.cc b/llvm_mode/afl-llvm-lto-whitelist.so.cc
index 8856ce21..33d40da8 100644
--- a/llvm_mode/afl-llvm-lto-whitelist.so.cc
+++ b/llvm_mode/afl-llvm-lto-whitelist.so.cc
@@ -36,6 +36,7 @@
#include <string>
#include <fstream>
#include <sys/time.h>
+#include <fnmatch.h>
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/BasicBlock.h"
@@ -175,9 +176,8 @@ bool AFLwhitelist::runOnModule(Module &M) {
* specified in the list. */
if (instFilename.str().length() >= it->length()) {
- if (instFilename.str().compare(
- instFilename.str().length() - it->length(), it->length(),
- *it) == 0) {
+ if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
+ 0) {
instrumentFunction = true;
break;
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index 3a0584e4..702384a3 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -74,10 +74,11 @@ u8 __afl_area_initial[MAP_INITIAL_SIZE];
#else
u8 __afl_area_initial[MAP_SIZE];
#endif
-u8 *__afl_area_ptr = __afl_area_initial;
-u8 *__afl_dictionary;
-u8 *__afl_fuzz_ptr;
-u32 __afl_fuzz_len;
+u8 * __afl_area_ptr = __afl_area_initial;
+u8 * __afl_dictionary;
+u8 * __afl_fuzz_ptr;
+u32 __afl_fuzz_len_dummy;
+u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy;
u32 __afl_final_loc;
u32 __afl_map_size = MAP_SIZE;
@@ -121,6 +122,8 @@ static void __afl_map_shm_fuzz() {
if (id_str) {
+ u8 *map = NULL;
+
#ifdef USEMMAP
const char * shm_file_path = id_str;
int shm_fd = -1;
@@ -136,27 +139,32 @@ static void __afl_map_shm_fuzz() {
}
- __afl_fuzz_ptr = mmap(0, MAX_FILE, PROT_READ, MAP_SHARED, shm_fd, 0);
+ map = (u8 *)mmap(0, MAX_FILE, PROT_READ, MAP_SHARED, shm_fd, 0);
#else
u32 shm_id = atoi(id_str);
-
- __afl_fuzz_ptr = shmat(shm_id, NULL, 0);
+ map = (u8 *)shmat(shm_id, NULL, 0);
#endif
/* Whooooops. */
- if (__afl_fuzz_ptr == (void *)-1) {
+ if (!map || map == (void *)-1) {
- fprintf(stderr, "Error: could not access fuzzing shared memory\n");
+ perror("Could not access fuzzign shared memory");
exit(1);
}
- if (getenv("AFL_DEBUG"))
+ __afl_fuzz_len = (u32 *)map;
+ __afl_fuzz_ptr = (u8 *)(map + sizeof(u32));
+
+ if (getenv("AFL_DEBUG")) {
+
fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n");
+ }
+
} else {
fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
@@ -308,6 +316,10 @@ static void __afl_map_shm(void) {
id_str = getenv(CMPLOG_SHM_ENV_VAR);
+ if (getenv("AFL_DEBUG"))
+ fprintf(stderr, "DEBUG: cmplog id_str %s\n",
+ id_str == NULL ? "<null>" : id_str);
+
if (id_str) {
#ifdef USEMMAP
@@ -420,7 +432,7 @@ static void __afl_start_snapshots(void) {
} else {
- // uh this forkserver master does not understand extended option passing
+ // uh this forkserver does not understand extended option passing
// or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1;
@@ -443,8 +455,31 @@ static void __afl_start_snapshots(void) {
}
- __afl_fuzz_len = (was_killed >> 8);
- was_killed = (was_killed & 0xff);
+ #ifdef _AFL_DOCUMENT_MUTATIONS
+ if (__afl_fuzz_ptr) {
+
+ static uint32_t counter = 0;
+ char fn[32];
+ sprintf(fn, "%09u:forkserver", counter);
+ s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd_doc >= 0) {
+
+ if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
+
+ fprintf(stderr, "write of mutation file failed: %s\n", fn);
+ unlink(fn);
+
+ }
+
+ close(fd_doc);
+
+ }
+
+ counter++;
+
+ }
+
+ #endif
/* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old
@@ -596,7 +631,7 @@ static void __afl_start_forkserver(void) {
} else {
- // uh this forkserver master does not understand extended option passing
+ // uh this forkserver does not understand extended option passing
// or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1;
@@ -620,8 +655,31 @@ static void __afl_start_forkserver(void) {
}
- __afl_fuzz_len = (was_killed >> 8);
- was_killed = (was_killed & 0xff);
+#ifdef _AFL_DOCUMENT_MUTATIONS
+ if (__afl_fuzz_ptr) {
+
+ static uint32_t counter = 0;
+ char fn[32];
+ sprintf(fn, "%09u:forkserver", counter);
+ s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd_doc >= 0) {
+
+ if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
+
+ fprintf(stderr, "write of mutation file failed: %s\n", fn);
+ unlink(fn);
+
+ }
+
+ close(fd_doc);
+
+ }
+
+ counter++;
+
+ }
+
+#endif
/* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old