diff --git a/compiler-rt/test/dfsan/event_callbacks.c b/compiler-rt/test/dfsan/event_callbacks.c --- a/compiler-rt/test/dfsan/event_callbacks.c +++ b/compiler-rt/test/dfsan/event_callbacks.c @@ -1,6 +1,6 @@ // RUN: %clang_dfsan -fno-sanitize=dataflow -O2 -fPIE -DCALLBACKS -c %s -o %t-callbacks.o // RUN: %clang_dfsan -O2 -mllvm -dfsan-event-callbacks %s %t-callbacks.o -o %t -// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %run %t FooBarBaz 2>&1 | FileCheck %s // Tests that callbacks are inserted for store events when // -dfsan-event-callbacks is specified. @@ -8,6 +8,7 @@ #include #include #include +#include #ifdef CALLBACKS // Compile this code without DFSan to avoid recursive instrumentation. @@ -15,6 +16,8 @@ extern dfsan_label LabelI; extern dfsan_label LabelJ; extern dfsan_label LabelIJ; +extern dfsan_label LabelArgv; +extern size_t LenArgv; void __dfsan_store_callback(dfsan_label Label) { if (!Label) @@ -45,6 +48,15 @@ fprintf(stderr, "Label %u loaded from memory\n", Label); } +void __dfsan_mem_transfer_callback(dfsan_label *Start, size_t Len) { + assert(Len == LenArgv); + for (int I = 0; I < Len; ++I) { + assert(Start[I] == LabelArgv); + } + + fprintf(stderr, "Label %u copied to memory\n", Start[0]); +} + #else // Compile this code with DFSan and -dfsan-event-callbacks to insert the // callbacks. @@ -52,8 +64,13 @@ dfsan_label LabelI; dfsan_label LabelJ; dfsan_label LabelIJ; +dfsan_label LabelArgv; + +size_t LenArgv; + +int main(int Argc, char *Argv[]) { + assert(Argc == 2); -int main(void) { int I = 1, J = 2; LabelI = dfsan_create_label("I", 0); dfsan_set_label(LabelI, &I, sizeof(I)); @@ -80,6 +97,19 @@ // CHECK: Label 3 loaded from memory assert(Sink == 3); + LenArgv = strlen(Argv[1]); + LabelArgv = dfsan_create_label("Argv", 0); + dfsan_set_label(LabelArgv, Argv[1], LenArgv); + + char SinkBuf[64]; + assert(LenArgv < sizeof(SinkBuf) - 1); + + // CHECK: Label 4 copied to memory + memcpy(SinkBuf, Argv[1], LenArgv); + + // CHECK: Label 4 copied to memory + memmove(&SinkBuf[1], SinkBuf, LenArgv); + return 0; } diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -163,12 +163,14 @@ cl::Hidden); // Experimental feature that inserts callbacks for certain data events. -// Currently callbacks are only inserted for loads and stores. +// Currently callbacks are only inserted for loads, stores, and memory transfers +// (i.e. memcpy and memmove). // // If this flag is set to true, the user must provide definitions for the // following callback functions: // void __dfsan_load_callback(dfsan_label Label); // void __dfsan_store_callback(dfsan_label Label); +// void __dfsan_mem_transfer_callback(dfsan_label *Start, size_t Len); static cl::opt ClEventCallbacks( "dfsan-event-callbacks", cl::desc("Insert calls to __dfsan_*_callback functions on data events."), @@ -358,6 +360,7 @@ FunctionType *DFSanNonzeroLabelFnTy; FunctionType *DFSanVarargWrapperFnTy; FunctionType *DFSanLoadStoreCallbackFnTy; + FunctionType *DFSanMemTransferCallbackFnTy; FunctionCallee DFSanUnionFn; FunctionCallee DFSanCheckedUnionFn; FunctionCallee DFSanUnionLoadFn; @@ -367,6 +370,7 @@ FunctionCallee DFSanVarargWrapperFn; FunctionCallee DFSanLoadCallbackFn; FunctionCallee DFSanStoreCallbackFn; + FunctionCallee DFSanMemTransferCallbackFn; MDNode *ColdCallWeights; DFSanABIList ABIList; DenseMap UnwrappedFnMap; @@ -600,6 +604,10 @@ Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); DFSanLoadStoreCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), ShadowTy, /*isVarArg=*/false); + Type *DFSanMemTransferCallbackArgs[2] = {ShadowPtrTy, IntptrTy}; + DFSanMemTransferCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), DFSanMemTransferCallbackArgs, + /*isVarArg=*/false); if (GetArgTLSPtr) { Type *ArgTLSTy = ArrayType::get(ShadowTy, 64); @@ -804,6 +812,8 @@ DFSanLoadStoreCallbackFnTy); DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback", DFSanLoadStoreCallbackFnTy); + DFSanMemTransferCallbackFn = Mod->getOrInsertFunction( + "__dfsan_mem_transfer_callback", DFSanMemTransferCallbackFnTy); std::vector FnsToInstrument; SmallPtrSet FnsWithNativeABI; @@ -817,7 +827,8 @@ &i != DFSanNonzeroLabelFn.getCallee()->stripPointerCasts() && &i != DFSanVarargWrapperFn.getCallee()->stripPointerCasts() && &i != DFSanLoadCallbackFn.getCallee()->stripPointerCasts() && - &i != DFSanStoreCallbackFn.getCallee()->stripPointerCasts()) + &i != DFSanStoreCallbackFn.getCallee()->stripPointerCasts() && + &i != DFSanMemTransferCallbackFn.getCallee()->stripPointerCasts()) FnsToInstrument.push_back(&i); } @@ -1520,13 +1531,13 @@ void DFSanVisitor::visitMemTransferInst(MemTransferInst &I) { IRBuilder<> IRB(&I); - Value *DestShadow = DFSF.DFS.getShadowAddress(I.getDest(), &I); + Value *RawDestShadow = DFSF.DFS.getShadowAddress(I.getDest(), &I); Value *SrcShadow = DFSF.DFS.getShadowAddress(I.getSource(), &I); Value *LenShadow = IRB.CreateMul( I.getLength(), ConstantInt::get(I.getLength()->getType(), DFSF.DFS.ShadowWidth / 8)); Type *Int8Ptr = Type::getInt8PtrTy(*DFSF.DFS.Ctx); - DestShadow = IRB.CreateBitCast(DestShadow, Int8Ptr); + Value *DestShadow = IRB.CreateBitCast(RawDestShadow, Int8Ptr); SrcShadow = IRB.CreateBitCast(SrcShadow, Int8Ptr); auto *MTI = cast( IRB.CreateCall(I.getFunctionType(), I.getCalledValue(), @@ -1538,6 +1549,10 @@ MTI->setDestAlignment(DFSF.DFS.ShadowWidth / 8); MTI->setSourceAlignment(DFSF.DFS.ShadowWidth / 8); } + if (ClEventCallbacks) { + IRB.CreateCall(DFSF.DFS.DFSanMemTransferCallbackFn, + {RawDestShadow, I.getLength()}); + } } void DFSanVisitor::visitReturnInst(ReturnInst &RI) {