aboutsummaryrefslogtreecommitdiff
path: root/llvm_mode
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_mode')
-rw-r--r--llvm_mode/GNUmakefile13
-rw-r--r--llvm_mode/README.instrument_file.md81
-rw-r--r--llvm_mode/README.instrument_list.md86
-rw-r--r--llvm_mode/README.lto.md25
-rw-r--r--llvm_mode/README.md2
-rw-r--r--llvm_mode/README.persistent_mode.md27
-rw-r--r--llvm_mode/afl-clang-fast.c54
-rw-r--r--llvm_mode/afl-llvm-common.cc487
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc111
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentlist.so.cc156
-rw-r--r--llvm_mode/afl-llvm-rt.o.c47
11 files changed, 744 insertions, 345 deletions
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index a030b910..0fa9b12e 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -387,20 +387,20 @@ endif
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o
document:
- $(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) -O3 -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o
- @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) -O3 -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_SAFE) -O3 -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
+ $(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c afl-llvm-rt.o.c -o ../afl-llvm-rt.o
+ @$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CLANG_CFL) -O3 -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_SAFE) $(CLANG_CFL) -O3 -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_SAFE) -O3 -Wno-unused-result -fPIC -c $< -o $@
+ $(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) -O3 -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)... "
- @$(CLANG_BIN) $(CFLAGS_SAFE) -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+ @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) -O3 -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)... "
- @$(CLANG_BIN) $(CFLAGS_SAFE) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+ @$(CLANG_BIN) $(CLANG_CFL) $(CFLAGS_SAFE) -O3 -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..."
@@ -427,6 +427,7 @@ install: all
if [ -f ../split-compares-pass.so ]; then set -e; install -m 755 ../split-compares-pass.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../split-switches-pass.so ]; then set -e; install -m 755 ../split-switches-pass.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../cmplog-instructions-pass.so ]; then set -e; install -m 755 ../cmplog-*-pass.so $${DESTDIR}$(HELPER_PATH); fi
+ set -e; install -m 644 ../dynamic_list.txt $${DESTDIR}$(HELPER_PATH)
set -e; if [ -f ../afl-clang-fast ] ; then ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang++ ; else ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ../afl-gcc $${DESTDIR}$(BIN_PATH)/afl-clang++; fi
install -m 644 README.*.md $${DESTDIR}$(DOC_PATH)/
install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.llvm_mode.md
diff --git a/llvm_mode/README.instrument_file.md b/llvm_mode/README.instrument_file.md
deleted file mode 100644
index 46e45ba2..00000000
--- a/llvm_mode/README.instrument_file.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# Using afl++ with partial instrumentation
-
- This file describes how you can selectively instrument only the source files
- that are interesting to you using the LLVM instrumentation provided by
- afl++
-
- Originally developed by Christian Holler (:decoder) <choller@mozilla.com>.
-
-## 1) Description and purpose
-
-When building and testing complex programs where only a part of the program is
-the fuzzing target, it often helps to only instrument the necessary parts of
-the program, leaving the rest uninstrumented. This helps to focus the fuzzer
-on the important parts of the program, avoiding undesired noise and
-disturbance by uninteresting code being exercised.
-
-For this purpose, I have added a "partial instrumentation" support to the LLVM
-mode of AFLFuzz that allows you to specify on a source file level which files
-should be compiled with or without instrumentation.
-
-Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead:
-https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation
-
-## 2) Building the LLVM module
-
-The new code is part of the existing afl++ LLVM module in the llvm_mode/
-subdirectory. There is nothing specifically to do :)
-
-
-## 3) How to use the partial instrumentation mode
-
-In order to build with partial instrumentation, you need to build with
-afl-clang-fast and afl-clang-fast++ respectively. The only required change is
-that you need to set the environment variable AFL_LLVM_INSTRUMENT_FILE when calling
-the compiler.
-
-The environment variable must point to a file containing all the filenames
-that should be instrumented. For matching, the filename that is being compiled
-must end in the filename entry contained in this the instrument file list (to avoid breaking
-the matching when absolute paths are used during compilation).
-
-For example if your source tree looks like this:
-
-```
-project/
-project/feature_a/a1.cpp
-project/feature_a/a2.cpp
-project/feature_b/b1.cpp
-project/feature_b/b2.cpp
-```
-
-and you only want to test feature_a, then create a the instrument file list file containing:
-
-```
-feature_a/a1.cpp
-feature_a/a2.cpp
-```
-
-However if the instrument file list file contains only this, it works as well:
-
-```
-a1.cpp
-a2.cpp
-```
-
-but it might lead to files being unwantedly instrumented if the same filename
-exists somewhere else in the project directories.
-
-The created the instrument file list file is then set to AFL_LLVM_INSTRUMENT_FILE when you compile
-your program. For each file that didn't match the the instrument file list, the compiler will
-issue a warning at the end stating that no blocks were instrumented. If you
-didn't intend to instrument that file, then you can safely ignore that warning.
-
-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 the instrument file list entries. See `man
-fnmatch` for the syntax. We do not set any of the `fnmatch` flags.
diff --git a/llvm_mode/README.instrument_list.md b/llvm_mode/README.instrument_list.md
new file mode 100644
index 00000000..d4739dda
--- /dev/null
+++ b/llvm_mode/README.instrument_list.md
@@ -0,0 +1,86 @@
+# Using afl++ with partial instrumentation
+
+ This file describes how you can selectively instrument only the source files
+ or functions that are interesting to you using the LLVM instrumentation
+ provided by afl++
+
+## 1) Description and purpose
+
+When building and testing complex programs where only a part of the program is
+the fuzzing target, it often helps to only instrument the necessary parts of
+the program, leaving the rest uninstrumented. This helps to focus the fuzzer
+on the important parts of the program, avoiding undesired noise and
+disturbance by uninteresting code being exercised.
+
+For this purpose, a "partial instrumentation" support en par with llvm sancov
+is provided by afl++ that allows you to specify on a source file and function
+level which should be compiled with or without instrumentation.
+
+Note: When using PCGUARD mode - and have llvm 12+ - you can use this instead:
+https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation
+
+the llvm sancov list format is fully supported by afl++, however afl++ has
+more flexbility.
+
+## 2) Building the LLVM module
+
+The new code is part of the existing afl++ LLVM module in the llvm_mode/
+subdirectory. There is nothing specifically to do :)
+
+## 3) How to use the partial instrumentation mode
+
+In order to build with partial instrumentation, you need to build with
+afl-clang-fast/afl-clang-fast++ or afl-clang-lto/afl-clang-lto++.
+The only required change is that you need to set either the environment variable
+AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST set with a filename.
+
+That file then contains the filenames or functions that should be instrumented
+(AFL_LLVM_ALLOWLIST) or should specifically NOT instrumentd (AFL_LLVM_DENYLIST).
+
+For matching, the function/filename that is being compiled must end in the
+function/filename entry contained in this the instrument file list (to avoid
+breaking the matching when absolute paths are used during compilation).
+
+**NOTE:** In optimization functions might be inlined and then not match!
+
+For example if your source tree looks like this:
+```
+project/
+project/feature_a/a1.cpp
+project/feature_a/a2.cpp
+project/feature_b/b1.cpp
+project/feature_b/b2.cpp
+```
+
+and you only want to test feature_a, then create a the instrument file list file containing:
+```
+feature_a/a1.cpp
+feature_a/a2.cpp
+```
+
+However if the instrument file list file contains only this, it works as well:
+```
+a1.cpp
+a2.cpp
+```
+but it might lead to files being unwantedly instrumented if the same filename
+exists somewhere else in the project directories.
+
+You can also specify function names. Note that for C++ the function names
+must be mangled to match!
+
+afl++ is intelligent to identify if an entry is a filename or a function.
+However if you want to be sure (and compliant to the sancov allow/blocklist
+format), you can specify source file entries like this:
+```
+src: *malloc.c
+```
+and function entries like this:
+```
+fun: MallocFoo
+```
+Note that whitespace is ignored and comments (`# foo`) supported.
+
+## 4) UNIX-style pattern matching
+You can add UNIX-style pattern matching in the the instrument file list entries.
+See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags.
diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md
index e521ac82..9046c5a8 100644
--- a/llvm_mode/README.lto.md
+++ b/llvm_mode/README.lto.md
@@ -17,9 +17,6 @@ This version requires a current llvm 11+ compiled from the github master.
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
A big issue with how afl/afl++ works is that the basic block IDs that are
@@ -108,15 +105,12 @@ make install
Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc.
-Also the instrument file listing (AFL_LLVM_INSTRUMENT_FILE -> [README.instrument_file.md](README.instrument_file.md)) and
+Also the instrument file listing (AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST -> [README.instrument_list.md](README.instrument_list.md)) and
laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
-InsTrim (control flow graph instrumentation) is supported and recommended!
- (set `AFL_LLVM_INSTRUMENT=CFG`)
Example:
```
CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar ./configure
-export AFL_LLVM_INSTRUMENT=CFG
make
```
@@ -131,14 +125,14 @@ on start. This improves coverage statistically by 5-10% :)
## 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.
+To speed up fuzzing, it is possible to set a fixed shared memory map.
+Recommened is the value 0x10000.
+In most cases this will work without any problems. However if a target uses
+early constructors, ifuncs or a deferred forkserver this can crash the target.
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).
## Document edge IDs
@@ -265,15 +259,6 @@ If this succeeeds then there is an issue with afl-clang-lto. Please report at
Even some targets where clang-12 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)
-or have their own _init/.init functions and these are instrumented then the
-target will likely crash when started. This can be avoided by compiling with
-`AFL_LLVM_MAP_DYNAMIC=1` .
-
-This can e.g. happen with OpenSSL.
-
## History
This was originally envisioned by hexcoder- in Summer 2019, however we saw no
diff --git a/llvm_mode/README.md b/llvm_mode/README.md
index 22088dfd..f23d7150 100644
--- a/llvm_mode/README.md
+++ b/llvm_mode/README.md
@@ -109,7 +109,7 @@ Several options are present to make llvm_mode faster or help it rearrange
the code to make afl-fuzz path discovery easier.
If you need just to instrument specific parts of the code, you can the instrument file list
-which C/C++ files to actually instrument. See [README.instrument_file](README.instrument_file.md)
+which C/C++ files to actually instrument. See [README.instrument_list](README.instrument_list.md)
For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md)
diff --git a/llvm_mode/README.persistent_mode.md b/llvm_mode/README.persistent_mode.md
index 4f0bcb2e..7d2fd93b 100644
--- a/llvm_mode/README.persistent_mode.md
+++ b/llvm_mode/README.persistent_mode.md
@@ -115,6 +115,33 @@ will keep working normally when compiled with a tool other than afl-clang-fast.
Finally, recompile the program with afl-clang-fast (afl-gcc or afl-clang will
*not* generate a deferred-initialization binary) - and you should be all set!
+*NOTE:* In the code between `main` and `__AFL_INIT()` should not be any code
+run that is instrumented - otherwise a crash might occure.
+In case this is useful (e.g. for expensive one time initialization) you can
+try to do the following:
+
+Add after the includes:
+```
+extern unsigned char *__afl_area_ptr;
+#define MAX_DUMMY_SIZE 256000
+
+__attribute__((constructor(1))) void __afl_protect(void) {
+#ifdef MAP_FIXED_NOREPLACE
+ __afl_area_ptr = (unsigned char*) mmap((void *)0x10000, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if ((uint64_t)__afl_area_ptr == -1)
+#endif
+ __afl_area_ptr = (unsigned char*) mmap((void *)0x10000, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if ((uint64_t)__afl_area_ptr == -1)
+ __afl_area_ptr = (unsigned char*) mmap(NULL, MAX_DUMMY_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+}
+
+```
+and just before `__AFL_INIT()`:
+```
+ munmap(__afl_area_ptr, MAX_DUMMY_SIZE);
+ __afl_area_ptr = NULL;
+```
+
## 4) persistent mode
Some libraries provide APIs that are stateless, or whose state can be reset in
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index ef99e3f3..efaba122 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -161,7 +161,8 @@ static void find_obj(u8 *argv0) {
static void edit_params(u32 argc, char **argv, char **envp) {
- u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
+ u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0,
+ preprocessor_only = 0;
u8 have_pic = 0;
u8 *name;
@@ -229,7 +230,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (lto_mode) {
if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
- getenv("AFL_LLVM_WHITELIST")) {
+ getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
+ getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
@@ -399,6 +401,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
+ if (!strcmp(cur, "-E")) preprocessor_only = 1;
+ if (!strcmp(cur, "-shared")) shared_linking = 1;
+
cc_params[cc_par_cnt++] = cur;
}
@@ -563,6 +568,18 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
+ if (preprocessor_only) {
+
+ /* In the preprocessor_only case (-E), we are not actually compiling at
+ all but requesting the compiler to output preprocessed sources only.
+ We must not add the runtime in this case because the compiler will
+ simply output its binary content back on stdout, breaking any build
+ systems that rely on a separate source preprocessing step. */
+ cc_params[cc_par_cnt] = NULL;
+ return;
+
+ }
+
#ifndef __ANDROID__
switch (bit_mode) {
@@ -605,6 +622,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
+ if (!shared_linking)
+ cc_params[cc_par_cnt++] =
+ alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
+
#endif
cc_params[cc_par_cnt] = NULL;
@@ -637,9 +658,13 @@ int main(int argc, char **argv, char **envp) {
}
- if ((getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) &&
+ if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
+ getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
+ getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) &&
getenv("AFL_DONT_OPTIMIZE"))
- FATAL("AFL_LLVM_INSTRUMENT_FILE and AFL_DONT_OPTIMIZE cannot be combined");
+ WARNF(
+ "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
+ "for file matching, only function matching!");
if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
getenv("INSTRIM_LIB")) {
@@ -787,15 +812,17 @@ int main(int argc, char **argv, char **envp) {
#if LLVM_VERSION_MAJOR <= 6
instrument_mode = INSTRUMENT_AFL;
#else
- if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) {
+ if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
+ getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
+ getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
instrument_mode = INSTRUMENT_AFL;
WARNF(
"switching to classic instrumentation because "
- "AFL_LLVM_INSTRUMENT_FILE does not work with PCGUARD. Use "
- "-fsanitize-coverage-allowlist=allowlist.txt if you want to use "
- "PCGUARD. Requires llvm 12+. See "
- "https://clang.llvm.org/docs/"
+ "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use "
+ "-fsanitize-coverage-allowlist=allowlist.txt or "
+ "-fsanitize-coverage-blocklist=denylist.txt if you want to use "
+ "PCGUARD. Requires llvm 12+. See https://clang.llvm.org/docs/ "
"SanitizerCoverage.html#partially-disabling-instrumentation");
} else
@@ -846,11 +873,14 @@ int main(int argc, char **argv, char **envp) {
"together");
if (instrument_mode == INSTRUMENT_PCGUARD &&
- (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")))
+ (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
+ getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
+ getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")))
FATAL(
"Instrumentation type PCGUARD does not support "
- "AFL_LLVM_INSTRUMENT_FILE! Use "
- "-fsanitize-coverage-allowlist=allowlist.txt instead (requires llvm "
+ "AFL_LLVM_ALLOWLIST/DENYLIST! Use "
+ "-fsanitize-coverage-allowlist=allowlist.txt or "
+ "-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm "
"12+), see "
"https://clang.llvm.org/docs/"
"SanitizerCoverage.html#partially-disabling-instrumentation");
diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc
index 9a884ded..0b50c547 100644
--- a/llvm_mode/afl-llvm-common.cc
+++ b/llvm_mode/afl-llvm-common.cc
@@ -20,7 +20,10 @@
using namespace llvm;
-static std::list<std::string> myInstrumentList;
+static std::list<std::string> allowListFiles;
+static std::list<std::string> allowListFunctions;
+static std::list<std::string> denyListFiles;
+static std::list<std::string> denyListFunctions;
char *getBBName(const llvm::BasicBlock *BB) {
@@ -57,7 +60,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
"asan.",
"llvm.",
"sancov.",
- "__ubsan_handle_",
+ "__ubsan_",
"ign.",
"__afl_",
"_fini",
@@ -87,30 +90,166 @@ bool isIgnoreFunction(const llvm::Function *F) {
void initInstrumentList() {
- char *instrumentListFilename = getenv("AFL_LLVM_INSTRUMENT_FILE");
- if (!instrumentListFilename)
- instrumentListFilename = getenv("AFL_LLVM_WHITELIST");
+ char *allowlist = getenv("AFL_LLVM_ALLOWLIST");
+ if (!allowlist) allowlist = getenv("AFL_LLVM_INSTRUMENT_FILE");
+ if (!allowlist) allowlist = getenv("AFL_LLVM_WHITELIST");
+ char *denylist = getenv("AFL_LLVM_DENYLIST");
+ if (!denylist) denylist = getenv("AFL_LLVM_BLOCKLIST");
- if (instrumentListFilename) {
+ if (allowlist && denylist)
+ FATAL(
+ "You can only specify either AFL_LLVM_ALLOWLIST or AFL_LLVM_DENYLIST "
+ "but not both!");
+
+ if (allowlist) {
std::string line;
std::ifstream fileStream;
- fileStream.open(instrumentListFilename);
- if (!fileStream)
- report_fatal_error("Unable to open AFL_LLVM_INSTRUMENT_FILE");
+ fileStream.open(allowlist);
+ if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_ALLOWLIST");
getline(fileStream, line);
+
while (fileStream) {
- myInstrumentList.push_back(line);
- getline(fileStream, line);
+ int is_file = -1;
+ std::size_t npos;
+ std::string original_line = line;
+
+ line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
+ line.end());
+
+ // remove # and following
+ if ((npos = line.find("#")) != std::string::npos)
+ line = line.substr(0, npos);
+
+ if (line.compare(0, 4, "fun:") == 0) {
+
+ is_file = 0;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 9, "function:") == 0) {
+
+ is_file = 0;
+ line = line.substr(9);
+
+ } else if (line.compare(0, 4, "src:") == 0) {
+
+ is_file = 1;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 7, "source:") == 0) {
+
+ is_file = 1;
+ line = line.substr(7);
+
+ }
+
+ if (line.find(":") != std::string::npos) {
+
+ FATAL("invalid line in AFL_LLVM_ALLOWLIST: %s", original_line.c_str());
+
+ }
+
+ if (line.length() > 0) {
+
+ // if the entry contains / or . it must be a file
+ if (is_file == -1)
+ if (line.find("/") != std::string::npos ||
+ line.find(".") != std::string::npos)
+ is_file = 1;
+ // otherwise it is a function
+
+ if (is_file == 1)
+ allowListFiles.push_back(line);
+ else
+ allowListFunctions.push_back(line);
+ getline(fileStream, line);
+
+ }
}
+ if (debug)
+ SAYF(cMGN "[D] " cRST
+ "loaded allowlist with %zu file and %zu function entries\n",
+ allowListFiles.size(), allowListFunctions.size());
+
}
- if (debug)
- SAYF(cMGN "[D] " cRST "loaded instrument list with %zu entries\n",
- myInstrumentList.size());
+ if (denylist) {
+
+ std::string line;
+ std::ifstream fileStream;
+ fileStream.open(denylist);
+ if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_DENYLIST");
+ getline(fileStream, line);
+
+ while (fileStream) {
+
+ int is_file = -1;
+ std::size_t npos;
+ std::string original_line = line;
+
+ line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
+ line.end());
+
+ // remove # and following
+ if ((npos = line.find("#")) != std::string::npos)
+ line = line.substr(0, npos);
+
+ if (line.compare(0, 4, "fun:") == 0) {
+
+ is_file = 0;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 9, "function:") == 0) {
+
+ is_file = 0;
+ line = line.substr(9);
+
+ } else if (line.compare(0, 4, "src:") == 0) {
+
+ is_file = 1;
+ line = line.substr(4);
+
+ } else if (line.compare(0, 7, "source:") == 0) {
+
+ is_file = 1;
+ line = line.substr(7);
+
+ }
+
+ if (line.find(":") != std::string::npos) {
+
+ FATAL("invalid line in AFL_LLVM_DENYLIST: %s", original_line.c_str());
+
+ }
+
+ if (line.length() > 0) {
+
+ // if the entry contains / or . it must be a file
+ if (is_file == -1)
+ if (line.find("/") != std::string::npos ||
+ line.find(".") != std::string::npos)
+ is_file = 1;
+ // otherwise it is a function
+
+ if (is_file == 1)
+ denyListFiles.push_back(line);
+ else
+ denyListFunctions.push_back(line);
+ getline(fileStream, line);
+
+ }
+
+ }
+
+ if (debug)
+ SAYF(cMGN "[D] " cRST
+ "loaded denylist with %zu file and %zu function entries\n",
+ denyListFiles.size(), denyListFunctions.size());
+
+ }
}
@@ -121,42 +260,173 @@ bool isInInstrumentList(llvm::Function *F) {
if (!F->size() || isIgnoreFunction(F)) return false;
// if we do not have a the instrument file list return true
- if (myInstrumentList.empty()) return true;
+ if (!allowListFiles.empty() || !allowListFunctions.empty()) {
+
+ if (!allowListFunctions.empty()) {
+
+ std::string instFunction = F->getName().str();
+
+ for (std::list<std::string>::iterator it = allowListFunctions.begin();
+ it != allowListFunctions.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. We also allow UNIX-style pattern
+ * matching */
- // 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 (instFunction.length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
+
+ if (debug)
+ SAYF(cMGN "[D] " cRST
+ "Function %s is in the allow function list, "
+ "instrumenting ... \n",
+ instFunction.c_str());
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (!allowListFiles.empty()) {
+
+ // 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) {
+ if (Loc) {
+
+ DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
+
+ unsigned int instLine = cDILoc->getLine();
+ StringRef instFilename = cDILoc->getFilename();
- DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
+ if (instFilename.str().empty()) {
- unsigned int instLine = cDILoc->getLine();
- StringRef instFilename = cDILoc->getFilename();
+ /* If the original location is empty, try using the inlined location
+ */
+ DILocation *oDILoc = cDILoc->getInlinedAt();
+ if (oDILoc) {
+
+ instFilename = oDILoc->getFilename();
+ instLine = oDILoc->getLine();
+
+ }
+
+ }
- if (instFilename.str().empty()) {
+ /* Continue only if we know where we actually are */
+ if (!instFilename.str().empty()) {
- /* If the original location is empty, try using the inlined location
- */
- DILocation *oDILoc = cDILoc->getInlinedAt();
- if (oDILoc) {
+ for (std::list<std::string>::iterator it = allowListFiles.begin();
+ it != allowListFiles.end(); ++it) {
- instFilename = oDILoc->getFilename();
- instLine = oDILoc->getLine();
+ /* 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. We also allow UNIX-style pattern
+ * matching */
+
+ if (instFilename.str().length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
+ 0) {
+
+ if (debug)
+ SAYF(cMGN "[D] " cRST
+ "Function %s is in the allowlist (%s), "
+ "instrumenting ... \n",
+ F->getName().str().c_str(), instFilename.str().c_str());
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+#else
+ if (!Loc.isUnknown()) {
+
+ DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
+
+ 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 = allowListFiles.begin();
+ it != allowListFiles.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. We also allow UNIX-style pattern
+ * matching */
+
+ if (instFilename.str().length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
+ 0) {
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
}
}
- /* Continue only if we know where we actually are */
- if (!instFilename.str().empty()) {
+#endif
+ else {
+
+ // we could not find out the location. in this case we say it is not
+ // in the the instrument file list
+ if (!be_quiet)
+ WARNF(
+ "No debug information found for function %s, will not be "
+ "instrumented (recompile with -g -O[1-3]).",
+ F->getName().str().c_str());
+ return false;
+
+ }
+
+ return false;
+
+ }
+
+ if (!denyListFiles.empty() || !denyListFunctions.empty()) {
+
+ if (!denyListFunctions.empty()) {
- for (std::list<std::string>::iterator it = myInstrumentList.begin();
- it != myInstrumentList.end(); ++it) {
+ std::string instFunction = F->getName().str();
+
+ for (std::list<std::string>::iterator it = denyListFunctions.begin();
+ it != denyListFunctions.end(); ++it) {
/* We don't check for filename equality here because
* filenames might actually be full paths. Instead we
@@ -164,16 +434,16 @@ bool isInInstrumentList(llvm::Function *F) {
* specified in the list. We also allow UNIX-style pattern
* matching */
- if (instFilename.str().length() >= it->length()) {
+ if (instFunction.length() >= it->length()) {
- if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
- 0) {
+ if (fnmatch(("*" + *it).c_str(), instFunction.c_str(), 0) == 0) {
if (debug)
SAYF(cMGN "[D] " cRST
- "Function %s is in the list (%s), instrumenting ... \n",
- F->getName().str().c_str(), instFilename.str().c_str());
- return true;
+ "Function %s is in the deny function list, "
+ "not instrumenting ... \n",
+ instFunction.c_str());
+ return false;
}
@@ -183,35 +453,64 @@ bool isInInstrumentList(llvm::Function *F) {
}
- }
+ if (!denyListFiles.empty()) {
-#else
- if (!Loc.isUnknown()) {
+ // 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();
- DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
+#if LLVM_VERSION_MAJOR >= 4 || \
+ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7)
+ if (Loc) {
- unsigned int instLine = cDILoc.getLineNumber();
- StringRef instFilename = cDILoc.getFilename();
+ DILocation *cDILoc = dyn_cast<DILocation>(Loc.getAsMDNode());
- (void)instLine;
- /* Continue only if we know where we actually are */
- if (!instFilename.str().empty()) {
+ unsigned int instLine = cDILoc->getLine();
+ StringRef instFilename = cDILoc->getFilename();
- for (std::list<std::string>::iterator it = myInstrumentList.begin();
- it != myInstrumentList.end(); ++it) {
+ if (instFilename.str().empty()) {
- /* 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. We also allow UNIX-style pattern
- * matching */
+ /* If the original location is empty, try using the inlined location
+ */
+ DILocation *oDILoc = cDILoc->getInlinedAt();
+ if (oDILoc) {
- if (instFilename.str().length() >= it->length()) {
+ instFilename = oDILoc->getFilename();
+ instLine = oDILoc->getLine();
- if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
- 0) {
+ }
- return true;
+ }
+
+ /* Continue only if we know where we actually are */
+ if (!instFilename.str().empty()) {
+
+ for (std::list<std::string>::iterator it = denyListFiles.begin();
+ it != denyListFiles.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. We also allow UNIX-style pattern
+ * matching */
+
+ if (instFilename.str().length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
+ 0) {
+
+ if (debug)
+ SAYF(cMGN "[D] " cRST
+ "Function %s is in the denylist (%s), not "
+ "instrumenting ... \n",
+ F->getName().str().c_str(), instFilename.str().c_str());
+ return false;
+
+ }
+
+ }
}
@@ -221,23 +520,65 @@ bool isInInstrumentList(llvm::Function *F) {
}
- }
+#else
+ if (!Loc.isUnknown()) {
+
+ DILocation cDILoc(Loc.getAsMDNode(F->getContext()));
+
+ 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 = denyListFiles.begin();
+ it != denyListFiles.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. We also allow UNIX-style pattern
+ * matching */
+
+ if (instFilename.str().length() >= it->length()) {
+
+ if (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
+ 0) {
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
#endif
- else {
-
- // we could not find out the location. in this case we say it is not
- // in the the instrument file list
- if (!be_quiet)
- WARNF(
- "No debug information found for function %s, will not be "
- "instrumented (recompile with -g -O[1-3]).",
- F->getName().str().c_str());
- return false;
+ else {
+
+ // we could not find out the location. in this case we say it is not
+ // in the the instrument file list
+ if (!be_quiet)
+ WARNF(
+ "No debug information found for function %s, will be "
+ "instrumented (recompile with -g -O[1-3]).",
+ F->getName().str().c_str());
+ return true;
+
+ }
+
+ return true;
}
- return false;
+ return true; // not reached
}
diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
index 38c3f202..fd8e48a7 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -49,6 +49,7 @@
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Pass.h"
+#include "llvm/IR/Constants.h"
#include "afl-llvm-common.h"
@@ -135,7 +136,10 @@ bool AFLLTOPass::runOnModule(Module &M) {
if (getenv("AFL_LLVM_LTO_AUTODICTIONARY")) autodictionary = 1;
- if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
+ // we make this the default as the fixed map has problems with
+ // defered forkserver, early constructors, ifuncs and maybe more
+ /*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
+ map_addr = 0;
if (getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2;
@@ -196,7 +200,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
ConstantInt *Zero = ConstantInt::get(Int8Ty, 0);
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
- /* This dumps all inialized global strings - might be useful in the future
+ // This dumps all inialized global strings - might be useful in the future
+ /*
for (auto G=M.getGlobalList().begin(); G!=M.getGlobalList().end(); G++) {
GlobalVariable &GV=*G;
@@ -212,7 +217,79 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
- */
+ */
+
+ std::vector<std::string> module_block_list;
+
+ if (map_addr) {
+
+ for (GlobalIFunc &IF : M.ifuncs()) {
+
+ StringRef ifunc_name = IF.getName();
+ Constant *r = IF.getResolver();
+ StringRef r_name = cast<Function>(r->getOperand(0))->getName();
+ if (!be_quiet)
+ fprintf(stderr,
+ "Warning: Found an ifunc with name %s that points to resolver "
+ "function %s, we cannot instrument this, putting it into a "
+ "block list.\n",
+ ifunc_name.str().c_str(), r_name.str().c_str());
+ module_block_list.push_back(r_name.str());
+
+ }
+
+ GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors");
+ if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) {
+
+ ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
+
+ if (InitList) {
+
+ for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
+
+ if (ConstantStruct *CS =
+ dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
+
+ if (CS->getNumOperands() >= 2) {
+
+ if (CS->getOperand(1)->isNullValue())
+ break; // Found a null terminator, stop here.
+
+ ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
+ int Priority = CI ? CI->getSExtValue() : 0;
+
+ Constant *FP = CS->getOperand(1);
+ if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
+ if (CE->isCast()) FP = CE->getOperand(0);
+ if (Function *F = dyn_cast<Function>(FP)) {
+
+ if (!F->isDeclaration() &&
+ strncmp(F->getName().str().c_str(), "__afl", 5) != 0 &&
+ Priority <= 5) {
+
+ if (!be_quiet)
+ fprintf(stderr,
+ "Warning: Found constructor function %s with prio "
+ "%u, we cannot instrument this, putting it into a "
+ "block list.\n",
+ F->getName().str().c_str(), Priority);
+ module_block_list.push_back(F->getName().str());
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
/* Instrument all the things! */
@@ -220,12 +297,36 @@ bool AFLLTOPass::runOnModule(Module &M) {
for (auto &F : M) {
- // fprintf(stderr, "DEBUG: Module %s Function %s\n",
- // M.getName().str().c_str(), F.getName().str().c_str());
+ /*For debugging
+ AttributeSet X = F.getAttributes().getFnAttributes();
+ fprintf(stderr, "DEBUG: Module %s Function %s attributes %u\n",
+ M.getName().str().c_str(), F.getName().str().c_str(),
+ X.getNumAttributes());
+ */
if (F.size() < function_minimum_size) continue;
if (isIgnoreFunction(&F)) continue;
+ if (module_block_list.size()) {
+
+ for (auto bname : module_block_list) {
+
+ std::string fname = F.getName().str();
+
+ if (fname.compare(bname) == 0) {
+
+ if (!be_quiet)
+ WARNF(
+ "Skipping instrumentation of dangerous early running function "
+ "%s",
+ fname.c_str());
+
+ }
+
+ }
+
+ }
+
// the instrument file list check
AttributeList Attrs = F.getAttributes();
if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) {
diff --git a/llvm_mode/afl-llvm-lto-instrumentlist.so.cc b/llvm_mode/afl-llvm-lto-instrumentlist.so.cc
index ab7c0c58..a7331444 100644
--- a/llvm_mode/afl-llvm-lto-instrumentlist.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentlist.so.cc
@@ -59,39 +59,9 @@ class AFLcheckIfInstrument : public ModulePass {
static char ID;
AFLcheckIfInstrument() : ModulePass(ID) {
- int entries = 0;
-
if (getenv("AFL_DEBUG")) debug = 1;
- char *instrumentListFilename = getenv("AFL_LLVM_INSTRUMENT_FILE");
- if (!instrumentListFilename)
- instrumentListFilename = getenv("AFL_LLVM_WHITELIST");
- if (instrumentListFilename) {
-
- std::string line;
- std::ifstream fileStream;
- fileStream.open(instrumentListFilename);
- if (!fileStream)
- report_fatal_error("Unable to open AFL_LLVM_INSTRUMENT_FILE");
- getline(fileStream, line);
- while (fileStream) {
-
- myInstrumentList.push_back(line);
- getline(fileStream, line);
- entries++;
-
- }
-
- } else
-
- PFATAL(
- "afl-llvm-lto-instrumentlist.so loaded without "
- "AFL_LLVM_INSTRUMENT_FILE?!");
-
- if (debug)
- SAYF(cMGN "[D] " cRST
- "loaded the instrument file list %s with %d entries\n",
- instrumentListFilename, entries);
+ initInstrumentList();
}
@@ -129,120 +99,28 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) {
for (auto &F : M) {
if (F.size() < 1) continue;
- // fprintf(stderr, "F:%s\n", F.getName().str().c_str());
- if (isIgnoreFunction(&F)) continue;
-
- BasicBlock::iterator IP = F.getEntryBlock().getFirstInsertionPt();
- IRBuilder<> IRB(&(*IP));
-
- if (!myInstrumentList.empty()) {
-
- bool instrumentFunction = 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 (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 (instFilename.str().empty()) {
- if (!be_quiet)
- WARNF(
- "Function %s has no source file name information and will "
- "not be instrumented.",
- F.getName().str().c_str());
- continue;
-
- }
-
- }
-
- //(void)instLine;
-
- fprintf(stderr, "xxx %s %s\n", F.getName().str().c_str(),
- instFilename.str().c_str());
- if (debug)
- SAYF(cMGN "[D] " cRST "function %s is in file %s\n",
- F.getName().str().c_str(), instFilename.str().c_str());
-
- for (std::list<std::string>::iterator it = myInstrumentList.begin();
- it != myInstrumentList.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 (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) ==
- 0) {
-
- instrumentFunction = true;
- break;
-
- }
-
- }
-
- }
-
- } else {
-
- if (!be_quiet)
- WARNF(
- "No debug information found for function %s, recompile with -g "
- "-O[1-3]",
- F.getName().str().c_str());
- continue;
-
- }
-
- /* Either we couldn't figure out our location or the location is
- * not the instrument file listed, so we skip instrumentation.
- * We do this by renaming the function. */
- if (instrumentFunction == true) {
-
- if (debug)
- SAYF(cMGN "[D] " cRST "function %s is in the instrument file list\n",
- F.getName().str().c_str());
-
- } else {
-
- if (debug)
- SAYF(cMGN "[D] " cRST
- "function %s is NOT in the instrument file list\n",
- F.getName().str().c_str());
+ // fprintf(stderr, "F:%s\n", F.getName().str().c_str());
- auto & Ctx = F.getContext();
- AttributeList Attrs = F.getAttributes();
- AttrBuilder NewAttrs;
- NewAttrs.addAttribute("skipinstrument");
- F.setAttributes(
- Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
+ if (isInInstrumentList(&F)) {
- }
+ if (debug)
+ SAYF(cMGN "[D] " cRST "function %s is in the instrument file list\n",
+ F.getName().str().c_str());
} else {
- PFATAL("InstrumentList is empty");
+ if (debug)
+ SAYF(cMGN "[D] " cRST
+ "function %s is NOT in the instrument file list\n",
+ F.getName().str().c_str());
+
+ auto & Ctx = F.getContext();
+ AttributeList Attrs = F.getAttributes();
+ AttrBuilder NewAttrs;
+ NewAttrs.addAttribute("skipinstrument");
+ F.setAttributes(
+ Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
}
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index fcacc675..a567593e 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -42,6 +42,8 @@
#include <sys/wait.h>
#include <sys/types.h>
+#include "llvm/Config/llvm-config.h"
+
#ifdef __linux__
#include "snapshot-inl.h"
#endif
@@ -183,6 +185,9 @@ static void __afl_map_shm_fuzz() {
static void __afl_map_shm(void) {
+ // we we are not running in afl ensure the map exists
+ if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial;
+
char *id_str = getenv(SHM_ENV_VAR);
if (__afl_final_loc) {
@@ -324,10 +329,13 @@ static void __afl_map_shm(void) {
id_str = getenv(CMPLOG_SHM_ENV_VAR);
- if (getenv("AFL_DEBUG"))
+ if (getenv("AFL_DEBUG")) {
+
fprintf(stderr, "DEBUG: cmplog id_str %s\n",
id_str == NULL ? "<null>" : id_str);
+ }
+
if (id_str) {
#ifdef USEMMAP
@@ -399,9 +407,12 @@ static void __afl_start_snapshots(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
- if (getenv("AFL_DEBUG"))
+ if (getenv("AFL_DEBUG")) {
+
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
+ }
+
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
@@ -608,9 +619,12 @@ static void __afl_start_forkserver(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
- if (getenv("AFL_DEBUG"))
+ if (getenv("AFL_DEBUG")) {
+
fprintf(stderr, "target forkserver recv: %08x\n", was_killed);
+ }
+
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
@@ -892,8 +906,16 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
*/
+#if (LLVM_VERSION_MAJOR < 9)
+
__afl_area_ptr[*guard]++;
+#else
+
+ __afl_area_ptr[*guard] = __afl_area_ptr[*guard] + 1 + (__afl_area_ptr[*guard] == 255 ? 1 : 0);
+
+#endif
+
}
/* Init callback. Populates instrumentation IDs. Note that we're using
@@ -905,6 +927,13 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
u32 inst_ratio = 100;
char *x;
+ if (getenv("AFL_DEBUG")) {
+
+ fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n",
+ start, stop);
+
+ }
+
if (start == stop || *start) return;
x = getenv("AFL_INST_RATIO");
@@ -940,7 +969,7 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
- if (!__afl_cmp_map) return;
+ if (unlikely(!__afl_cmp_map)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
@@ -963,7 +992,7 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
- if (!__afl_cmp_map) return;
+ if (unlikely(!__afl_cmp_map)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
@@ -984,7 +1013,7 @@ void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
- if (!__afl_cmp_map) return;
+ if (unlikely(!__afl_cmp_map)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
@@ -1005,7 +1034,7 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
- if (!__afl_cmp_map) return;
+ if (unlikely(!__afl_cmp_map)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
@@ -1056,6 +1085,8 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
+ if (unlikely(!__afl_cmp_map)) return;
+
for (uint64_t i = 0; i < cases[0]; i++) {
uintptr_t k = (uintptr_t)__builtin_return_address(0) + i;
@@ -1093,7 +1124,7 @@ static int area_is_mapped(void *ptr, size_t len) {
void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
- if (!__afl_cmp_map) return;
+ if (unlikely(!__afl_cmp_map)) return;
if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return;