From 06264df16891070a09a31cd981a9dcaaf01de7c7 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 30 Jun 2020 17:28:21 +0200 Subject: rename whitelist -> instrumentlist --- llvm_mode/GNUmakefile | 6 +- llvm_mode/LLVMInsTrim.so.cc | 4 +- llvm_mode/README.instrument_file.md | 79 +++++++++ llvm_mode/README.lto.md | 4 +- llvm_mode/README.md | 4 +- llvm_mode/README.whitelist.md | 79 --------- llvm_mode/TODO | 10 -- llvm_mode/afl-clang-fast.c | 17 +- llvm_mode/afl-llvm-common.cc | 37 ++-- llvm_mode/afl-llvm-common.h | 4 +- llvm_mode/afl-llvm-lto-instrim.so.cc | 5 +- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 5 +- llvm_mode/afl-llvm-lto-instrumentlist.so.cc | 253 +++++++++++++++++++++++++++ llvm_mode/afl-llvm-lto-whitelist.so.cc | 244 -------------------------- llvm_mode/afl-llvm-pass.so.cc | 4 +- llvm_mode/cmplog-instructions-pass.cc | 4 +- llvm_mode/cmplog-routines-pass.cc | 4 +- llvm_mode/compare-transform-pass.so.cc | 4 +- llvm_mode/split-compares-pass.so.cc | 4 +- llvm_mode/split-switches-pass.so.cc | 4 +- 20 files changed, 392 insertions(+), 383 deletions(-) create mode 100644 llvm_mode/README.instrument_file.md delete mode 100644 llvm_mode/README.whitelist.md delete mode 100644 llvm_mode/TODO create mode 100644 llvm_mode/afl-llvm-lto-instrumentlist.so.cc delete mode 100644 llvm_mode/afl-llvm-lto-whitelist.so.cc (limited to 'llvm_mode') diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 4cc55d92..b5d026ef 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -253,7 +253,7 @@ ifeq "$(TEST_MMAP)" "1" LDFLAGS += -Wno-deprecated-declarations endif - 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 + PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-ld-lto ../afl-llvm-lto-instrumentlist.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)" "" @@ -332,7 +332,7 @@ ifeq "$(LLVM_MIN_4_0_1)" "0" endif $(CXX) $(CLANG_CPPFL) -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-common.o +../afl-llvm-lto-instrumentlist.so: afl-llvm-lto-instrumentlist.so.cc afl-llvm-common.o ifeq "$(LLVM_LTO)" "1" $(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) afl-llvm-common.o endif @@ -403,7 +403,7 @@ all_done: test_build 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-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-instrumentlist.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 diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index 991127a7..75548266 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -74,7 +74,7 @@ struct InsTrim : public ModulePass { InsTrim() : ModulePass(ID), generator(0) { - initWhitelist(); + initInstrumentList(); } @@ -271,7 +271,7 @@ struct InsTrim : public ModulePass { } - if (!isInWhitelist(&F)) continue; + if (!isInInstrumentList(&F)) continue; // if the function below our minimum size skip it (1 or 2) if (F.size() < function_minimum_size) { continue; } diff --git a/llvm_mode/README.instrument_file.md b/llvm_mode/README.instrument_file.md new file mode 100644 index 00000000..347bd3c6 --- /dev/null +++ b/llvm_mode/README.instrument_file.md @@ -0,0 +1,79 @@ +# 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) . + +## 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. + + +## 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 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.lto.md b/llvm_mode/README.lto.md index 517cb62a..4641fa89 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -7,7 +7,7 @@ This version requires a current llvm 11 compiled from the github master. 1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better coverage than anything else that is out there in the AFL world -2. You can use it together with llvm_mode: laf-intel and whitelisting +2. You can use it together with llvm_mode: laf-intel and the instrument file listing features and can be combined with cmplog/Redqueen 3. It only works with llvm 11 (current github master state) @@ -108,7 +108,7 @@ make install Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc. -Also whitelisting (AFL_LLVM_WHITELIST -> [README.whitelist.md](README.whitelist.md)) and +Also the instrument file listing (AFL_LLVM_INSTRUMENT_FILE -> [README.instrument_file.md](README.instrument_file.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`) diff --git a/llvm_mode/README.md b/llvm_mode/README.md index c24aef49..e2e22751 100644 --- a/llvm_mode/README.md +++ b/llvm_mode/README.md @@ -108,8 +108,8 @@ directory. 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 whitelist -which C/C++ files to actually instrument. See [README.whitelist](README.whitelist.md) +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) For splitting memcmp, strncmp, etc. please see [README.laf-intel](README.laf-intel.md) diff --git a/llvm_mode/README.whitelist.md b/llvm_mode/README.whitelist.md deleted file mode 100644 index 6393fae8..00000000 --- a/llvm_mode/README.whitelist.md +++ /dev/null @@ -1,79 +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) . - -## 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. - - -## 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_WHITELIST 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 whitelist (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 whitelist file containing: - -``` -feature_a/a1.cpp -feature_a/a2.cpp -``` - -However if the whitelist 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 whitelist file is then set to AFL_LLVM_WHITELIST when you compile -your program. For each file that didn't match the whitelist, 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 whitelist entries. See `man -fnmatch` for the syntax. We do not set any of the `fnmatch` flags. diff --git a/llvm_mode/TODO b/llvm_mode/TODO deleted file mode 100644 index 2729d688..00000000 --- a/llvm_mode/TODO +++ /dev/null @@ -1,10 +0,0 @@ -TODO for afl-ld: -* handle libfoo.a object archives - -TODO for afl-llvm-lto-instrumentation: -* better algo for putting stuff in the map? -* try to predict how long the instrumentation process will take - -TODO for afl-llvm-lto-whitelist -* different solution then renaming? - diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 3b0225c2..f1b03682 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -227,13 +227,14 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (lto_mode) { - if (getenv("AFL_LLVM_WHITELIST") != NULL) { + if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL || + getenv("AFL_LLVM_WHITELIST")) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-lto-whitelist.so", obj_path); + alloc_printf("%s/afl-llvm-lto-instrumentlist.so", obj_path); } @@ -762,7 +763,7 @@ int main(int argc, char **argv, char **envp) { #if LLVM_VERSION_MAJOR <= 6 instrument_mode = INSTRUMENT_AFL; #else - if (getenv("AFL_LLVM_WHITELIST")) + if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) instrument_mode = INSTRUMENT_AFL; else instrument_mode = INSTRUMENT_PCGUARD; @@ -810,8 +811,11 @@ int main(int argc, char **argv, char **envp) { "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set " "together"); - if (instrument_mode == INSTRUMENT_PCGUARD && getenv("AFL_LLVM_WHITELIST")) - WARNF("Instrumentation type PCGUARD does not support AFL_LLVM_WHITELIST!"); + if (instrument_mode == INSTRUMENT_PCGUARD && + (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST"))) + WARNF( + "Instrumentation type PCGUARD does not support " + "AFL_LLVM_INSTRUMENT_FILE!"); if (argc < 2 || strcmp(argv[1], "-h") == 0) { @@ -861,7 +865,8 @@ int main(int argc, char **argv, char **envp) { "AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison " "function calls\n" "AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n" - "AFL_LLVM_WHITELIST: enable whitelisting (selective " + "AFL_LLVM_INSTRUMENT_FILE: enable the instrument file listing " + "(selective " "instrumentation)\n" "AFL_NO_BUILTIN: compile for use with libtokencap.so\n" "AFL_PATH: path to instrumenting pass and runtime " diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc index 5a75c4dd..47b49358 100644 --- a/llvm_mode/afl-llvm-common.cc +++ b/llvm_mode/afl-llvm-common.cc @@ -18,7 +18,7 @@ using namespace llvm; -static std::list myWhitelist; +static std::list myInstrumentList; char *getBBName(const llvm::BasicBlock *BB) { @@ -44,7 +44,7 @@ char *getBBName(const llvm::BasicBlock *BB) { } /* Function that we never instrument or analyze */ -/* Note: this ignore check is also called in isInWhitelist() */ +/* Note: this ignore check is also called in isInInstrumentList() */ bool isIgnoreFunction(const llvm::Function *F) { // Starting from "LLVMFuzzer" these are functions used in libfuzzer based @@ -83,19 +83,22 @@ bool isIgnoreFunction(const llvm::Function *F) { } -void initWhitelist() { +void initInstrumentList() { - char *instWhiteListFilename = getenv("AFL_LLVM_WHITELIST"); - if (instWhiteListFilename) { + char *instrumentListFilename = getenv("AFL_LLVM_INSTRUMENT_FILE"); + if (!instrumentListFilename) + instrumentListFilename = getenv("AFL_LLVM_WHITELIST"); + if (instrumentListFilename) { std::string line; std::ifstream fileStream; - fileStream.open(instWhiteListFilename); - if (!fileStream) report_fatal_error("Unable to open AFL_LLVM_WHITELIST"); + fileStream.open(instrumentListFilename); + if (!fileStream) + report_fatal_error("Unable to open AFL_LLVM_INSTRUMENT_FILE"); getline(fileStream, line); while (fileStream) { - myWhitelist.push_back(line); + myInstrumentList.push_back(line); getline(fileStream, line); } @@ -104,14 +107,14 @@ void initWhitelist() { } -bool isInWhitelist(llvm::Function *F) { +bool isInInstrumentList(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 ignored. + // anyway and cant be in the the instrument file list. Or if it is ignored. if (!F->size() || isIgnoreFunction(F)) return false; - // if we do not have a whitelist return true - if (myWhitelist.empty()) return true; + // if we do not have a the instrument file list return true + if (myInstrumentList.empty()) return true; // let's try to get the filename for the function auto bb = &F->getEntryBlock(); @@ -147,8 +150,8 @@ bool isInWhitelist(llvm::Function *F) { /* Continue only if we know where we actually are */ if (!instFilename.str().empty()) { - for (std::list::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { + for (std::list::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 @@ -185,8 +188,8 @@ bool isInWhitelist(llvm::Function *F) { /* Continue only if we know where we actually are */ if (!instFilename.str().empty()) { - for (std::list::iterator it = myWhitelist.begin(); - it != myWhitelist.end(); ++it) { + for (std::list::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 @@ -215,7 +218,7 @@ bool isInWhitelist(llvm::Function *F) { else { // we could not find out the location. in this case we say it is not - // in the whitelist + // in the the instrument file list return false; diff --git a/llvm_mode/afl-llvm-common.h b/llvm_mode/afl-llvm-common.h index db009f8f..38e0c830 100644 --- a/llvm_mode/afl-llvm-common.h +++ b/llvm_mode/afl-llvm-common.h @@ -34,8 +34,8 @@ typedef long double max_align_t; char * getBBName(const llvm::BasicBlock *BB); bool isIgnoreFunction(const llvm::Function *F); -void initWhitelist(); -bool isInWhitelist(llvm::Function *F); +void initInstrumentList(); +bool isInInstrumentList(llvm::Function *F); unsigned long long int calculateCollisions(uint32_t edges); #endif diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc index b62912a6..ca2b5886 100644 --- a/llvm_mode/afl-llvm-lto-instrim.so.cc +++ b/llvm_mode/afl-llvm-lto-instrim.so.cc @@ -566,12 +566,13 @@ struct InsTrimLTO : public ModulePass { functions++; - // whitelist check + // the instrument file list check AttributeList Attrs = F.getAttributes(); if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) { if (debug) - fprintf(stderr, "DEBUG: Function %s is not whitelisted\n", + fprintf(stderr, + "DEBUG: Function %s is not the instrument file listed\n", F.getName().str().c_str()); continue; diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 82af890c..af2db3ff 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -198,12 +198,13 @@ bool AFLLTOPass::runOnModule(Module &M) { if (F.size() < function_minimum_size) continue; if (isIgnoreFunction(&F)) continue; - // whitelist check + // the instrument file list check AttributeList Attrs = F.getAttributes(); if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) { if (debug) - fprintf(stderr, "DEBUG: Function %s is not whitelisted\n", + fprintf(stderr, + "DEBUG: Function %s is not the instrument file listed\n", F.getName().str().c_str()); continue; diff --git a/llvm_mode/afl-llvm-lto-instrumentlist.so.cc b/llvm_mode/afl-llvm-lto-instrumentlist.so.cc new file mode 100644 index 00000000..6e6199e9 --- /dev/null +++ b/llvm_mode/afl-llvm-lto-instrumentlist.so.cc @@ -0,0 +1,253 @@ +/* + american fuzzy lop++ - LLVM-mode instrumentation pass + --------------------------------------------------- + + Written by Laszlo Szekeres and + Michal Zalewski + + LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted + from afl-as.c are Michal's fault. + + Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This library is plugged into LLVM when invoking clang through afl-clang-fast. + It tells the compiler to add code roughly equivalent to the bits discussed + in ../afl-as.h. + + */ + +#define AFL_LLVM_PASS + +#include "config.h" +#include "debug.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/IR/CFG.h" + +#include "afl-llvm-common.h" + +using namespace llvm; + +namespace { + +class AFLcheckIfInstrument : public ModulePass { + + public: + 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); + + } + + bool runOnModule(Module &M) override; + + // StringRef getPassName() const override { + + // return "American Fuzzy Lop Instrumentation"; + // } + + protected: + std::list myInstrumentList; + int debug = 0; + +}; + +} // namespace + +char AFLcheckIfInstrument::ID = 0; + +bool AFLcheckIfInstrument::runOnModule(Module &M) { + + /* Show a banner */ + + char be_quiet = 0; + setvbuf(stdout, NULL, _IONBF, 0); + + if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) { + + SAYF(cCYA "afl-llvm-lto-instrumentlist" VERSION cRST + " by Marc \"vanHauser\" Heuse \n"); + + } else if (getenv("AFL_QUIET")) + + be_quiet = 1; + + 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(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; + + if (debug) + SAYF(cMGN "[D] " cRST "function %s is in file %s\n", + F.getName().str().c_str(), instFilename.str().c_str()); + /* Continue only if we know where we actually are */ + if (!instFilename.str().empty()) { + + for (std::list::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; + + } + + } + + } + + } + + } + + /* 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()); + + auto & Ctx = F.getContext(); + AttributeList Attrs = F.getAttributes(); + AttrBuilder NewAttrs; + NewAttrs.addAttribute("skipinstrument"); + F.setAttributes( + Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs)); + + } + + } else { + + PFATAL("InstrumentList is empty"); + + } + + } + + return true; + +} + +static void registerAFLcheckIfInstrumentpass(const PassManagerBuilder &, + legacy::PassManagerBase &PM) { + + PM.add(new AFLcheckIfInstrument()); + +} + +static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass( + PassManagerBuilder::EP_ModuleOptimizerEarly, + registerAFLcheckIfInstrumentpass); + +static RegisterStandardPasses RegisterAFLcheckIfInstrumentpass0( + PassManagerBuilder::EP_EnabledOnOptLevel0, + registerAFLcheckIfInstrumentpass); + diff --git a/llvm_mode/afl-llvm-lto-whitelist.so.cc b/llvm_mode/afl-llvm-lto-whitelist.so.cc deleted file mode 100644 index 52c7cf0d..00000000 --- a/llvm_mode/afl-llvm-lto-whitelist.so.cc +++ /dev/null @@ -1,244 +0,0 @@ -/* - american fuzzy lop++ - LLVM-mode instrumentation pass - --------------------------------------------------- - - Written by Laszlo Szekeres and - Michal Zalewski - - LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted - from afl-as.c are Michal's fault. - - Copyright 2015, 2016 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This library is plugged into LLVM when invoking clang through afl-clang-fast. - It tells the compiler to add code roughly equivalent to the bits discussed - in ../afl-as.h. - - */ - -#define AFL_LLVM_PASS - -#include "config.h" -#include "debug.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Debug.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/IR/CFG.h" - -#include "afl-llvm-common.h" - -using namespace llvm; - -namespace { - -class AFLwhitelist : public ModulePass { - - public: - static char ID; - AFLwhitelist() : ModulePass(ID) { - - int entries = 0; - - if (getenv("AFL_DEBUG")) debug = 1; - - 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); - entries++; - - } - - } else - - PFATAL("afl-llvm-lto-whitelist.so loaded without AFL_LLVM_WHITELIST?!"); - - if (debug) - SAYF(cMGN "[D] " cRST "loaded whitelist %s with %d entries\n", - instWhiteListFilename, entries); - - } - - bool runOnModule(Module &M) override; - - // StringRef getPassName() const override { - - // return "American Fuzzy Lop Instrumentation"; - // } - - protected: - std::list myWhitelist; - int debug = 0; - -}; - -} // namespace - -char AFLwhitelist::ID = 0; - -bool AFLwhitelist::runOnModule(Module &M) { - - /* Show a banner */ - - char be_quiet = 0; - setvbuf(stdout, NULL, _IONBF, 0); - - if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) { - - SAYF(cCYA "afl-llvm-lto-whitelist" VERSION cRST - " by Marc \"vanHauser\" Heuse \n"); - - } else if (getenv("AFL_QUIET")) - - be_quiet = 1; - - 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 (!myWhitelist.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(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; - - if (debug) - SAYF(cMGN "[D] " cRST "function %s is in file %s\n", - F.getName().str().c_str(), instFilename.str().c_str()); - /* Continue only if we know where we actually are */ - if (!instFilename.str().empty()) { - - for (std::list::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 (fnmatch(("*" + *it).c_str(), instFilename.str().c_str(), 0) == - 0) { - - instrumentFunction = true; - break; - - } - - } - - } - - } - - } - - /* Either we couldn't figure out our location or the location is - * not whitelisted, so we skip instrumentation. - * We do this by renaming the function. */ - if (instrumentFunction == true) { - - if (debug) - SAYF(cMGN "[D] " cRST "function %s is in whitelist\n", - F.getName().str().c_str()); - - } else { - - if (debug) - SAYF(cMGN "[D] " cRST "function %s is NOT in whitelist\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)); - - } - - } else { - - PFATAL("Whitelist is empty"); - - } - - } - - return true; - -} - -static void registerAFLwhitelistpass(const PassManagerBuilder &, - legacy::PassManagerBase &PM) { - - PM.add(new AFLwhitelist()); - -} - -static RegisterStandardPasses RegisterAFLwhitelistpass( - PassManagerBuilder::EP_ModuleOptimizerEarly, registerAFLwhitelistpass); - -static RegisterStandardPasses RegisterAFLwhitelistpass0( - PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLwhitelistpass); - diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 7997df51..90cf3eb4 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -74,7 +74,7 @@ class AFLCoverage : public ModulePass { static char ID; AFLCoverage() : ModulePass(ID) { - initWhitelist(); + initInstrumentList(); } @@ -307,7 +307,7 @@ bool AFLCoverage::runOnModule(Module &M) { fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(), F.size()); - if (!isInWhitelist(&F)) continue; + if (!isInInstrumentList(&F)) continue; if (F.size() < function_minimum_size) continue; diff --git a/llvm_mode/cmplog-instructions-pass.cc b/llvm_mode/cmplog-instructions-pass.cc index c5a6ff8b..f929361a 100644 --- a/llvm_mode/cmplog-instructions-pass.cc +++ b/llvm_mode/cmplog-instructions-pass.cc @@ -59,7 +59,7 @@ class CmpLogInstructions : public ModulePass { static char ID; CmpLogInstructions() : ModulePass(ID) { - initWhitelist(); + initInstrumentList(); } @@ -170,7 +170,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { /* iterate over all functions, bbs and instruction and add suitable calls */ for (auto &F : M) { - if (!isInWhitelist(&F)) continue; + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { diff --git a/llvm_mode/cmplog-routines-pass.cc b/llvm_mode/cmplog-routines-pass.cc index 792a45b9..318193a4 100644 --- a/llvm_mode/cmplog-routines-pass.cc +++ b/llvm_mode/cmplog-routines-pass.cc @@ -59,7 +59,7 @@ class CmpLogRoutines : public ModulePass { static char ID; CmpLogRoutines() : ModulePass(ID) { - initWhitelist(); + initInstrumentList(); } @@ -118,7 +118,7 @@ bool CmpLogRoutines::hookRtns(Module &M) { /* iterate over all functions, bbs and instruction and add suitable calls */ for (auto &F : M) { - if (!isInWhitelist(&F)) continue; + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index 96abeebb..2d1ab1cc 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -58,7 +58,7 @@ class CompareTransform : public ModulePass { static char ID; CompareTransform() : ModulePass(ID) { - initWhitelist(); + initInstrumentList(); } @@ -124,7 +124,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, * strcmp/memcmp/strncmp/strcasecmp/strncasecmp */ for (auto &F : M) { - if (!isInWhitelist(&F)) continue; + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { diff --git a/llvm_mode/split-compares-pass.so.cc b/llvm_mode/split-compares-pass.so.cc index 2c4ed71c..651fa5b4 100644 --- a/llvm_mode/split-compares-pass.so.cc +++ b/llvm_mode/split-compares-pass.so.cc @@ -55,7 +55,7 @@ class SplitComparesTransform : public ModulePass { static char ID; SplitComparesTransform() : ModulePass(ID) { - initWhitelist(); + initInstrumentList(); } @@ -102,7 +102,7 @@ bool SplitComparesTransform::simplifyCompares(Module &M) { * all integer comparisons with >= and <= predicates to the icomps vector */ for (auto &F : M) { - if (!isInWhitelist(&F)) continue; + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { diff --git a/llvm_mode/split-switches-pass.so.cc b/llvm_mode/split-switches-pass.so.cc index 4a6ca3d9..44075c94 100644 --- a/llvm_mode/split-switches-pass.so.cc +++ b/llvm_mode/split-switches-pass.so.cc @@ -60,7 +60,7 @@ class SplitSwitchesTransform : public ModulePass { static char ID; SplitSwitchesTransform() : ModulePass(ID) { - initWhitelist(); + initInstrumentList(); } @@ -312,7 +312,7 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { * all switches to switches vector for later processing */ for (auto &F : M) { - if (!isInWhitelist(&F)) continue; + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { -- cgit 1.4.1