mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
c89946fc19 | |||
3136ad5bca | |||
50311d5a6a | |||
748da4ee16 | |||
6d5e5484b6 | |||
37de3ba212 | |||
2a13c8b497 | |||
87be884221 | |||
ff168fe3eb | |||
dce29b1e7d | |||
518b13827b | |||
b7a2999c03 | |||
a86659f834 | |||
917c0bf1d7 |
@ -299,7 +299,7 @@ ifeq "$(TEST_MMAP)" "1"
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
|
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./libLLVMInsTrim.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so ./afl-llvm-unreachable.so
|
||||||
|
|
||||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||||
ifeq "$(LLVMVER)" ""
|
ifeq "$(LLVMVER)" ""
|
||||||
@ -429,7 +429,10 @@ endif
|
|||||||
./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||||
|
|
||||||
afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
|
./afl-llvm-unreachable.so: instrumentation/afl-llvm-unreachable.cc instrumentation/afl-llvm-common.o | test_deps
|
||||||
|
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||||
|
|
||||||
|
./afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||||
|
|
||||||
.PHONY: document
|
.PHONY: document
|
||||||
|
@ -156,6 +156,8 @@ Then there are a few specific features that are only available in instrumentatio
|
|||||||
This defaults to 1
|
This defaults to 1
|
||||||
- `AFL_LLVM_LTO_DONTWRITEID` prevents that the highest location ID written
|
- `AFL_LLVM_LTO_DONTWRITEID` prevents that the highest location ID written
|
||||||
into the instrumentation is set in a global variable
|
into the instrumentation is set in a global variable
|
||||||
|
- `AFL_LLVM_LTO_UNREACHABLE` will *not* instrument the binary for fuzzing but
|
||||||
|
instead perform an analysis on unreachable functions
|
||||||
|
|
||||||
See [instrumentation/README.lto.md](../instrumentation/README.lto.md) for more information.
|
See [instrumentation/README.lto.md](../instrumentation/README.lto.md) for more information.
|
||||||
|
|
||||||
|
@ -102,8 +102,9 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_LLVM_INSTRUMENT_FILE",
|
"AFL_LLVM_INSTRUMENT_FILE",
|
||||||
"AFL_LLVM_SKIP_NEVERZERO",
|
"AFL_LLVM_SKIP_NEVERZERO",
|
||||||
"AFL_NO_AFFINITY",
|
"AFL_NO_AFFINITY",
|
||||||
"AFL_LLVM_LTO_STARTID",
|
"AFL_LLVM_LTO_UNREACHABLE",
|
||||||
"AFL_LLVM_LTO_DONTWRITEID",
|
"AFL_LLVM_LTO_DONTWRITEID",
|
||||||
|
"AFL_LLVM_LTO_STARTID",
|
||||||
"AFL_NO_ARITH",
|
"AFL_NO_ARITH",
|
||||||
"AFL_NO_AUTODICT",
|
"AFL_NO_AUTODICT",
|
||||||
"AFL_NO_BUILTIN",
|
"AFL_NO_BUILTIN",
|
||||||
|
@ -57,23 +57,28 @@ bool isIgnoreFunction(const llvm::Function *F) {
|
|||||||
|
|
||||||
static const char *ignoreList[] = {
|
static const char *ignoreList[] = {
|
||||||
|
|
||||||
"asan.",
|
".module_",
|
||||||
"llvm.",
|
"__sanitizer", // maybe we should drop anything starting with "__"?
|
||||||
"sancov.",
|
"__local",
|
||||||
"__ubsan_",
|
"__ubsan",
|
||||||
"ign.",
|
|
||||||
"__afl_",
|
"__afl_",
|
||||||
"_fini",
|
"__libc_",
|
||||||
"__libc_csu",
|
|
||||||
"__asan",
|
"__asan",
|
||||||
"__msan",
|
"__msan",
|
||||||
"__cmplog",
|
"__cmplog",
|
||||||
"__sancov",
|
"__sancov",
|
||||||
|
"__clang",
|
||||||
|
"__gnu",
|
||||||
|
"__decide_deferred",
|
||||||
|
"_fini",
|
||||||
|
"ign.", // compiler specifics
|
||||||
|
"llvm.",
|
||||||
|
"asan.",
|
||||||
|
"sancov.",
|
||||||
"msan.",
|
"msan.",
|
||||||
"LLVMFuzzerM",
|
"LLVMFuzzerM", // fuzzing framework specifics
|
||||||
"LLVMFuzzerC",
|
"LLVMFuzzerC",
|
||||||
"LLVMFuzzerI",
|
"LLVMFuzzerI",
|
||||||
"__decide_deferred",
|
|
||||||
"maybe_duplicate_stderr",
|
"maybe_duplicate_stderr",
|
||||||
"discard_output",
|
"discard_output",
|
||||||
"close_stdout",
|
"close_stdout",
|
||||||
|
512
instrumentation/afl-llvm-unreachable.cc
Normal file
512
instrumentation/afl-llvm-unreachable.cc
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
/*
|
||||||
|
american fuzzy lop++ - LLVM Dead Function Analysis
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Written by Marc Heuse <mh@mh-sec.de>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include "llvm/Config/llvm-config.h"
|
||||||
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/IR/IRBuilder.h"
|
||||||
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
|
#include "llvm/IR/Module.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/Pass.h"
|
||||||
|
#include "llvm/Analysis/ValueTracking.h"
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR > 3 || \
|
||||||
|
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||||
|
#include "llvm/IR/Verifier.h"
|
||||||
|
#include "llvm/IR/DebugInfo.h"
|
||||||
|
#else
|
||||||
|
#include "llvm/Analysis/Verifier.h"
|
||||||
|
#include "llvm/DebugInfo.h"
|
||||||
|
#define nullptr 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include "config.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "afl-llvm-common.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class Unreachable : public ModulePass {
|
||||||
|
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
Unreachable() : ModulePass(ID) {
|
||||||
|
|
||||||
|
initInstrumentList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool runOnModule(Module &M) override;
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR < 4
|
||||||
|
const char *getPassName() const override {
|
||||||
|
|
||||||
|
#else
|
||||||
|
StringRef getPassName() const override {
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return "cmplog instructions";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool hookInstrs(Module &M);
|
||||||
|
bool is_in_function_list(std::string);
|
||||||
|
Function *get_next_follow_function(Module &M);
|
||||||
|
void add_to_follow_list(Module &M, std::string func);
|
||||||
|
void remove_from_function_list(std::string fname);
|
||||||
|
void extract_all_plain_constants(std::vector<Value *> *all_constants,
|
||||||
|
Value * V);
|
||||||
|
|
||||||
|
std::vector<std::string> all_functions;
|
||||||
|
std::vector<std::string> follow;
|
||||||
|
int debug = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
char Unreachable::ID = 0;
|
||||||
|
bool isIgnoreFunction(const llvm::Function *F);
|
||||||
|
|
||||||
|
/* Check if a function is our total function list */
|
||||||
|
bool Unreachable::is_in_function_list(std::string fname) {
|
||||||
|
|
||||||
|
std::vector<std::string>::iterator it =
|
||||||
|
std::find(all_functions.begin(), all_functions.end(), fname);
|
||||||
|
if (it != all_functions.end()) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the next entry in the function list we follow */
|
||||||
|
Function *Unreachable::get_next_follow_function(Module &M) {
|
||||||
|
|
||||||
|
std::string fname = follow.front();
|
||||||
|
follow.erase(follow.begin());
|
||||||
|
return M.getFunction(fname);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove an entry from the list of all functions */
|
||||||
|
void Unreachable::remove_from_function_list(std::string fname) {
|
||||||
|
|
||||||
|
std::vector<std::string>::iterator it =
|
||||||
|
std::find(all_functions.begin(), all_functions.end(), fname);
|
||||||
|
if (it != all_functions.end()) { all_functions.erase(it); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A function that is called in a function we follow - so follow it too */
|
||||||
|
void Unreachable::add_to_follow_list(Module &M, std::string fname) {
|
||||||
|
|
||||||
|
Function *F = M.getFunction(fname);
|
||||||
|
|
||||||
|
std::vector<std::string>::iterator it =
|
||||||
|
std::find(all_functions.begin(), all_functions.end(), fname);
|
||||||
|
if (it != all_functions.end()) {
|
||||||
|
|
||||||
|
all_functions.erase(it);
|
||||||
|
if (!F || !F->size()) return;
|
||||||
|
if (!isInInstrumentList(F)) return;
|
||||||
|
follow.push_back(fname);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GlobalVariables can be structs that contain arrays that contain ...
|
||||||
|
This is all broken up here until we only have raw Constant parameters */
|
||||||
|
void Unreachable::extract_all_plain_constants(
|
||||||
|
std::vector<Value *> *all_constants, Value *V) {
|
||||||
|
|
||||||
|
auto CS = dyn_cast<ConstantStruct>(V);
|
||||||
|
auto CA = dyn_cast<ConstantArray>(V);
|
||||||
|
auto CV = dyn_cast<ConstantVector>(V);
|
||||||
|
unsigned int i = 0;
|
||||||
|
Constant * C;
|
||||||
|
|
||||||
|
if (CS) {
|
||||||
|
|
||||||
|
while ((C = CS->getAggregateElement(i++))) {
|
||||||
|
|
||||||
|
extract_all_plain_constants(all_constants,
|
||||||
|
C->stripPointerCastsAndAliases());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (CA) {
|
||||||
|
|
||||||
|
while ((C = CA->getAggregateElement(i++))) {
|
||||||
|
|
||||||
|
extract_all_plain_constants(all_constants,
|
||||||
|
C->stripPointerCastsAndAliases());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (CV) {
|
||||||
|
|
||||||
|
while ((C = CV->getAggregateElement(i++))) {
|
||||||
|
|
||||||
|
extract_all_plain_constants(all_constants,
|
||||||
|
C->stripPointerCastsAndAliases());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
all_constants->push_back(V);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Unreachable::hookInstrs(Module &M) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (debug) { // needs an llvm debug build!
|
||||||
|
int i = 0;
|
||||||
|
for (auto &F : M)
|
||||||
|
// if (F.getName().compare("foo") == 0)
|
||||||
|
for (auto &BB : F)
|
||||||
|
for (auto &IN : BB) {
|
||||||
|
|
||||||
|
fprintf(stderr, "%d: ", ++i);
|
||||||
|
IN.dump();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Grab all functions */
|
||||||
|
for (auto &F : M) {
|
||||||
|
|
||||||
|
if (F.size() && !isIgnoreFunction(&F)) {
|
||||||
|
|
||||||
|
if (debug) fprintf(stderr, "ADD: %s\n", F.getName().str().c_str());
|
||||||
|
all_functions.push_back(F.getName().str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add CTORs and DTORs - if they should be followed */
|
||||||
|
GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors");
|
||||||
|
if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) {
|
||||||
|
|
||||||
|
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
|
||||||
|
|
||||||
|
if (InitList) {
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
||||||
|
|
||||||
|
if (ConstantStruct *CS =
|
||||||
|
dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
|
||||||
|
|
||||||
|
if (CS->getNumOperands() >= 2) {
|
||||||
|
|
||||||
|
if (CS->getOperand(1)->isNullValue())
|
||||||
|
break; // Found a null terminator, stop here.
|
||||||
|
|
||||||
|
Constant *FP = CS->getOperand(1);
|
||||||
|
|
||||||
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
|
||||||
|
if (CE->isCast()) FP = CE->getOperand(0);
|
||||||
|
if (Function *F = dyn_cast<Function>(FP)) {
|
||||||
|
|
||||||
|
if (!F->isDeclaration()) {
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, "Adding CTOR: %s\n",
|
||||||
|
F->getName().str().c_str());
|
||||||
|
add_to_follow_list(M, F->getName().str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GV = M.getNamedGlobal("llvm.global_dtors");
|
||||||
|
if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) {
|
||||||
|
|
||||||
|
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
|
||||||
|
|
||||||
|
if (InitList) {
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
||||||
|
|
||||||
|
if (ConstantStruct *CS =
|
||||||
|
dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
|
||||||
|
|
||||||
|
if (CS->getNumOperands() >= 2) {
|
||||||
|
|
||||||
|
if (CS->getOperand(1)->isNullValue())
|
||||||
|
break; // Found a null terminator, stop here.
|
||||||
|
|
||||||
|
Constant *FP = CS->getOperand(1);
|
||||||
|
|
||||||
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
|
||||||
|
if (CE->isCast()) FP = CE->getOperand(0);
|
||||||
|
|
||||||
|
if (Function *F = dyn_cast<Function>(FP)) {
|
||||||
|
|
||||||
|
if (!F->isDeclaration()) {
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, "Adding DTOR: %s\n",
|
||||||
|
F->getName().str().c_str());
|
||||||
|
add_to_follow_list(M, F->getName().str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search and add starter functions */
|
||||||
|
if (is_in_function_list("LLVMFuzzerTestOneInput")) {
|
||||||
|
|
||||||
|
add_to_follow_list(M, "LLVMFuzzerTestOneInput");
|
||||||
|
if (is_in_function_list("LLVMFuzzerInitialize"))
|
||||||
|
add_to_follow_list(M, "LLVMFuzzerInitialize");
|
||||||
|
|
||||||
|
} else if (is_in_function_list("main")) {
|
||||||
|
|
||||||
|
add_to_follow_list(M, "main");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
fprintf(stderr, "Error: no main() or LLVMFuzzerTestOneInput() found!\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here happens the magic -> static analysis of all functions to follow */
|
||||||
|
while (follow.size()) {
|
||||||
|
|
||||||
|
Function *F = get_next_follow_function(M);
|
||||||
|
if (!F || !F->size()) { continue; }
|
||||||
|
|
||||||
|
if (debug) fprintf(stderr, "Following: %s\n", F->getName().str().c_str());
|
||||||
|
|
||||||
|
for (auto &BB : *F) {
|
||||||
|
|
||||||
|
for (auto &IN : BB) {
|
||||||
|
|
||||||
|
auto SI = dyn_cast<StoreInst>(&IN);
|
||||||
|
if (SI) {
|
||||||
|
|
||||||
|
auto V = SI->getValueOperand()->stripPointerCastsAndAliases();
|
||||||
|
if (V) {
|
||||||
|
|
||||||
|
auto T = V->getType();
|
||||||
|
if (T && T->isPointerTy()) {
|
||||||
|
|
||||||
|
// This is C++ class + virtual function support
|
||||||
|
auto VV = V->stripInBoundsOffsets();
|
||||||
|
auto *G = dyn_cast<GlobalVariable>(VV);
|
||||||
|
if (G && G->hasInitializer()) {
|
||||||
|
|
||||||
|
Constant * GV = G->getInitializer();
|
||||||
|
std::vector<Value *> all_constants;
|
||||||
|
Value * VV = dyn_cast<Value>(GV);
|
||||||
|
extract_all_plain_constants(&all_constants, VV);
|
||||||
|
for (auto C : all_constants) {
|
||||||
|
|
||||||
|
Function *f = dyn_cast<Function>(C);
|
||||||
|
if (f) {
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, "F:%s Store isFunction %s\n",
|
||||||
|
F->getName().str().c_str(),
|
||||||
|
f->getName().str().c_str());
|
||||||
|
// this is wrong here, needs static analysis
|
||||||
|
add_to_follow_list(M, f->getName().str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isa<FunctionType>(T->getPointerElementType())) {
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, "F:%s Store isFunction",
|
||||||
|
F->getName().str().c_str());
|
||||||
|
Function *f = dyn_cast<Function>(V);
|
||||||
|
if (f) {
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, " \"%s\"\n", f->getName().str().c_str());
|
||||||
|
// this is wrong here, needs static analysis
|
||||||
|
add_to_follow_list(M, f->getName().str());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (debug) fprintf(stderr, " <unknown>\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CI = dyn_cast<CallInst>(&IN);
|
||||||
|
if (CI) {
|
||||||
|
|
||||||
|
Function *Callee = CI->getCalledFunction();
|
||||||
|
if (Callee) add_to_follow_list(M, Callee->getName().str());
|
||||||
|
|
||||||
|
for (int i = 0; i < CI->getNumArgOperands(); i++) {
|
||||||
|
|
||||||
|
auto O = CI->getArgOperand(i);
|
||||||
|
auto T = O->getType();
|
||||||
|
if (T && T->isPointerTy()) {
|
||||||
|
|
||||||
|
if (isa<FunctionType>(T->getPointerElementType())) {
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, "F:%s call %s ", F->getName().str().c_str(),
|
||||||
|
Callee->getName().str().c_str());
|
||||||
|
if (debug) fprintf(stderr, "isFunctionPtr[%d]", i);
|
||||||
|
Function *f =
|
||||||
|
dyn_cast<Function>(O->stripPointerCastsAndAliases());
|
||||||
|
if (f) {
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
fprintf(stderr, " \"%s\"\n", f->getName().str().c_str());
|
||||||
|
add_to_follow_list(M, f->getName().str());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (debug) fprintf(stderr, " <unknown>\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// print all functions not visited, however drop __*, std:: and gnu::
|
||||||
|
std::regex re1("(^__*[A-Z0-9][A-Z0-9]*_*)([a-z]*)(.*)");
|
||||||
|
for (auto func : all_functions) {
|
||||||
|
|
||||||
|
std::string rest = std::regex_replace(func, re1, "$2");
|
||||||
|
if (rest.empty() || (rest.compare("t") && rest.compare(0, 3, "gnu") &&
|
||||||
|
func.compare(0, 2, "__")))
|
||||||
|
printf("UNREACHABLE FUNCTION: %s\n", func.c_str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Unreachable::runOnModule(Module &M) {
|
||||||
|
|
||||||
|
if (getenv("AFL_DEBUG")) { debug = 1; }
|
||||||
|
if (!getenv("AFL_QUIET") || debug)
|
||||||
|
printf("Running afl-llvm-unreachable by Marc Heuse, mh@mh-sec.de\n");
|
||||||
|
else
|
||||||
|
be_quiet = 1;
|
||||||
|
|
||||||
|
hookInstrs(M);
|
||||||
|
if (!be_quiet) printf("Unreachable analysis finished.\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
verifyModule(M);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerUnreachablePass(const PassManagerBuilder &,
|
||||||
|
legacy::PassManagerBase &PM) {
|
||||||
|
|
||||||
|
auto p = new Unreachable();
|
||||||
|
PM.add(p);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegisterStandardPasses RegisterUnreachablePass(
|
||||||
|
PassManagerBuilder::EP_OptimizerLast, registerUnreachablePass);
|
||||||
|
|
||||||
|
static RegisterStandardPasses RegisterUnreachablePass0(
|
||||||
|
PassManagerBuilder::EP_EnabledOnOptLevel0, registerUnreachablePass);
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR >= 11
|
||||||
|
static RegisterStandardPasses RegisterUnreachablePassLTO(
|
||||||
|
PassManagerBuilder::EP_FullLinkTimeOptimizationEarly,
|
||||||
|
registerUnreachablePass);
|
||||||
|
#endif
|
||||||
|
|
Submodule qemu_mode/qemuafl updated: 47722f64e4...246c1777f4
50
src/afl-cc.c
50
src/afl-cc.c
@ -31,6 +31,8 @@
|
|||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#if (LLVM_MAJOR - 0 == 0)
|
#if (LLVM_MAJOR - 0 == 0)
|
||||||
#undef LLVM_MAJOR
|
#undef LLVM_MAJOR
|
||||||
@ -566,12 +568,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
|
cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
|
||||||
|
|
||||||
if (instrument_mode == INSTRUMENT_CFG ||
|
if (getenv("AFL_LLVM_LTO_UNREACHABLE"))
|
||||||
instrument_mode == INSTRUMENT_PCGUARD)
|
cc_params[cc_par_cnt++] = alloc_printf(
|
||||||
|
"-Wl,-mllvm=-load=%s/afl-llvm-unreachable.so", obj_path);
|
||||||
|
else if (instrument_mode == INSTRUMENT_CFG ||
|
||||||
|
instrument_mode == INSTRUMENT_PCGUARD)
|
||||||
cc_params[cc_par_cnt++] = alloc_printf(
|
cc_params[cc_par_cnt++] = alloc_printf(
|
||||||
"-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
|
"-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
|
||||||
else
|
else
|
||||||
|
|
||||||
cc_params[cc_par_cnt++] = alloc_printf(
|
cc_params[cc_par_cnt++] = alloc_printf(
|
||||||
"-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
|
"-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
|
||||||
cc_params[cc_par_cnt++] = lto_flag;
|
cc_params[cc_par_cnt++] = lto_flag;
|
||||||
@ -801,7 +805,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
if (!getenv("AFL_DONT_OPTIMIZE") && !getenv("AFL_LLVM_LTO_UNREACHABLE")) {
|
||||||
|
|
||||||
cc_params[cc_par_cnt++] = "-g";
|
cc_params[cc_par_cnt++] = "-g";
|
||||||
if (!have_o) cc_params[cc_par_cnt++] = "-O3";
|
if (!have_o) cc_params[cc_par_cnt++] = "-O3";
|
||||||
@ -1010,6 +1014,29 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (getenv("AFL_LLVM_LTO_UNREACHABLE")) {
|
||||||
|
|
||||||
|
if (!lto_mode) { FATAL("AFL_LLVM_LTO_UNREACHABLE requires LTO mode"); }
|
||||||
|
cc_params[cc_par_cnt++] = "-O0";
|
||||||
|
cc_params[cc_par_cnt++] = "-w";
|
||||||
|
cc_params[cc_par_cnt++] = "-Wl,-mllvm,-compute-dead=false";
|
||||||
|
cc_params[cc_par_cnt++] = "-fno-inline";
|
||||||
|
cc_params[cc_par_cnt++] = "-fno-inline-functions";
|
||||||
|
cc_params[cc_par_cnt++] = "-Wl,--discard-none";
|
||||||
|
cc_params[cc_par_cnt++] = "-Wl,--lto-O0";
|
||||||
|
cc_params[cc_par_cnt++] = "-femit-all-decls";
|
||||||
|
cc_params[cc_par_cnt++] = "-fno-virtual-function-elimination";
|
||||||
|
cc_params[cc_par_cnt++] = "-Wl,--no-gc-sections";
|
||||||
|
if (!be_quiet) {
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"Note: UNREACHABLE analysis will not create an instrumented binary "
|
||||||
|
"for fuzzing.\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
cc_params[cc_par_cnt] = NULL;
|
cc_params[cc_par_cnt] = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1655,8 +1682,9 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
" AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
|
" AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
|
||||||
"global var\n"
|
"global var\n"
|
||||||
" AFL_LLVM_LTO_STARTID: from which ID to start counting from for "
|
" AFL_LLVM_LTO_STARTID: from which ID to start counting from for "
|
||||||
"a "
|
"a bb\n"
|
||||||
"bb\n"
|
" AFL_LLVM_LTO_UNREACHABLE: will analyze for unreachable "
|
||||||
|
"functions, not instrument for fuzzing"
|
||||||
" AFL_REAL_LD: use this lld linker instead of the compiled in "
|
" AFL_REAL_LD: use this lld linker instead of the compiled in "
|
||||||
"path\n"
|
"path\n"
|
||||||
"If anything fails - be sure to read README.lto.md!\n");
|
"If anything fails - be sure to read README.lto.md!\n");
|
||||||
@ -1831,8 +1859,8 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
DEBUGF("cd '%s';", getthecwd());
|
DEBUGF("cd '%s';", getthecwd());
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
SAYF(" '%s'", argv[i]);
|
DEBUGF(" '%s'", argv[i]);
|
||||||
SAYF("\n");
|
DEBUGF("\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
@ -1873,17 +1901,15 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
DEBUGF("cd '%s';", getthecwd());
|
DEBUGF("cd '%s';", getthecwd());
|
||||||
for (i = 0; i < (s32)cc_par_cnt; i++)
|
for (i = 0; i < (s32)cc_par_cnt; i++)
|
||||||
SAYF(" '%s'", cc_params[i]);
|
DEBUGF(" '%s'", cc_params[i]);
|
||||||
SAYF("\n");
|
DEBUGF("\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
execvp(cc_params[0], (char **)cc_params);
|
execvp(cc_params[0], (char **)cc_params);
|
||||||
|
|
||||||
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1303,7 +1303,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CMPLOG_SOLVE_ARITHMETIC */
|
#endif /* CMPLOG_SOLVE_ARITHMETIC */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -2670,3 +2670,4 @@ exit_its:
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
57
test.c
Normal file
57
test.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void barY() {
|
||||||
|
printf("barY\n");
|
||||||
|
}
|
||||||
|
void barZ() {
|
||||||
|
printf("barZ\n");
|
||||||
|
}
|
||||||
|
void bar0() {
|
||||||
|
printf("bar0\n");
|
||||||
|
}
|
||||||
|
void bar1() {
|
||||||
|
printf("bar1\n");
|
||||||
|
}
|
||||||
|
void bar2() {
|
||||||
|
printf("bar2\n");
|
||||||
|
}
|
||||||
|
void bard() {
|
||||||
|
printf("bar3\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int foo(int a, int b, int c) {
|
||||||
|
|
||||||
|
switch(a) {
|
||||||
|
case 0: bar0(); break;
|
||||||
|
case 1: bar1(); break;
|
||||||
|
case 2: bar2(); break;
|
||||||
|
default: bard(); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(b) {
|
||||||
|
case 0: bar0(); break;
|
||||||
|
case 1: bar1(); break;
|
||||||
|
case 2: bar2(); break;
|
||||||
|
default: bard(); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(c) {
|
||||||
|
case 1: barY(); break;
|
||||||
|
case 2: barZ(); break;
|
||||||
|
default: barZ(); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
int a = 1, b = 2, c;
|
||||||
|
|
||||||
|
if (argc == 1) c = 3; else if (argc == 2) c = atoi(argv[1]);
|
||||||
|
// else: uninitialized
|
||||||
|
|
||||||
|
return foo(a, b, c);
|
||||||
|
|
||||||
|
}
|
Submodule unicorn_mode/unicornafl updated: fb2fc9f25d...80d31ef367
Reference in New Issue
Block a user