Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.13)

project(symsan VERSION 1.2.2 LANGUAGES C CXX ASM)

Expand Down
15 changes: 13 additions & 2 deletions driver/aflpp/symsan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ using namespace __dfsan;

static bool NestedSolving = false;
static int TraceBounds = 0;
static int ExitOnMemError = 1; // default is exit on memory error
static int SolveUB = 0;
static int ForceStdin = 0;
static bool SaveSolved = false;
Expand Down Expand Up @@ -171,14 +172,19 @@ static void handle_cond(pipe_msg &msg, my_mutator_t *my_mutator) {
lc += 1;
}

// prase flags
bool always_solve = (msg.flags & F_ADD_CONS) == 0;
bool loop_latch = (msg.flags & F_LOOP_LATCH) != 0;
bool loop_exit = (msg.flags & F_LOOP_EXIT) != 0;

const branch_ctx_t ctx = my_mutator->cov_mgr->add_branch((void*)msg.addr,
msg.id, msg.result != 0, msg.context, false, false);
msg.id, msg.result != 0, msg.context, loop_latch, loop_exit);

branch_ctx_t neg_ctx = std::make_shared<rgd::BranchContext>();
*neg_ctx = *ctx;
neg_ctx->direction = !ctx->direction;

if (my_mutator->cov_mgr->is_branch_interesting(neg_ctx)) {
if (my_mutator->cov_mgr->is_branch_interesting(neg_ctx) || always_solve) {
// parse the uniont table AST to solving tasks
std::vector<uint64_t> tasks;
if (my_mutator->parser->parse_cond(msg.label, ctx->direction, msg.flags & F_ADD_CONS, tasks) != 0) {
Expand Down Expand Up @@ -274,6 +280,10 @@ extern "C" my_mutator_t *afl_custom_init(afl_state *afl, unsigned int seed) {
if (getenv("SYMSAN_TRACE_BOUNDS")) {
TraceBounds = 1;
}
// disable exit on memory error
if (getenv("SYMSAN_DONT_EXIT_ON_MEMERROR")) {
ExitOnMemError = 0;
}
if (getenv("SYMSAN_SOLVE_UB")) {
TraceBounds = 1; // solve undefined depends on trace bounds
SolveUB = 1;
Expand Down Expand Up @@ -415,6 +425,7 @@ extern "C" u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf,
symsan_set_args(argc, data->argv);
symsan_set_debug(DEBUG);
symsan_set_bounds_check(TraceBounds);
symsan_set_exit_on_memerror(ExitOnMemError);
symsan_set_solve_ub(SolveUB);
symsan_set_force_stdin(ForceStdin);
}
Expand Down
14 changes: 14 additions & 0 deletions driver/harness-proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,16 @@
#include <fcntl.h>

extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
__attribute__((weak)) void LLVMFuzzerCleanup(void);

int main(int argc, char* argv[]) {

// Initialize the fuzzer if the function is available
if (LLVMFuzzerInitialize) {
LLVMFuzzerInitialize(&argc, &argv);
}

// open file
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
Expand Down Expand Up @@ -50,5 +58,11 @@ int main(int argc, char* argv[]) {
int retval = LLVMFuzzerTestOneInput((const uint8_t *)string, fsize);

free(string);

// Cleanup if the function is available
if (LLVMFuzzerCleanup) {
LLVMFuzzerCleanup();
}

return retval;
}
93 changes: 84 additions & 9 deletions instrumentation/TaintPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ static cl::opt<bool> ClSolveUB(
cl::desc("Solve undefined behaviours."),
cl::Hidden, cl::init(false));

// SYMSAN specific flags, only send events for annotated basic blocks
static cl::opt<bool> ClTraceAnnotatedBB(
"taint-trace-annotated-bb",
cl::desc("Only trace annotated basic blocks."),
cl::Hidden, cl::init(false));

static StringRef getGlobalTypeString(const GlobalValue &G) {
// Types of GlobalVariables are always pointer types.
Type *GType = G.getValueType();
Expand Down Expand Up @@ -448,6 +454,7 @@ class Taint {
void addContextRecording(Function &F);
void addFrameTracing(Function &F);
uint32_t getInstructionId(Instruction *Inst);
const uint32_t InvalidInstructionId = -1;

void initializeRuntimeFunctions(Module &M);
void initializeCallbackFunctions(Module &M);
Expand Down Expand Up @@ -480,6 +487,9 @@ class Taint {
/// Returns the shadow type of of V's type.
Type *getShadowTy(Value *V);

/// Returns an uninitialized shadow value with the shadow type of OrigTy.
Constant *getUninitializedShadow(Type *OrigTy);

public:
Taint(const std::vector<std::string> &ABIListFiles);

Expand Down Expand Up @@ -756,6 +766,23 @@ bool Taint::isZeroShadow(Value *V) {
return isa<ConstantAggregateZero>(V);
}

Constant *Taint::getUninitializedShadow(Type *OrigTy) {
if (!isa<ArrayType>(OrigTy) && !isa<StructType>(OrigTy))
return UninitializedPrimitiveShadow;
Type *ShadowTy = getShadowTy(OrigTy);
if (ArrayType *AT = dyn_cast<ArrayType>(ShadowTy)) {
SmallVector<Constant *, 4> Elements(AT->getNumElements(),
getUninitializedShadow(AT->getElementType()));
return ConstantArray::get(AT, Elements);
} else if (StructType *ST = dyn_cast<StructType>(ShadowTy)) {
SmallVector<Constant *, 4> Elements(ST->getNumElements());
for (unsigned I = 0, N = ST->getNumElements(); I < N; ++I)
Elements[I] = getUninitializedShadow(ST->getElementType(I));
return ConstantStruct::get(ST, Elements);
}
llvm_unreachable("Unexpected type for uninitialized shadow");
}

Constant *Taint::getZeroShadow(Type *OrigTy) {
if (!isa<ArrayType>(OrigTy) && !isa<StructType>(OrigTy))
return ZeroPrimitiveShadow;
Expand Down Expand Up @@ -791,6 +818,20 @@ Type *Taint::getShadowTy(Value *V) {
}

uint32_t Taint::getInstructionId(Instruction *Inst) {
// check if there is a bbid annotation
if (MDNode *BBID = Inst->getMetadata("bbid")) {
auto C = dyn_cast<ConstantAsMetadata>(BBID->getOperand(0));
if (ConstantInt *CI = dyn_cast<ConstantInt>(C->getValue())) {
uint64_t BBIDValue = CI->getZExtValue();
assert(BBIDValue < UINT32_MAX &&
"bbid value is too large for 32-bit hash");
return static_cast<uint32_t>(BBIDValue);
}
}
if (ClTraceAnnotatedBB && Inst->isTerminator())
return InvalidInstructionId;

// otherwise, fallback to hash
static uint32_t unamed = 0;
auto SourceInfo = Mod->getSourceFileName();
DILocation *Loc = Inst->getDebugLoc();
Expand Down Expand Up @@ -1376,11 +1417,28 @@ bool Taint::runImpl(Module &M) {
initializeRuntimeFunctions(M);

std::vector<Function *> FnsToInstrument;
SmallPtrSet<Function *, 8> IFuncs;
SmallPtrSet<Function *, 2> FnsWithNativeABI;
SmallPtrSet<Function *, 2> FnsWithForceZeroLabel;
SmallPtrSet<Constant *, 1> PersonalityFns;

// find ifunc resolvers and their dependencies, we can't instrument them
// as dfsan initialization is not done yet
for (auto &ifunc : M.ifuncs()) {
auto *resolver = ifunc.getResolverFunction();
IFuncs.insert(resolver);
for (auto &I : instructions(resolver)) {
if (CallBase *CB = dyn_cast<CallBase>(&I)) {
if (Function *Callee = CB->getCalledFunction()) {
IFuncs.insert(Callee);
}
}
}
}

for (Function &F : M) {
if (!F.isIntrinsic() && !TaintRuntimeFunctions.count(&F)) {
if (!F.isIntrinsic() && !TaintRuntimeFunctions.count(&F) &&
!IFuncs.count(&F)) {
FnsToInstrument.push_back(&F);
if (F.hasPersonalityFn())
PersonalityFns.insert(F.getPersonalityFn());
Expand Down Expand Up @@ -1919,7 +1977,7 @@ Value *TaintFunction::loadShadow(Type *T, Value *Addr, uint64_t Size,
if (AllocaInst *AI = dyn_cast<AllocaInst>(Addr)) {
const auto i = AllocaShadowMap.find(AI);
if (i != AllocaShadowMap.end()) {
return IRB.CreateLoad(TT.PrimitiveShadowTy, i->second);
return IRB.CreateLoad(TT.getShadowTy(T), i->second);
}
}

Expand Down Expand Up @@ -2302,10 +2360,13 @@ void TaintFunction::visitSwitchInst(SwitchInst *I) {
Value *CondShadow = getShadow(Cond);
if (TT.isZeroShadow(CondShadow))
return;
uint32_t cid = TT.getInstructionId(I);
if (cid == TT.InvalidInstructionId)
return;
unsigned size = DL.getTypeSizeInBits(Cond->getType());
ConstantInt *Size = ConstantInt::get(TT.Int32Ty, size);
ConstantInt *Predicate = ConstantInt::get(TT.Int32Ty, 32); // EQ, ==
ConstantInt *CID = ConstantInt::get(TT.Int32Ty, TT.getInstructionId(I));
ConstantInt *CID = ConstantInt::get(TT.Int32Ty, cid);

IRBuilder<> IRB(I);
for (auto C : I->cases()) {
Expand Down Expand Up @@ -2508,11 +2569,12 @@ void TaintVisitor::visitAllocaInst(AllocaInst &I) {
}
if (AllLoadsStores) {
IRBuilder<> IRB(&I);
AllocaInst *AI = IRB.CreateAlloca(TF.TT.PrimitiveShadowTy);
AllocaInst *AI = IRB.CreateAlloca(TF.TT.getShadowTy(I.getAllocatedType()),
I.getArraySize(), I.getName() + ".taint");
TF.AllocaShadowMap[&I] = AI;
if (ClTraceBound) {
// set shadow to uninit
IRB.CreateStore(TF.TT.UninitializedPrimitiveShadow, AI);
IRB.CreateStore(TF.TT.getUninitializedShadow(I.getAllocatedType()), AI);
}
}
if (!ClTraceBound) {
Expand All @@ -2530,6 +2592,16 @@ void TaintVisitor::visitAllocaInst(AllocaInst &I) {
}
// set uninit shadow for allocation with constant size
if (!AllLoadsStores && isa<ConstantInt>(ArraySize)) {
Value *Init = TF.TT.UninitializedPrimitiveShadow;
// XXX: skip __va_list_tag, as we don't trace llvm.va_start
if (ArrayType *AT = dyn_cast<ArrayType>(T)) {
T = AT->getElementType();
}
if (T->isStructTy() &&
T->getStructName().find("__va_list_tag") != StringRef::npos) {
// FIXME: don't set uninit, assuming llvm.va_start will be called
Init = TF.TT.ZeroPrimitiveShadow;
}
// handle not all loads and stores cases here
IRBuilder<> IRB(I.getNextNode());
auto DL = I.getModule()->getDataLayout();
Expand All @@ -2538,9 +2610,9 @@ void TaintVisitor::visitAllocaInst(AllocaInst &I) {
Value *Size =
ConstantInt::get(TF.TT.IntptrTy, (size->getFixedValue() + 7) >> 3);
IRB.CreateCall(TF.TT.TaintSetLabelFn,
{TF.TT.UninitializedPrimitiveShadow,
IRB.CreateBitCast(&I, Type::getInt8PtrTy(*TF.TT.Ctx)),
Size});
{Init,
IRB.CreateBitCast(&I, Type::getInt8PtrTy(*TF.TT.Ctx)),
Size});
}
}
}
Expand Down Expand Up @@ -3015,8 +3087,11 @@ void TaintFunction::visitCondition(Value *Condition, Instruction *I) {
// except for loop exit
if (TT.isZeroShadow(Shadow) && (flag & LoopExitBranch) == 0)
return;
uint32_t cid = TT.getInstructionId(I);
if (cid == TT.InvalidInstructionId)
return; // XXX: forget about loop?
ConstantInt *LF = ConstantInt::get(TT.Int8Ty, flag);
ConstantInt *CID = ConstantInt::get(TT.Int32Ty, TT.getInstructionId(I));
ConstantInt *CID = ConstantInt::get(TT.Int32Ty, cid);
IRB.CreateCall(TT.TaintTraceCondFn, {Shadow, Condition, LF, CID});
}

Expand Down
Loading