diff options
Diffstat (limited to 'instrumentation')
-rw-r--r-- | instrumentation/LLVMInsTrim.so.cc | 14 | ||||
-rw-r--r-- | instrumentation/MarkNodes.cc | 2 | ||||
-rw-r--r-- | instrumentation/README.instrument_list.md | 53 | ||||
-rw-r--r-- | instrumentation/SanitizerCoverageLTO.so.cc | 11 | ||||
-rw-r--r-- | instrumentation/SanitizerCoveragePCGUARD.so.cc | 10 | ||||
-rw-r--r-- | instrumentation/afl-compiler-rt.o.c | 189 | ||||
-rw-r--r-- | instrumentation/afl-gcc-pass.so.cc | 11 | ||||
-rw-r--r-- | instrumentation/afl-llvm-dict2file.so.cc | 6 | ||||
-rw-r--r-- | instrumentation/afl-llvm-lto-instrumentation.so.cc | 35 | ||||
-rw-r--r-- | instrumentation/afl-llvm-pass.so.cc | 12 | ||||
-rw-r--r-- | instrumentation/cmplog-instructions-pass.cc | 89 | ||||
-rw-r--r-- | instrumentation/compare-transform-pass.so.cc | 29 | ||||
-rw-r--r-- | instrumentation/split-compares-pass.so.cc | 10 |
13 files changed, 348 insertions, 123 deletions
diff --git a/instrumentation/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc index 6b3231e6..235ee30f 100644 --- a/instrumentation/LLVMInsTrim.so.cc +++ b/instrumentation/LLVMInsTrim.so.cc @@ -200,7 +200,7 @@ struct InsTrim : public ModulePass { LoadInst * PrevCtx = NULL; // for CTX sensitive coverage if (ctx_str) -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLContext = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); #else @@ -211,7 +211,7 @@ struct InsTrim : public ModulePass { #ifdef AFL_HAVE_VECTOR_INTRINSICS if (ngram_size) - #ifdef __ANDROID__ + #if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, /* Initializer */ nullptr, "__afl_prev_loc"); @@ -224,7 +224,7 @@ struct InsTrim : public ModulePass { #endif else #endif -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); #else @@ -407,10 +407,10 @@ struct InsTrim : public ModulePass { // does the function have calls? and is any of the calls larger than // one basic block? has_calls = 0; - for (auto &BB : F) { + for (auto &BB2 : F) { if (has_calls) break; - for (auto &IN : BB) { + for (auto &IN : BB2) { CallInst *callInst = nullptr; if ((callInst = dyn_cast<CallInst>(&IN))) { @@ -454,7 +454,7 @@ struct InsTrim : public ModulePass { auto *PN = PHINode::Create(Int32Ty, 0, "", &*BB.begin()); DenseMap<BasicBlock *, unsigned> PredMap; - for (auto PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) { + for (PI = pred_begin(&BB), PE = pred_end(&BB); PI != PE; ++PI) { BasicBlock *PBB = *PI; auto It = PredMap.insert({PBB, genLabel()}); @@ -568,7 +568,7 @@ struct InsTrim : public ModulePass { getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - OKF("Instrumented %u locations (%llu, %llu) (%s mode)\n", total_instr, + OKF("Instrumented %d locations (%llu, %llu) (%s mode)\n", total_instr, total_rs, total_hs, modeline); } diff --git a/instrumentation/MarkNodes.cc b/instrumentation/MarkNodes.cc index 20a7df35..b77466d9 100644 --- a/instrumentation/MarkNodes.cc +++ b/instrumentation/MarkNodes.cc @@ -332,11 +332,11 @@ bool Indistinguish(uint32_t node1, uint32_t node2) { void MakeUniq(uint32_t now) { - bool StopFlag = false; if (Marked.find(now) == Marked.end()) { for (uint32_t pred1 : t_Pred[now]) { + bool StopFlag = false; for (uint32_t pred2 : t_Pred[now]) { if (pred1 == pred2) continue; diff --git a/instrumentation/README.instrument_list.md b/instrumentation/README.instrument_list.md index 122be2b6..b47b50f6 100644 --- a/instrumentation/README.instrument_list.md +++ b/instrumentation/README.instrument_list.md @@ -1,8 +1,9 @@ # Using afl++ with partial instrumentation - This file describes how to selectively instrument only source files - or functions that are of interest to you using the LLVM and GCC_PLUGIN - instrumentation provided by afl++. + This file describes two different mechanisms to selectively instrument + only specific parts in the target. + + Both mechanisms work for LLVM and GCC_PLUGIN, but not for afl-clang/afl-gcc. ## 1) Description and purpose @@ -12,28 +13,42 @@ 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 to specify on a source file and function -level which function should be compiled with or without instrumentation. +For this purpose, "partial instrumentation" support is provided by afl++ that +allows to specify what should be instrumented and what not. + +Both mechanisms can be used together. + +## 2) Selective instrumentation with __AFL_COVERAGE_... directives + +In this mechanism the selective instrumentation is done in the source code. -Note: When using PCGUARD mode - and llvm 12+ - you can use this instead: -https://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation +After the includes a special define has to be made, eg.: + +``` +#include <stdio.h> +#include <stdint.h> +// ... + +__AFL_COVERAGE(); // <- required for this feature to work +``` -The llvm sancov list format is fully supported by afl++, however afl++ has -more flexibility. +If you want to disable the coverage at startup until you specify coverage +should be started, then add `__AFL_COVERAGE_START_OFF();` at that position. -## 2a) Building the LLVM module +From here on out you have the following macros available that you can use +in any function where you want: -The new code is part of the existing afl++ LLVM module in the instrumentation/ -subdirectory. There is nothing specifically to do for the build :) + * `__AFL_COVERAGE_ON();` - enable coverage from this point onwards + * `__AFL_COVERAGE_OFF();` - disable coverage from this point onwards + * `__AFL_COVERAGE_DISCARD();` - reset all coverage gathered until this point + * `__AFL_COVERAGE_SKIP();` - mark this test case as unimportant. Whatever happens, afl-fuzz will ignore it. -## 2b) Building the GCC module +## 3) Selective instrumenation with AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST -The new code is part of the existing afl++ GCC_PLUGIN module in the -instrumentation/ subdirectory. There is nothing specifically to do for -the build :) +This feature is equivalent to llvm 12 sancov feature and allows to specify +on a filename and/or function name level to instrument these or skip them. -## 3) How to use the partial instrumentation mode +### 3a) 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++. @@ -90,7 +105,7 @@ fun: MallocFoo ``` Note that whitespace is ignored and comments (`# foo`) are supported. -## 4) UNIX-style pattern matching +### 3b) UNIX-style pattern matching You can add UNIX-style pattern matching in the "instrument file list" entries. See `man fnmatch` for the syntax. We do not set any of the `fnmatch` flags. diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 82e55218..016ac71f 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1111,7 +1111,7 @@ bool ModuleSanitizerCoverage::instrumentModule( getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); OKF("Instrumented %u locations with no collisions (on average %llu " - "collisions would be in afl-gcc/afl-clang-fast) (%s mode).", + "collisions would be in afl-gcc/vanilla AFL) (%s mode).", inst, calculateCollisions(inst), modeline); } @@ -1403,24 +1403,17 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, BasicBlock::iterator IP = BB.getFirstInsertionPt(); bool IsEntryBB = &BB == &F.getEntryBlock(); - DebugLoc EntryLoc; + if (IsEntryBB) { - if (auto SP = F.getSubprogram()) - EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP); // Keep static allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); - } else { - - EntryLoc = IP->getDebugLoc(); - } IRBuilder<> IRB(&*IP); - IRB.SetCurrentDebugLocation(EntryLoc); if (Options.TracePC) { IRB.CreateCall(SanCovTracePC) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 102b44a4..ecd6bc9b 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1163,24 +1163,18 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, BasicBlock::iterator IP = BB.getFirstInsertionPt(); bool IsEntryBB = &BB == &F.getEntryBlock(); - DebugLoc EntryLoc; + if (IsEntryBB) { - if (auto SP = F.getSubprogram()) - EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP); // Keep static allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); - } else { - - EntryLoc = IP->getDebugLoc(); - } IRBuilder<> IRB(&*IP); - IRB.SetCurrentDebugLocation(EntryLoc); + if (Options.TracePC) { IRB.CreateCall(SanCovTracePC); diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index cddde87c..e31bff16 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -76,7 +76,9 @@ #endif u8 __afl_area_initial[MAP_INITIAL_SIZE]; +u8 * __afl_area_ptr_dummy = __afl_area_initial; u8 * __afl_area_ptr = __afl_area_initial; +u8 * __afl_area_ptr_backup = __afl_area_initial; u8 * __afl_dictionary; u8 * __afl_fuzz_ptr; u32 __afl_fuzz_len_dummy; @@ -87,7 +89,12 @@ u32 __afl_map_size = MAP_SIZE; u32 __afl_dictionary_len; u64 __afl_map_addr; -#ifdef __ANDROID__ +// for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work: +int __afl_selective_coverage __attribute__((weak)); +int __afl_selective_coverage_start_off __attribute__((weak)); +int __afl_selective_coverage_temp = 1; + +#if defined(__ANDROID__) || defined(__HAIKU__) PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; u32 __afl_prev_ctx; u32 __afl_cmp_counter; @@ -100,6 +107,7 @@ __thread u32 __afl_cmp_counter; int __afl_sharedmem_fuzzing __attribute__((weak)); struct cmp_map *__afl_cmp_map; +struct cmp_map *__afl_cmp_map_backup; /* Child pid? */ @@ -230,7 +238,7 @@ static void __afl_map_shm_fuzz() { static void __afl_map_shm(void) { // if we are not running in afl ensure the map exists - if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_initial; } + if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; } char *id_str = getenv(SHM_ENV_VAR); @@ -295,11 +303,17 @@ static void __afl_map_shm(void) { if (__afl_area_ptr && __afl_area_ptr != __afl_area_initial) { - if (__afl_map_addr) + if (__afl_map_addr) { + munmap((void *)__afl_map_addr, __afl_final_loc); - else + + } else { + free(__afl_area_ptr); - __afl_area_ptr = __afl_area_initial; + + } + + __afl_area_ptr = __afl_area_ptr_dummy; } @@ -352,6 +366,18 @@ static void __afl_map_shm(void) { #else u32 shm_id = atoi(id_str); + if (__afl_map_size && __afl_map_size > MAP_SIZE) { + + u8 *map_env = getenv("AFL_MAP_SIZE"); + if (!map_env || atoi(map_env) < MAP_SIZE) { + + send_forkserver_error(FS_ERROR_MAP_SIZE); + _exit(1); + + } + + } + __afl_area_ptr = shmat(shm_id, (void *)__afl_map_addr, 0); /* Whooooops. */ @@ -396,9 +422,42 @@ static void __afl_map_shm(void) { free(__afl_area_ptr); __afl_area_ptr = NULL; - if (__afl_final_loc > MAP_INITIAL_SIZE) + + if (__afl_final_loc > MAP_INITIAL_SIZE) { + __afl_area_ptr = malloc(__afl_final_loc); - if (!__afl_area_ptr) __afl_area_ptr = __afl_area_initial; + + } + + if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; } + + } + + __afl_area_ptr_backup = __afl_area_ptr; + + if (__afl_selective_coverage) { + + if (__afl_map_size > MAP_INITIAL_SIZE) { + + __afl_area_ptr_dummy = malloc(__afl_map_size); + + if (__afl_area_ptr_dummy) { + + if (__afl_selective_coverage_start_off) { + + __afl_area_ptr = __afl_area_ptr_dummy; + + } + + } else { + + fprintf(stderr, "Error: __afl_selective_coverage failed!\n"); + __afl_selective_coverage = 0; + // continue; + + } + + } } @@ -449,6 +508,8 @@ static void __afl_map_shm(void) { __afl_cmp_map = shmat(shm_id, NULL, 0); #endif + __afl_cmp_map_backup = __afl_cmp_map; + if (!__afl_cmp_map || __afl_cmp_map == (void *)-1) { perror("shmat for cmplog"); @@ -683,7 +744,7 @@ static void __afl_start_forkserver(void) { #endif u8 tmp[4] = {0, 0, 0, 0}; - u32 status = 0; + u32 status_for_fsrv = 0; u32 already_read_first = 0; u32 was_killed; @@ -691,17 +752,26 @@ static void __afl_start_forkserver(void) { void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) - status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT; - if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ; - if (status) status |= (FS_OPT_ENABLED); - memcpy(tmp, &status, 4); + if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) { + + status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + + } + + if (__afl_dictionary_len && __afl_dictionary) { + + status_for_fsrv |= FS_OPT_AUTODICT; + + } + + if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; } + if (status_for_fsrv) { status_for_fsrv |= (FS_OPT_ENABLED); } + memcpy(tmp, &status_for_fsrv, 4); /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ - if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { @@ -726,7 +796,6 @@ static void __afl_start_forkserver(void) { // great lets pass the dictionary through the forkserver FD u32 len = __afl_dictionary_len, offset = 0; - s32 ret; if (write(FORKSRV_FD + 1, &len, 4) != 4) { @@ -738,6 +807,7 @@ static void __afl_start_forkserver(void) { while (len != 0) { + s32 ret; ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); if (ret < 1) { @@ -894,6 +964,8 @@ int __afl_persistent_loop(unsigned int max_cnt) { cycle_cnt = max_cnt; first_pass = 0; + __afl_selective_coverage_temp = 1; + return 1; } @@ -906,6 +978,7 @@ int __afl_persistent_loop(unsigned int max_cnt) { __afl_area_ptr[0] = 1; memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); + __afl_selective_coverage_temp = 1; return 1; @@ -915,7 +988,7 @@ int __afl_persistent_loop(unsigned int max_cnt) { follows the loop is not traced. We do that by pivoting back to the dummy output region. */ - __afl_area_ptr = __afl_area_initial; + __afl_area_ptr = __afl_area_ptr_dummy; } @@ -937,7 +1010,7 @@ void __afl_manual_init(void) { init_done = 1; is_persistent = 0; __afl_sharedmem_fuzzing = 0; - if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_initial; + if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_ptr_dummy; if (getenv("AFL_DEBUG")) fprintf(stderr, @@ -998,7 +1071,12 @@ __attribute__((constructor(1))) void __afl_auto_second(void) { else ptr = (u8 *)malloc(__afl_final_loc); - if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr; + if (ptr && (ssize_t)ptr != -1) { + + __afl_area_ptr = ptr; + __afl_area_ptr_backup = __afl_area_ptr; + + } } @@ -1014,7 +1092,12 @@ __attribute__((constructor(0))) void __afl_auto_first(void) { ptr = (u8 *)malloc(1024000); - if (ptr && (ssize_t)ptr != -1) __afl_area_ptr = ptr; + if (ptr && (ssize_t)ptr != -1) { + + __afl_area_ptr = ptr; + __afl_area_ptr_backup = __afl_area_ptr; + + } } @@ -1304,3 +1387,69 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { } +/* COVERAGE manipulation features */ + +// this variable is then used in the shm setup to create an additional map +// if __afl_map_size > MAP_SIZE or cmplog is used. +// Especially with cmplog this would result in a ~260MB mem increase per +// target run. + +// disable coverage from this point onwards until turned on again +void __afl_coverage_off() { + + if (likely(__afl_selective_coverage)) { + + __afl_area_ptr = __afl_area_ptr_dummy; + __afl_cmp_map = NULL; + + } + +} + +// enable coverage +void __afl_coverage_on() { + + if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) { + + __afl_area_ptr = __afl_area_ptr_backup; + __afl_cmp_map = __afl_cmp_map_backup; + + } + +} + +// discard all coverage up to this point +void __afl_coverage_discard() { + + memset(__afl_area_ptr_backup, 0, __afl_map_size); + __afl_area_ptr_backup[0] = 1; + + if (__afl_cmp_map) { memset(__afl_cmp_map, 0, sizeof(struct cmp_map)); } + +} + +// discard the testcase +void __afl_coverage_skip() { + + __afl_coverage_discard(); + + if (likely(is_persistent && __afl_selective_coverage)) { + + __afl_coverage_off(); + __afl_selective_coverage_temp = 0; + + } else { + + exit(0); + + } + +} + +// mark this area as especially interesting +void __afl_coverage_interesting(u8 val, u32 id) { + + __afl_area_ptr[id] = val; + +} + diff --git a/instrumentation/afl-gcc-pass.so.cc b/instrumentation/afl-gcc-pass.so.cc index 25437609..41bb5152 100644 --- a/instrumentation/afl-gcc-pass.so.cc +++ b/instrumentation/afl-gcc-pass.so.cc @@ -228,7 +228,7 @@ struct afl_pass : gimple_opt_pass { const bool neverZero; /* Count instrumented blocks. */ - int inst_blocks; + unsigned int inst_blocks; virtual unsigned int execute(function *fn) { @@ -444,8 +444,10 @@ struct afl_pass : gimple_opt_pass { DECL_EXTERNAL(decl) = 1; DECL_ARTIFICIAL(decl) = 1; TREE_STATIC(decl) = 1; +#if !defined(__ANDROID__) && !defined(__HAIKU__) set_decl_tls_model( decl, (flag_pic ? TLS_MODEL_INITIAL_EXEC : TLS_MODEL_LOCAL_EXEC)); +#endif return decl; } @@ -920,8 +922,9 @@ int plugin_init(struct plugin_name_args * info, struct plugin_gcc_version *version) { if (!plugin_default_version_check(version, &gcc_version)) - FATAL(G_("GCC and plugin have incompatible versions, expected GCC %d.%d"), - GCCPLUGIN_VERSION_MAJOR, GCCPLUGIN_VERSION_MINOR); + FATAL(G_("GCC and plugin have incompatible versions, expected GCC %s, " + "is %s"), + gcc_version.basever, version->basever); /* Show a banner. */ bool quiet = false; @@ -931,7 +934,7 @@ int plugin_init(struct plugin_name_args * info, quiet = true; /* Decide instrumentation ratio. */ - int inst_ratio = 100; + unsigned int inst_ratio = 100U; if (char *inst_ratio_str = getenv("AFL_INST_RATIO")) if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || !inst_ratio || inst_ratio > 100) diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index bd8eb27a..a4b33732 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -355,7 +355,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { *Str2P = callInst->getArgOperand(1); std::string Str1, Str2; StringRef TmpStr; - bool HasStr1 = getConstantStringInfo(Str1P, TmpStr); + bool HasStr1; + getConstantStringInfo(Str1P, TmpStr); if (TmpStr.empty()) { HasStr1 = false; @@ -367,7 +368,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { } - bool HasStr2 = getConstantStringInfo(Str2P, TmpStr); + bool HasStr2; + getConstantStringInfo(Str2P, TmpStr); if (TmpStr.empty()) { HasStr2 = false; diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 9e026e57..13dca8c4 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -70,7 +70,7 @@ class AFLLTOPass : public ModulePass { if (getenv("AFL_DEBUG")) debug = 1; if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL) if ((afl_global_id = atoi(ptr)) < 0 || afl_global_id >= MAP_SIZE) - FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %d\n", + FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is not between 0 and %u\n", ptr, MAP_SIZE - 1); skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); @@ -100,9 +100,9 @@ class AFLLTOPass : public ModulePass { bool AFLLTOPass::runOnModule(Module &M) { - LLVMContext & C = M.getContext(); - std::vector<std::string> dictionary; - std::vector<CallInst *> calls; + LLVMContext & C = M.getContext(); + std::vector<std::string> dictionary; + // std::vector<CallInst *> calls; DenseMap<Value *, std::string *> valueMap; std::vector<BasicBlock *> BlockList; char * ptr; @@ -471,7 +471,8 @@ bool AFLLTOPass::runOnModule(Module &M) { *Str2P = callInst->getArgOperand(1); std::string Str1, Str2; StringRef TmpStr; - bool HasStr1 = getConstantStringInfo(Str1P, TmpStr); + bool HasStr1; + getConstantStringInfo(Str1P, TmpStr); if (TmpStr.empty()) { HasStr1 = false; @@ -483,7 +484,8 @@ bool AFLLTOPass::runOnModule(Module &M) { } - bool HasStr2 = getConstantStringInfo(Str2P, TmpStr); + bool HasStr2; + getConstantStringInfo(Str2P, TmpStr); if (TmpStr.empty()) { HasStr2 = false; @@ -671,7 +673,6 @@ bool AFLLTOPass::runOnModule(Module &M) { if (!be_quiet) { - std::string outstring; fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen, thestring.length()); for (uint8_t i = 0; i < thestring.length(); i++) { @@ -799,7 +800,7 @@ bool AFLLTOPass::runOnModule(Module &M) { if (documentFile) { - fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%u\n", + fprintf(documentFile, "ModuleID=%llu Function=%s edgeID=%d\n", moduleID, F.getName().str().c_str(), afl_global_id); } @@ -871,10 +872,10 @@ bool AFLLTOPass::runOnModule(Module &M) { while ((map = map >> 1)) pow2map++; WARNF( - "We have %u blocks to instrument but the map size is only %u. Either " - "edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " + "We have %d blocks to instrument but the map size is only %u. Either " + "edit config.h and set MAP_SIZE_POW2 from %d to %u, then recompile " "afl-fuzz and llvm_mode and then make this target - or set " - "AFL_MAP_SIZE with at least size %u when running afl-fuzz with this " + "AFL_MAP_SIZE with at least size %d when running afl-fuzz with this " "target.", afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id); @@ -937,8 +938,7 @@ bool AFLLTOPass::runOnModule(Module &M) { if (dictionary.size()) { - size_t memlen = 0, count = 0, offset = 0; - char * ptr; + size_t memlen = 0, count = 0; // sort and unique the dictionary std::sort(dictionary.begin(), dictionary.end()); @@ -953,14 +953,14 @@ bool AFLLTOPass::runOnModule(Module &M) { } if (!be_quiet) - printf("AUTODICTIONARY: %lu string%s found\n", count, + printf("AUTODICTIONARY: %zu string%s found\n", count, count == 1 ? "" : "s"); if (count) { if ((ptr = (char *)malloc(memlen + count)) == NULL) { - fprintf(stderr, "Error: malloc for %lu bytes failed!\n", + fprintf(stderr, "Error: malloc for %zu bytes failed!\n", memlen + count); exit(-1); @@ -968,6 +968,7 @@ bool AFLLTOPass::runOnModule(Module &M) { count = 0; + size_t offset = 0; for (auto token : dictionary) { if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) { @@ -1031,8 +1032,8 @@ bool AFLLTOPass::runOnModule(Module &M) { getenv("AFL_USE_MSAN") ? ", MSAN" : "", getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - OKF("Instrumented %u locations with no collisions (on average %llu " - "collisions would be in afl-gcc/afl-clang-fast) (%s mode).", + OKF("Instrumented %d locations with no collisions (on average %llu " + "collisions would be in afl-gcc/vanilla AFL) (%s mode).", inst_blocks, calculateCollisions(inst_blocks), modeline); } diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 8c8c987a..57ff3b47 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -241,7 +241,7 @@ bool AFLCoverage::runOnModule(Module &M) { GlobalVariable *AFLContext = NULL; if (ctx_str) -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLContext = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); #else @@ -252,7 +252,7 @@ bool AFLCoverage::runOnModule(Module &M) { #ifdef AFL_HAVE_VECTOR_INTRINSICS if (ngram_size) - #ifdef __ANDROID__ + #if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, PrevLocTy, /* isConstant */ false, GlobalValue::ExternalLinkage, /* Initializer */ nullptr, "__afl_prev_loc"); @@ -265,7 +265,7 @@ bool AFLCoverage::runOnModule(Module &M) { #endif else #endif -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__HAIKU__) AFLPrevLoc = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); #else @@ -327,10 +327,10 @@ bool AFLCoverage::runOnModule(Module &M) { // does the function have calls? and is any of the calls larger than one // basic block? - for (auto &BB : F) { + for (auto &BB_2 : F) { if (has_calls) break; - for (auto &IN : BB) { + for (auto &IN : BB_2) { CallInst *callInst = nullptr; if ((callInst = dyn_cast<CallInst>(&IN))) { @@ -628,7 +628,7 @@ bool AFLCoverage::runOnModule(Module &M) { getenv("AFL_USE_MSAN") ? ", MSAN" : "", getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - OKF("Instrumented %u locations (%s mode, ratio %u%%).", inst_blocks, + OKF("Instrumented %d locations (%s mode, ratio %u%%).", inst_blocks, modeline, inst_ratio); } diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index 9921de0c..3499ccf0 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -186,16 +186,19 @@ bool CmpLogInstructions::hookInstrs(Module &M) { selectcmpInst->getPredicate() == CmpInst::ICMP_UGE || selectcmpInst->getPredicate() == CmpInst::ICMP_SGE || selectcmpInst->getPredicate() == CmpInst::ICMP_ULE || - selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) { - - auto op0 = selectcmpInst->getOperand(0); - auto op1 = selectcmpInst->getOperand(1); - - IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType()); - IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType()); - - /* this is probably not needed but we do it anyway */ - if (!intTyOp0 || !intTyOp1) { continue; } + selectcmpInst->getPredicate() == CmpInst::ICMP_SLE || + selectcmpInst->getPredicate() == CmpInst::FCMP_OGE || + selectcmpInst->getPredicate() == CmpInst::FCMP_UGE || + selectcmpInst->getPredicate() == CmpInst::FCMP_OLE || + selectcmpInst->getPredicate() == CmpInst::FCMP_ULE || + selectcmpInst->getPredicate() == CmpInst::FCMP_OGT || + selectcmpInst->getPredicate() == CmpInst::FCMP_UGT || + selectcmpInst->getPredicate() == CmpInst::FCMP_OLT || + selectcmpInst->getPredicate() == CmpInst::FCMP_ULT || + selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || + selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || + selectcmpInst->getPredicate() == CmpInst::FCMP_UNE || + selectcmpInst->getPredicate() == CmpInst::FCMP_ONE) { icomps.push_back(selectcmpInst); @@ -221,16 +224,66 @@ bool CmpLogInstructions::hookInstrs(Module &M) { auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); - IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType()); - IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType()); + IntegerType * intTyOp0 = NULL; + IntegerType * intTyOp1 = NULL; + unsigned max_size = 0; + std::vector<Value *> args; - unsigned max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() - ? intTyOp0->getBitWidth() - : intTyOp1->getBitWidth(); + if (selectcmpInst->getOpcode() == Instruction::FCmp) { - std::vector<Value *> args; - args.push_back(op0); - args.push_back(op1); + auto ty0 = op0->getType(); + if (ty0->isHalfTy() +#if LLVM_VERSION_MAJOR >= 11 + || ty0->isBFloatTy() +#endif + ) + max_size = 16; + else if (ty0->isFloatTy()) + max_size = 32; + else if (ty0->isDoubleTy()) + max_size = 64; + + if (max_size) { + + Value *V0 = IRB.CreateBitCast(op0, IntegerType::get(C, max_size)); + intTyOp0 = dyn_cast<IntegerType>(V0->getType()); + Value *V1 = IRB.CreateBitCast(op1, IntegerType::get(C, max_size)); + intTyOp1 = dyn_cast<IntegerType>(V1->getType()); + + if (intTyOp0 && intTyOp1) { + + max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() + ? intTyOp0->getBitWidth() + : intTyOp1->getBitWidth(); + args.push_back(V0); + args.push_back(V1); + + } else { + + max_size = 0; + + } + + } + + } else { + + intTyOp0 = dyn_cast<IntegerType>(op0->getType()); + intTyOp1 = dyn_cast<IntegerType>(op1->getType()); + + if (intTyOp0 && intTyOp1) { + + max_size = intTyOp0->getBitWidth() > intTyOp1->getBitWidth() + ? intTyOp0->getBitWidth() + : intTyOp1->getBitWidth(); + args.push_back(op0); + args.push_back(op1); + + } + + } + + if (max_size < 8 || max_size > 64 || !intTyOp0 || !intTyOp1) continue; switch (max_size) { diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index de8b97f0..da5cf7e9 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -68,7 +68,7 @@ class CompareTransform : public ModulePass { const char *getPassName() const override { #else - StringRef getPassName() const override { + StringRef getPassName() const override { #endif return "transforms compare functions"; @@ -101,22 +101,31 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, IntegerType * Int64Ty = IntegerType::getInt64Ty(C); #if LLVM_VERSION_MAJOR < 9 - Constant * + Function *tolowerFn; #else - FunctionCallee + FunctionCallee tolowerFn; #endif - c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty + { + +#if LLVM_VERSION_MAJOR < 9 + Constant * +#else + FunctionCallee +#endif + c = M.getOrInsertFunction("tolower", Int32Ty, Int32Ty #if LLVM_VERSION_MAJOR < 5 - , - NULL + , + NULL #endif - ); + ); #if LLVM_VERSION_MAJOR < 9 - Function *tolowerFn = cast<Function>(c); + tolowerFn = cast<Function>(c); #else - FunctionCallee tolowerFn = c; + tolowerFn = c; #endif + } + /* iterate over all functions, bbs and instruction and add suitable calls to * strcmp/memcmp/strncmp/strcasecmp/strncasecmp */ for (auto &F : M) { @@ -234,7 +243,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, if (!HasStr2) { - auto *Ptr = dyn_cast<ConstantExpr>(Str1P); + Ptr = dyn_cast<ConstantExpr>(Str1P); if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 33a87719..b6d8c466 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -53,7 +53,7 @@ class SplitComparesTransform : public ModulePass { public: static char ID; - SplitComparesTransform() : ModulePass(ID) { + SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) { initInstrumentList(); @@ -555,6 +555,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) { if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || + selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_ONE || selectcmpInst->getPredicate() == CmpInst::FCMP_UNE || selectcmpInst->getPredicate() == CmpInst::FCMP_UGT || @@ -735,6 +736,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock * signequal2_bb = signequal_bb; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_exponent_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); @@ -816,6 +818,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* if the exponents are satifying the compare do a fraction cmp in * middle_bb */ @@ -900,11 +903,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* compare the fractions of the operands */ Instruction *icmp_fraction_result; - Instruction *icmp_fraction_result2; BasicBlock * middle2_bb = middle_bb; PHINode * PN2 = nullptr; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1); @@ -927,6 +930,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_OLT: case CmpInst::FCMP_ULT: { + Instruction *icmp_fraction_result2; + middle2_bb = middle_bb->splitBasicBlock( BasicBlock::iterator(middle_bb->getTerminator())); @@ -980,6 +985,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* unequal signs cannot be equal values */ /* goto false branch */ |