aboutsummaryrefslogtreecommitdiff
path: root/llvm_mode
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_mode')
-rw-r--r--llvm_mode/GNUmakefile3
-rw-r--r--llvm_mode/README.lto.md41
-rw-r--r--llvm_mode/afl-clang-fast.c3
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc330
-rw-r--r--llvm_mode/afl-llvm-rt.o.c170
5 files changed, 485 insertions, 62 deletions
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index 7432b061..b176a24f 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -273,6 +273,7 @@ endif
../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc
ifeq "$(LLVM_LTO)" "1"
$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
+ $(CC) $(CFLAGS) -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
endif
# laf
@@ -318,7 +319,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 $${DESTDIR}$(HELPER_PATH); install -m 755 ../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-rt-lto.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md
index a3c7ddc3..48d0e36c 100644
--- a/llvm_mode/README.lto.md
+++ b/llvm_mode/README.lto.md
@@ -12,6 +12,8 @@ This version requires a current llvm 11 compiled from the github master.
3. It only works with llvm 11 (current github master state)
+4. AUTODICTIONARY feature! see below
+
## Introduction and problem description
A big issue with how afl/afl++ works is that the basic block IDs that are
@@ -33,33 +35,22 @@ and many dead ends until we got to this:
* Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the
correct LTO options and runs our own afl-ld linker instead of the system
linker
- * Our linker collects all LTO files to link and instruments them so that
+ * The LLVM linker collects all LTO files to link and instruments them so that
we have non-colliding edge overage
* We use a new (for afl) edge coverage - which is the same as in llvm
-fsanitize=coverage edge coverage mode :)
- * after inserting our instrumentation in all interesting edges we link
- all parts of the program together to our executable
The result:
- * 10-15% speed gain compared to llvm_mode
+ * 10-20% speed gain compared to llvm_mode
* guaranteed non-colliding edge coverage :-)
* The compile time especially for libraries can be longer
Example build output from a libtiff build:
```
-/bin/bash ../libtool --tag=CC --mode=link afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/libtiff.la ../port/libport.la -llzma -ljbig -ljpeg -lz -lm
libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm
-afl-clang-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
-afl-ld++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de> (level 0)
-[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../libtiff/.libs/libtiff.a into /tmp/.afl-3914343-1583339800.dir
-[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../port/.libs/libport.a into /tmp/.afl-3914343-1583339800.dir
-[+] Running bitcode linker, creating /tmp/.afl-3914343-1583339800-1.ll
-[+] Performing optimization via opt, creating /tmp/.afl-3914343-1583339800-2.bc
-[+] Performing instrumentation via opt, creating /tmp/.afl-3914343-1583339800-3.bc
-afl-llvm-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
-[+] Instrumented 15833 locations with no collisions (on average 1767 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
-[+] Running real linker /bin/x86_64-linux-gnu-ld
-[+] Linker was successful
+afl-clang-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de> in mode LTO
+afl-llvm-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de>
+[+] Instrumented 11836 locations with no collisions (on average 1007 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
```
## Building llvm 11
@@ -70,8 +61,8 @@ $ git clone https://github.com/llvm/llvm-project
$ cd llvm-project
$ mkdir build
$ cd build
-$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/
-$ make
+$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/
+$ make -j $(nproc)
$ export PATH=`pwd`/bin:$PATH
$ export LLVM_CONFIG=`pwd`/bin/llcm-config
$ cd /path/to/AFLplusplus/
@@ -96,6 +87,13 @@ CC=afl-clang-lto CXX=afl-clang-lto++ ./configure
make
```
+## AUTODICTIONARY feature
+
+Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the
+target binary based on string compare and memory compare functions.
+afl-fuzz will automatically get these transmitted when starting to fuzz.
+This improves coverage on a lot of targets.
+
## Potential issues
### compiling libraries fails
@@ -121,11 +119,8 @@ Please report issues at:
## Upcoming Work
-1. Currently the LTO whitelist feature does not allow to not instrument main, start and init functions
-2. Modify the forkserver + afl-fuzz so that only the necessary map size is
- loaded and used - and communicated to afl-fuzz too.
- Result: faster fork in the target and faster map analysis in afl-fuzz
- => more speed :-)
+1. Currently the LTO whitelist feature does not allow to not instrument main,
+ start and init functions
## History
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index 26ee0bab..cdb22cb9 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -477,6 +477,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
+ if (instrument_mode == INSTRUMENT_LTO)
+ cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
+
#ifndef __ANDROID__
switch (bit_mode) {
diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
index 93968984..f387e79c 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -38,17 +38,24 @@
#include <sys/time.h>
#include "llvm/Config/llvm-config.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Verifier.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/CFG.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Pass.h"
+
+#include <set>
using namespace llvm;
@@ -145,7 +152,7 @@ class AFLLTOPass : public ModulePass {
bool runOnModule(Module &M) override;
protected:
- int afl_global_id = 1, debug = 0;
+ int afl_global_id = 1, debug = 0, autodictionary = 0;
uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
};
@@ -154,7 +161,9 @@ class AFLLTOPass : public ModulePass {
bool AFLLTOPass::runOnModule(Module &M) {
- LLVMContext &C = M.getContext();
+ LLVMContext & C = M.getContext();
+ std::vector<std::string> dictionary;
+ std::vector<CallInst *> calls;
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
@@ -172,6 +181,10 @@ bool AFLLTOPass::runOnModule(Module &M) {
be_quiet = 1;
+ if (getenv("AFL_LLVM_AUTODICTIONARY") ||
+ getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
+ autodictionary = 1;
+
/* Get globals for the SHM region and the previous location. Note that
__afl_prev_loc is thread-local. */
@@ -193,6 +206,110 @@ bool AFLLTOPass::runOnModule(Module &M) {
std::vector<BasicBlock *> InsBlocks;
+ if (autodictionary) {
+
+ for (auto &BB : F) {
+
+ for (auto &IN : BB) {
+
+ CallInst *callInst = nullptr;
+
+ if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+ bool isStrcmp = true;
+ bool isMemcmp = true;
+ bool isStrncmp = true;
+ bool isStrcasecmp = true;
+ bool isStrncasecmp = true;
+
+ Function *Callee = callInst->getCalledFunction();
+ if (!Callee) continue;
+ if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+ StringRef FuncName = Callee->getName();
+ isStrcmp &= !FuncName.compare(StringRef("strcmp"));
+ isMemcmp &= !FuncName.compare(StringRef("memcmp"));
+ isStrncmp &= !FuncName.compare(StringRef("strncmp"));
+ isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp"));
+ isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp"));
+
+ if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+ !isStrncasecmp)
+ continue;
+
+ /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
+ * prototype */
+ FunctionType *FT = Callee->getFunctionType();
+
+ isStrcmp &= FT->getNumParams() == 2 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext());
+ isStrcasecmp &= FT->getNumParams() == 2 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext());
+ isMemcmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0)->isPointerTy() &&
+ FT->getParamType(1)->isPointerTy() &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+ isStrncasecmp &= FT->getNumParams() == 3 &&
+ FT->getReturnType()->isIntegerTy(32) &&
+ FT->getParamType(0) == FT->getParamType(1) &&
+ FT->getParamType(0) ==
+ IntegerType::getInt8PtrTy(M.getContext()) &&
+ FT->getParamType(2)->isIntegerTy();
+
+ if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+ !isStrncasecmp)
+ continue;
+
+ /* is a str{n,}{case,}cmp/memcmp, check if we have
+ * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
+ * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
+ * memcmp(x, "const", ..) or memcmp("const", x, ..) */
+ Value *Str1P = callInst->getArgOperand(0),
+ *Str2P = callInst->getArgOperand(1);
+ StringRef Str1, Str2;
+ bool HasStr1 = getConstantStringInfo(Str1P, Str1);
+ bool HasStr2 = getConstantStringInfo(Str2P, Str2);
+
+ /* handle cases of one string is const, one string is variable */
+ if (!(HasStr1 ^ HasStr2)) continue;
+
+ if (isMemcmp || isStrncmp || isStrncasecmp) {
+
+ /* check if third operand is a constant integer
+ * strlen("constStr") and sizeof() are treated as constant */
+ Value * op2 = callInst->getArgOperand(2);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+ if (!ilen) continue;
+ /* final precaution: if size of compare is larger than constant
+ * string skip it*/
+ uint64_t literalLength =
+ HasStr1 ? GetStringLength(Str1P) : GetStringLength(Str2P);
+ if (literalLength < ilen->getZExtValue()) continue;
+
+ }
+
+ calls.push_back(callInst);
+
+ }
+
+ }
+
+ }
+
+ }
+
for (auto &BB : F) {
uint32_t succ = 0;
@@ -282,32 +399,201 @@ bool AFLLTOPass::runOnModule(Module &M) {
}
+ // save highest location ID to global variable
+ // do this after each function to fail faster
+ if (afl_global_id > MAP_SIZE) {
+
+ uint32_t pow2map = 1, map = afl_global_id;
+ while ((map = map >> 1))
+ pow2map++;
+ FATAL(
+ "We have %u blocks to instrument but the map size is only %u! Edit "
+ "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
+ "afl-fuzz and llvm_mode.",
+ afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map);
+
+ }
+
}
- // save highest location ID to global variable
+ if (calls.size()) {
- if (afl_global_id > MAP_SIZE) {
+ for (auto &callInst : calls) {
- uint32_t pow2map = 1, map = afl_global_id;
- while ((map = map >> 1))
- pow2map++;
- FATAL(
- "We have %u blocks to instrument but the map size is only %u! Edit "
- "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
- "afl-fuzz and llvm_mode.",
- afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map);
+ Value *Str1P = callInst->getArgOperand(0),
+ *Str2P = callInst->getArgOperand(1);
+ StringRef Str1, Str2, ConstStr;
+ std::string TmpConstStr;
+ Value * VarStr;
+ bool HasStr1 = getConstantStringInfo(Str1P, Str1);
+ getConstantStringInfo(Str2P, Str2);
+ uint64_t constLen, sizedLen;
+ bool isMemcmp = !callInst->getCalledFunction()->getName().compare(
+ StringRef("memcmp"));
+ bool isSizedcmp = isMemcmp ||
+ !callInst->getCalledFunction()->getName().compare(
+ StringRef("strncmp")) ||
+ !callInst->getCalledFunction()->getName().compare(
+ StringRef("strncasecmp"));
+
+ if (isSizedcmp) {
+
+ Value * op2 = callInst->getArgOperand(2);
+ ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+ sizedLen = ilen->getZExtValue();
+
+ } else {
+
+ sizedLen = 0;
+
+ }
+
+ if (HasStr1) {
+
+ TmpConstStr = Str1.str();
+ VarStr = Str2P;
+ constLen = isMemcmp ? sizedLen : GetStringLength(Str1P);
+
+ } else {
+
+ TmpConstStr = Str2.str();
+ VarStr = Str1P;
+ constLen = isMemcmp ? sizedLen : GetStringLength(Str2P);
+
+ }
+
+ /* properly handle zero terminated C strings by adding the terminating 0
+ * to the StringRef (in comparison to std::string a StringRef has built-in
+ * runtime bounds checking, which makes debugging easier) */
+ TmpConstStr.append("\0", 1);
+ ConstStr = StringRef(TmpConstStr);
+
+ if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; }
+
+ /*
+ if (!be_quiet)
+ errs() << callInst->getCalledFunction()->getName() << ": len "
+ << constLen << ": " << ConstStr << "\n";
+ */
+
+ if (constLen && constLen < MAX_DICT_FILE)
+ dictionary.push_back(ConstStr.str().substr(0, constLen));
+
+ }
}
- if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
+ if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL || dictionary.size()) {
+
+ // yes we could create our own function, insert it into ctors ...
+ // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
- GlobalVariable *AFLFinalLoc = new GlobalVariable(
- M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", 0,
- GlobalVariable::GeneralDynamicTLSModel, 0, false);
- ConstantInt *const_loc = ConstantInt::get(Int32Ty, afl_global_id);
- MaybeAlign Align = MaybeAlign(4);
- AFLFinalLoc->setAlignment(Align);
- AFLFinalLoc->setInitializer(const_loc);
+ Function *f = M.getFunction("__afl_auto_init_globals");
+
+ if (!f) {
+
+ fprintf(stderr,
+ "Error: init function could not be found (this hould not "
+ "happen)\n");
+ exit(-1);
+
+ }
+
+ BasicBlock *bb = &f->getEntryBlock();
+ if (!bb) {
+
+ fprintf(stderr,
+ "Error: init function does not have an EntryBlock (this should "
+ "not happen)\n");
+ exit(-1);
+
+ }
+
+ BasicBlock::iterator IP = bb->getFirstInsertionPt();
+ IRBuilder<> IRB(&(*IP));
+
+ if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
+
+ GlobalVariable *AFLFinalLoc = new GlobalVariable(
+ M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc",
+ 0, GlobalVariable::GeneralDynamicTLSModel, 0, false);
+ ConstantInt *const_loc = ConstantInt::get(Int32Ty, (((afl_global_id + 8) >> 3) << 3));
+ StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
+ StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ }
+
+ if (dictionary.size()) {
+
+ size_t memlen = 0, count = 0, offset = 0;
+ char * ptr;
+
+ for (auto token : dictionary) {
+
+ memlen += token.length();
+ count++;
+
+ }
+
+ if (!be_quiet) printf("AUTODICTIONARY: %lu strings found\n", count);
+
+ if (count) {
+
+ if ((ptr = (char *)malloc(memlen + count)) == NULL) {
+
+ fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
+ memlen + count);
+ exit(-1);
+
+ }
+
+ for (auto token : dictionary) {
+
+ if (offset + token.length() < 0xfffff0) {
+
+ ptr[offset++] = (uint8_t)token.length();
+ memcpy(ptr + offset, token.c_str(), token.length());
+ offset += token.length();
+
+ }
+
+ }
+
+ GlobalVariable *AFLDictionaryLen = new GlobalVariable(
+ M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
+ "__afl_dictionary_len", 0, GlobalVariable::GeneralDynamicTLSModel,
+ 0, false);
+ ConstantInt *const_len = ConstantInt::get(Int32Ty, offset);
+ StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen);
+ StoreDictLen->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset);
+ GlobalVariable *AFLInternalDictionary = new GlobalVariable(
+ M, ArrayTy, true, GlobalValue::ExternalLinkage,
+ ConstantDataArray::get(C,
+ *(new ArrayRef<char>((char *)ptr, offset))),
+ "__afl_internal_dictionary", 0,
+ GlobalVariable::GeneralDynamicTLSModel, 0, false);
+ AFLInternalDictionary->setInitializer(ConstantDataArray::get(
+ C, *(new ArrayRef<char>((char *)ptr, offset))));
+ AFLInternalDictionary->setConstant(true);
+
+ GlobalVariable *AFLDictionary = new GlobalVariable(
+ M, PointerType::get(Int8Ty, 0), false, GlobalValue::ExternalLinkage,
+ 0, "__afl_dictionary");
+
+ Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero);
+ Value *AFLDictPtr =
+ IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0));
+ StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
+ StoreDict->setMetadata(M.getMDKindID("nosanitize"),
+ MDNode::get(C, None));
+
+ }
+
+ }
}
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index 3651fd97..cbc4648d 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -50,11 +50,7 @@
Basically, we need to make sure that the forkserver is initialized after
the LLVM-generated runtime initialization pass, not before. */
-#ifdef USE_TRACE_PC
#define CONST_PRIO 5
-#else
-#define CONST_PRIO 0
-#endif /* ^USE_TRACE_PC */
#include <sys/mman.h>
#include <fcntl.h>
@@ -65,17 +61,20 @@
u8 __afl_area_initial[MAP_SIZE];
u8 *__afl_area_ptr = __afl_area_initial;
+u8 *__afl_dictionary;
#ifdef __ANDROID__
PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
u32 __afl_final_loc;
u32 __afl_prev_ctx;
u32 __afl_cmp_counter;
+u32 __afl_dictionary_len;
#else
__thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
__thread u32 __afl_final_loc;
__thread u32 __afl_prev_ctx;
__thread u32 __afl_cmp_counter;
+__thread u32 __afl_dictionary_len;
#endif
struct cmp_map *__afl_cmp_map;
@@ -100,6 +99,10 @@ static void __afl_map_shm(void) {
const char * shm_file_path = id_str;
int shm_fd = -1;
unsigned char *shm_base = NULL;
+ unsigned int map_size = MAP_SIZE
+
+ if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) map_size =
+ __afl_final_loc;
/* create the shared memory segment as if it was a file */
shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
@@ -111,7 +114,7 @@ static void __afl_map_shm(void) {
}
/* map the shared memory segment to the address space of the process */
- shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+ shm_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm_base == MAP_FAILED) {
close(shm_fd);
@@ -187,8 +190,15 @@ static void __afl_map_shm(void) {
#ifdef __linux__
static void __afl_start_snapshots(void) {
- static u8 tmp[4];
+ static u8 tmp[4] = {0, 0, 0, 0};
s32 child_pid;
+ u32 status = 0;
+ u32 map_size = MAP_SIZE;
+ u32 already_read_first = 0;
+ u32 was_killed;
+
+ if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
+ map_size = __afl_final_loc;
u8 child_stopped = 0;
@@ -197,16 +207,74 @@ static void __afl_start_snapshots(void) {
/* 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. */
+ status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT);
+ if (map_size <= 0x1000000)
+ status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE);
+ if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
+ memcpy(tmp, &status, 4);
+
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
+ if (__afl_dictionary_len > 0 && __afl_dictionary) {
+
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+ if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
+ (FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
+
+ // 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) {
+
+ write(2, "Error: could not send dictionary len\n",
+ strlen("Error: could not send dictionary len\n"));
+ _exit(1);
+
+ }
+
+ while (len != 0) {
+
+ ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
+
+ if (ret < 1) {
+
+ write(2, "Error: could not send dictionary\n",
+ strlen("Error: could not send dictionary\n"));
+ _exit(1);
+
+ }
+
+ len -= ret;
+ offset += ret;
+
+ }
+
+ } else {
+
+ // uh this forkserver master does not understand extended option passing
+ // or does not want the dictionary
+ already_read_first = 1;
+
+ }
+
+ }
+
while (1) {
- u32 was_killed;
int status;
- /* Wait for parent by reading from the pipe. Abort if read fails. */
+ if (already_read_first) {
- if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+ already_read_first = 0;
+
+ } else {
+
+ /* Wait for parent by reading from the pipe. Abort if read fails. */
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+ }
/* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old
@@ -291,26 +359,92 @@ static void __afl_start_forkserver(void) {
#endif
- static u8 tmp[4];
- s32 child_pid;
+ u8 tmp[4] = {0, 0, 0, 0};
+ s32 child_pid;
+ u32 status = 0;
+ u32 map_size = MAP_SIZE;
+ u32 already_read_first = 0;
+ u32 was_killed;
+
+ if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
+ map_size = __afl_final_loc;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL);
+ if (map_size <= 0x1000000)
+ status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE);
+ if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
+ if (status) status |= (FS_OPT_ENABLED);
+ memcpy(tmp, &status, 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 (__afl_dictionary_len > 0 && __afl_dictionary) {
+
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+ if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
+ (FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
+
+ // 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) {
+
+ write(2, "Error: could not send dictionary len\n",
+ strlen("Error: could not send dictionary len\n"));
+ _exit(1);
+
+ }
+
+ while (len != 0) {
+
+ ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
+
+ if (ret < 1) {
+
+ write(2, "Error: could not send dictionary\n",
+ strlen("Error: could not send dictionary\n"));
+ _exit(1);
+
+ }
+
+ len -= ret;
+ offset += ret;
+
+ }
+
+ } else {
+
+ // uh this forkserver master does not understand extended option passing
+ // or does not want the dictionary
+ already_read_first = 1;
+
+ }
+
+ }
+
while (1) {
- u32 was_killed;
int status;
/* Wait for parent by reading from the pipe. Abort if read fails. */
- if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+ if (already_read_first) {
+
+ already_read_first = 0;
+
+ } else {
+
+ if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+ }
/* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old
@@ -378,8 +512,12 @@ static void __afl_start_forkserver(void) {
int __afl_persistent_loop(unsigned int max_cnt) {
- static u8 first_pass = 1;
- static u32 cycle_cnt;
+ static u8 first_pass = 1;
+ static u32 cycle_cnt;
+ unsigned int map_size = MAP_SIZE;
+
+ if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
+ map_size = __afl_final_loc;
if (first_pass) {
@@ -390,7 +528,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
if (is_persistent) {
- memset(__afl_area_ptr, 0, MAP_SIZE);
+ memset(__afl_area_ptr, 0, map_size);
__afl_area_ptr[0] = 1;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));