From: Matt Morehouse Date: Fri, 28 Feb 2020 01:13:59 +0000 (-0800) Subject: [DFSan] Add flag to insert event callbacks. X-Git-Tag: llvmorg-12-init~13420 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=470db54cbdf1ce65e7084aa42a8c5e9f1c41a9bd;p=platform%2Fupstream%2Fllvm.git [DFSan] Add flag to insert event callbacks. Summary: For now just insert the callback for stores, similar to how MSan tracks origins. In the future we may want to add callbacks for loads, memcpy, function calls, CMPs, etc. Reviewers: pcc, vitalybuka, kcc, eugenis Reviewed By: vitalybuka, kcc, eugenis Subscribers: eugenis, hiraditya, #sanitizers, llvm-commits, kcc Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D75312 --- diff --git a/compiler-rt/test/dfsan/event_callbacks.c b/compiler-rt/test/dfsan/event_callbacks.c new file mode 100644 index 0000000..e3a4f6c --- /dev/null +++ b/compiler-rt/test/dfsan/event_callbacks.c @@ -0,0 +1,67 @@ +// RUN: %clang_dfsan -fno-sanitize=dataflow -fPIE -DCALLBACKS -c %s -o %t-callbacks.o +// RUN: %clang_dfsan -mllvm -dfsan-event-callbacks %s %t-callbacks.o -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +// Tests that callbacks are inserted for store events when +// -dfsan-event-callbacks is specified. + +#include +#include +#include + +#ifdef CALLBACKS +// Compile this code without DFSan to avoid recursive instrumentation. + +extern dfsan_label LabelI; +extern dfsan_label LabelJ; +extern dfsan_label LabelIJ; + +void __dfsan_store_callback(dfsan_label Label) { + if (!Label) + return; + + static int Count = 0; + switch (Count++) { + case 0: + assert(Label == LabelI); + break; + case 1: + assert(Label == LabelJ); + break; + case 2: + assert(Label == LabelIJ); + break; + default: + assert(0); + } + + // CHECK: Label 1 stored to memory + // CHECK: Label 2 stored to memory + // CHECK: Label 3 stored to memory + fprintf(stderr, "Label %u stored to memory\n", Label); +} + +#else +// Compile this code with DFSan and -dfsan-event-callbacks to insert the +// callbacks. + +dfsan_label LabelI; +dfsan_label LabelJ; +dfsan_label LabelIJ; + +int main(void) { + int I = 1, J = 2; + LabelI = dfsan_create_label("I", 0); + dfsan_set_label(LabelI, &I, sizeof(I)); + LabelJ = dfsan_create_label("J", 0); + dfsan_set_label(LabelJ, &J, sizeof(J)); + LabelIJ = dfsan_union(LabelI, LabelJ); + + volatile int Sink = I; + Sink = J; + Sink += I; + + return 0; +} + +#endif // #ifdef CALLBACKS diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index c77cb4e..3b873cb 100644 --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -162,6 +162,17 @@ static cl::opt ClDebugNonzeroLabels( "load or return with a nonzero label"), cl::Hidden); +// Experimental feature that inserts callbacks for certain data events. +// Currently callbacks are only inserted for stores. +// +// If this flag is set to true, the user must provide definitions for the +// following callback functions: +// void __dfsan_store_callback(dfsan_label Label); +static cl::opt ClEventCallbacks( + "dfsan-event-callbacks", + cl::desc("Insert calls to __dfsan_*_callback functions on data events."), + cl::Hidden, cl::init(false)); + static StringRef GetGlobalTypeString(const GlobalValue &G) { // Types of GlobalVariables are always pointer types. Type *GType = G.getValueType(); @@ -345,6 +356,7 @@ class DataFlowSanitizer : public ModulePass { FunctionType *DFSanSetLabelFnTy; FunctionType *DFSanNonzeroLabelFnTy; FunctionType *DFSanVarargWrapperFnTy; + FunctionType *DFSanStoreCallbackFnTy; FunctionCallee DFSanUnionFn; FunctionCallee DFSanCheckedUnionFn; FunctionCallee DFSanUnionLoadFn; @@ -352,6 +364,7 @@ class DataFlowSanitizer : public ModulePass { FunctionCallee DFSanSetLabelFn; FunctionCallee DFSanNonzeroLabelFn; FunctionCallee DFSanVarargWrapperFn; + FunctionCallee DFSanStoreCallbackFn; MDNode *ColdCallWeights; DFSanABIList ABIList; DenseMap UnwrappedFnMap; @@ -583,6 +596,8 @@ bool DataFlowSanitizer::doInitialization(Module &M) { Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); DFSanVarargWrapperFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); + DFSanStoreCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), ShadowTy, /*isVarArg=*/false); if (GetArgTLSPtr) { Type *ArgTLSTy = ArrayType::get(ShadowTy, 64); @@ -783,6 +798,9 @@ bool DataFlowSanitizer::runOnModule(Module &M) { DFSanVarargWrapperFn = Mod->getOrInsertFunction("__dfsan_vararg_wrapper", DFSanVarargWrapperFnTy); + DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback", + DFSanStoreCallbackFnTy); + std::vector FnsToInstrument; SmallPtrSet FnsWithNativeABI; for (Function &i : M) { @@ -793,7 +811,8 @@ bool DataFlowSanitizer::runOnModule(Module &M) { &i != DFSanUnimplementedFn.getCallee()->stripPointerCasts() && &i != DFSanSetLabelFn.getCallee()->stripPointerCasts() && &i != DFSanNonzeroLabelFn.getCallee()->stripPointerCasts() && - &i != DFSanVarargWrapperFn.getCallee()->stripPointerCasts()) + &i != DFSanVarargWrapperFn.getCallee()->stripPointerCasts() && + &i != DFSanStoreCallbackFn.getCallee()->stripPointerCasts()) FnsToInstrument.push_back(&i); } @@ -1396,6 +1415,10 @@ void DFSanVisitor::visitStoreInst(StoreInst &SI) { Shadow = DFSF.combineShadows(Shadow, PtrShadow, &SI); } DFSF.storeShadow(SI.getPointerOperand(), Size, Alignement, Shadow, &SI); + if (ClEventCallbacks) { + IRBuilder<> IRB(&SI); + IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, Shadow); + } } void DFSanVisitor::visitUnaryOperator(UnaryOperator &UO) {