From 80ddb484deb82aefc9ba35c766ffca313d74e377 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 6 May 2020 11:51:28 +0200 Subject: added InsTrimLTO :-) --- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 44 +++++----------------------- 1 file changed, 8 insertions(+), 36 deletions(-) (limited to 'llvm_mode/afl-llvm-lto-instrumentation.so.cc') diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 838e45af..79081d37 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -1,14 +1,9 @@ /* - american fuzzy lop++ - LLVM-mode instrumentation pass - --------------------------------------------------- + american fuzzy lop++ - LLVM LTO instrumentation pass + ---------------------------------------------------- - Written by Laszlo Szekeres and - Michal Zalewski + Written by Marc Heuse - 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"); @@ -17,9 +12,7 @@ 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. + This library is plugged into LLVM when invoking clang through afl-clang-lto. */ @@ -32,11 +25,12 @@ #include #include #include +#include #include #include #include -#include +#include #include "llvm/Config/llvm-config.h" #include "llvm/ADT/Statistic.h" @@ -56,7 +50,6 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Pass.h" -#include #include "afl-llvm-common.h" using namespace llvm; @@ -90,23 +83,6 @@ class AFLLTOPass : public ModulePass { } - // Calculate the number of average collisions that would occur if all - // location IDs would be assigned randomly (like normal afl/afl++). - // This uses the "balls in bins" algorithm. - unsigned long long int calculateCollisions(uint32_t edges) { - - double bins = MAP_SIZE; - double balls = edges; - double step1 = 1 - (1 / bins); - double step2 = pow(step1, balls); - double step3 = bins * step2; - double step4 = round(step3); - unsigned long long int empty = step4; - unsigned long long int collisions = edges - (MAP_SIZE - empty); - return collisions; - - } - bool runOnModule(Module &M) override; protected: @@ -131,8 +107,6 @@ bool AFLLTOPass::runOnModule(Module &M) { IntegerType *Int32Ty = IntegerType::getInt32Ty(C); IntegerType *Int64Ty = IntegerType::getInt64Ty(C); - if (getenv("AFL_DEBUG")) debug = 1; - /* Show a banner */ if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { @@ -185,12 +159,10 @@ bool AFLLTOPass::runOnModule(Module &M) { if (debug) { fprintf(stderr, "map address is %lu\n", map_addr); } - /* Get globals for the SHM region and the previous location. Note that - __afl_prev_loc is thread-local. */ + /* Get/set the globals for the SHM region. */ GlobalVariable *AFLMapPtr = NULL; - ; - Value *MapPtrFixed = NULL; + Value * MapPtrFixed = NULL; if (!map_addr) { -- cgit 1.4.1 From 140053502bd5ce162ab7e6bfbb151494381d704c Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 7 May 2020 08:08:20 +0200 Subject: import transform fix into autodict, code-format --- examples/afl_untracer/afl-untracer.c | 40 +++++++++++++++------------- llvm_mode/afl-clang-fast.c | 6 +++-- llvm_mode/afl-llvm-lto-instrim.so.cc | 24 +++++++++++------ llvm_mode/afl-llvm-lto-instrumentation.so.cc | 24 +++++++++++------ 4 files changed, 58 insertions(+), 36 deletions(-) (limited to 'llvm_mode/afl-llvm-lto-instrumentation.so.cc') diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 99f06f36..5dbc71bf 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -279,12 +279,13 @@ library_list_t *find_library(char *name) { /* for having an easy breakpoint after load the shared library */ // this seems to work for clang too. nice :) requires gcc 4.4+ #pragma GCC push_options -#pragma GCC optimize ("O0") -void breakpoint() { +#pragma GCC optimize("O0") +void breakpoint() { if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); } + #pragma GCC pop_options /* Error reporting to forkserver controller */ @@ -470,7 +471,7 @@ void setup_trap_instrumentation() { FILE *patches = fopen(filename, "r"); if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename); - // Index into the coverage bitmap for the current trap instruction. + // Index into the coverage bitmap for the current trap instruction. #ifdef __aarch64__ uint64_t bitmap_index = 0; #else @@ -507,11 +508,13 @@ void setup_trap_instrumentation() { PROT_READ | PROT_WRITE | PROT_EXEC) != 0) FATAL("Failed to mprotect library %s writable", line); - // Create shadow memory. + // Create shadow memory. #ifdef __aarch64__ for (int i = 0; i < 8; i++) { + #else for (int i = 0; i < 4; i++) { + #endif void *shadow_addr = SHADOW(lib_addr + i); @@ -540,16 +543,17 @@ void setup_trap_instrumentation() { FATAL("Too many basic blocks to instrument"); #ifdef __arch64__ - uint64_t + uint64_t #else - uint32_t + uint32_t #endif - *shadow = SHADOW(lib_addr + offset); + *shadow = SHADOW(lib_addr + offset); if (*shadow != 0) continue; // skip duplicates // Make lookup entry in shadow memory. -#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || defined(__i386__)) +#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \ + defined(__i386__)) // this is for Intel x64 @@ -566,10 +570,10 @@ void setup_trap_instrumentation() { // this is for aarch64 - uint32_t *patch_bytes = (uint32_t*)(lib_addr + offset); - uint32_t orig_bytes = *patch_bytes; + uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset); + uint32_t orig_bytes = *patch_bytes; *shadow = (bitmap_index << 32) | orig_bytes; - *patch_bytes = 0xd4200000; // replace instruction with debug trap + *patch_bytes = 0xd4200000; // replace instruction with debug trap if (debug) fprintf(stderr, "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n", @@ -577,14 +581,14 @@ void setup_trap_instrumentation() { bitmap_index, *shadow); #else - // this will be ARM and AARCH64 - // for ARM we will need to identify if the code is in thumb or ARM + // this will be ARM and AARCH64 + // for ARM we will need to identify if the code is in thumb or ARM #error "non x86_64/aarch64 not supported yet" - //__arm__: - // linux thumb: 0xde01 - // linux arm: 0xe7f001f0 - //__aarch64__: - // linux aarch64: 0xd4200000 + //__arm__: + // linux thumb: 0xde01 + // linux arm: 0xe7f001f0 + //__aarch64__: + // linux aarch64: 0xd4200000 #endif bitmap_index++; diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 1f3463eb..42b02bdd 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -716,9 +716,11 @@ int main(int argc, char **argv, char **envp) { } } - + if (instrument_opt_mode && lto_mode) - FATAL("CTX and NGRAM can not be used in LTO mode (and would make LTO useless)"); + FATAL( + "CTX and NGRAM can not be used in LTO mode (and would make LTO " + "useless)"); if (!instrument_opt_mode) { diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc index 9fd3e3ec..f862e091 100644 --- a/llvm_mode/afl-llvm-lto-instrim.so.cc +++ b/llvm_mode/afl-llvm-lto-instrim.so.cc @@ -346,11 +346,15 @@ struct InsTrimLTO : public ModulePass { if (auto *Var = dyn_cast(Ptr->getOperand(0))) { - if (auto *Array = dyn_cast( - Var->getInitializer())) { + if (Var->hasInitializer()) { - HasStr2 = true; - Str2 = Array->getAsString().str(); + if (auto *Array = dyn_cast( + Var->getInitializer())) { + + HasStr2 = true; + Str2 = Array->getAsString().str(); + + } } @@ -419,11 +423,15 @@ struct InsTrimLTO : public ModulePass { if (auto *Var = dyn_cast(Ptr->getOperand(0))) { - if (auto *Array = dyn_cast( - Var->getInitializer())) { + if (Var->hasInitializer()) { + + if (auto *Array = dyn_cast( + Var->getInitializer())) { + + HasStr1 = true; + Str1 = Array->getAsString().str(); - HasStr1 = true; - Str1 = Array->getAsString().str(); + } } diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 79081d37..0e353fdf 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -326,11 +326,15 @@ bool AFLLTOPass::runOnModule(Module &M) { if (auto *Var = dyn_cast(Ptr->getOperand(0))) { - if (auto *Array = - dyn_cast(Var->getInitializer())) { + if (Var->hasInitializer()) { - HasStr2 = true; - Str2 = Array->getAsString().str(); + if (auto *Array = dyn_cast( + Var->getInitializer())) { + + HasStr2 = true; + Str2 = Array->getAsString().str(); + + } } @@ -398,11 +402,15 @@ bool AFLLTOPass::runOnModule(Module &M) { if (auto *Var = dyn_cast(Ptr->getOperand(0))) { - if (auto *Array = - dyn_cast(Var->getInitializer())) { + if (Var->hasInitializer()) { + + if (auto *Array = dyn_cast( + Var->getInitializer())) { + + HasStr1 = true; + Str1 = Array->getAsString().str(); - HasStr1 = true; - Str1 = Array->getAsString().str(); + } } -- cgit 1.4.1 From ef2ccc8117bb899616472e2d95525ae0ca1a2098 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 7 May 2020 14:59:12 +0200 Subject: added AFL_LLVM_SKIPSINGLEBLOCK and changed default behaviour to instrument single block functions --- docs/Changelog.md | 2 ++ docs/env_variables.md | 8 ++++---- llvm_mode/LLVMInsTrim.so.cc | 5 +++-- llvm_mode/afl-llvm-lto-instrim.so.cc | 3 ++- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 7 ++++++- llvm_mode/afl-llvm-pass.so.cc | 17 ++++++++++++----- src/afl-common.c | 18 +++++++++--------- 7 files changed, 38 insertions(+), 22 deletions(-) (limited to 'llvm_mode/afl-llvm-lto-instrumentation.so.cc') diff --git a/docs/Changelog.md b/docs/Changelog.md index 35240021..8bcc8949 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,8 @@ sending a mail to . - an old, old bug in afl that would show negative stability in rare circumstances is now hopefully fixed - llvm_mode: + - afl-clang-fast/lto now do not skip single block functions. This + behaviour can be reactivated with AFL_LLVM_SKIPSINGLEBLOCK - if LLVM 11 is installed the posix shm_open+mmap is used and a fixed address for the shared memory map is used as this increases the fuzzing speed diff --git a/docs/env_variables.md b/docs/env_variables.md index f5d28981..36e5a432 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -83,6 +83,10 @@ tools make fairly broad use of environmental variables: The native instrumentation helpers (llvm_mode and gcc_plugin) accept a subset of the settings discussed in section #1, with the exception of: + - Setting AFL_LLVM_SKIPSINGLEBLOCK=1 will skip instrumenting + functions with a single basic block. This is useful for most C and + some C++ targets. This works for all instrumentation modes. + - AFL_AS, since this toolchain does not directly invoke GNU as. - TMPDIR and AFL_KEEP_ASSEMBLY, since no temporary assembly files are @@ -156,10 +160,6 @@ Then there are a few specific features that are only available in llvm_mode: afl-fuzz will only be able to see the path the loop took, but not how many times it was called (unless it is a complex loop). - - Setting AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK=1 will skip instrumenting - functions with a single basic block. This is useful for most C and - some C++ targets. - See llvm_mode/README.instrim.md ### NGRAM diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index ad046a8b..ed6c79e8 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -134,7 +134,8 @@ struct InsTrim : public ModulePass { } - if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL) + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2; unsigned PrevLocSize = 0; @@ -394,7 +395,7 @@ struct InsTrim : public ModulePass { if ((callInst = dyn_cast(&IN))) { Function *Callee = callInst->getCalledFunction(); - if (!Callee || Callee->size() < 2) + if (!Callee || Callee->size() < function_minimum_size) continue; else { diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc index 6371a3cc..a686bb81 100644 --- a/llvm_mode/afl-llvm-lto-instrim.so.cc +++ b/llvm_mode/afl-llvm-lto-instrim.so.cc @@ -172,7 +172,8 @@ struct InsTrimLTO : public ModulePass { } - if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") != NULL) + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2; // this is our default diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 0e353fdf..f44b336e 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -87,6 +87,7 @@ class AFLLTOPass : public ModulePass { protected: int afl_global_id = 1, debug = 0, autodictionary = 0; + uint32_t function_minimum_size = 1; uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0; uint64_t map_addr = 0x10000; char * skip_nozero = NULL; @@ -124,6 +125,10 @@ bool AFLLTOPass::runOnModule(Module &M) { if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) + function_minimum_size = 2; + if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) { uint64_t val; @@ -189,7 +194,7 @@ bool AFLLTOPass::runOnModule(Module &M) { // fprintf(stderr, "DEBUG: Function %s\n", F.getName().str().c_str()); - if (F.size() < 2) continue; + if (F.size() < function_minimum_size) continue; if (isBlacklisted(&F)) continue; std::vector InsBlocks; diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 0d9e0aba..2d23ad21 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -84,6 +84,7 @@ class AFLCoverage : public ModulePass { uint32_t ngram_size = 0; uint32_t debug = 0; uint32_t map_size = MAP_SIZE; + uint32_t function_minimum_size = 1; char * ctx_str = NULL, *skip_nozero = NULL; }; @@ -182,6 +183,10 @@ bool AFLCoverage::runOnModule(Module &M) { #endif skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") || + getenv("AFL_LLVM_SKIPSINGLEBLOCK")) + function_minimum_size = 2; + unsigned PrevLocSize = 0; char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); @@ -294,13 +299,15 @@ bool AFLCoverage::runOnModule(Module &M) { if (!isInWhitelist(&F)) continue; + if (F.size() < function_minimum_size) continue; + for (auto &BB : F) { BasicBlock::iterator IP = BB.getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); // Context sensitive coverage - if (ctx_str && &BB == &F.getEntryBlock() && F.size() > 1) { + if (ctx_str && &BB == &F.getEntryBlock()) { // load the context ID of the previous function and write to to a local // variable on the stack @@ -318,7 +325,7 @@ bool AFLCoverage::runOnModule(Module &M) { if ((callInst = dyn_cast(&IN))) { Function *Callee = callInst->getCalledFunction(); - if (!Callee || Callee->size() < 2) + if (!Callee || Callee->size() < function_minimum_size) continue; else { @@ -389,11 +396,11 @@ bool AFLCoverage::runOnModule(Module &M) { } // fprintf(stderr, " == %d\n", more_than_one); - if (more_than_one != 1) { + if (F.size() > 1 && more_than_one != 1) { // in CTX mode we have to restore the original context for the caller - // she might be calling other functions which need the correct CTX - if (ctx_str && has_calls && F.size() > 1) { + if (ctx_str && has_calls) { Instruction *Inst = BB.getTerminator(); if (isa(Inst) || isa(Inst)) { @@ -526,7 +533,7 @@ bool AFLCoverage::runOnModule(Module &M) { // in CTX mode we have to restore the original context for the caller - // she might be calling other functions which need the correct CTX. // Currently this is only needed for the Ubuntu clang-6.0 bug - if (ctx_str && has_calls && F.size() > 1) { + if (ctx_str && has_calls) { Instruction *Inst = BB.getTerminator(); if (isa(Inst) || isa(Inst)) { diff --git a/src/afl-common.c b/src/afl-common.c index 54b2e790..d9d57863 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -64,15 +64,15 @@ char *afl_environment_variables[] = { "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY", - "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES", - "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS", - "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES", - "AFL_LLVM_MAP_ADDR", "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", - "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", - "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", - "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN", - "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", "AFL_NO_PYTHON", - "AFL_UNTRACER_FILE", + "AFL_LLVM_SKIPSINGLEBLOCK", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", + "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", + "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES", + "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR", + "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE", + "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_LLVM_SKIP_NEVERZERO", + "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", + "AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", + "AFL_NO_UI", "AFL_NO_PYTHON", "AFL_UNTRACER_FILE", "AFL_NO_X86", // not really an env but we dont want to warn on it "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE", //"AFL_PERSISTENT", // not implemented anymore, so warn additionally -- cgit 1.4.1