Commit f668baa4 authored by Matt Morehouse's avatar Matt Morehouse
Browse files

[DFSan] Add __dfsan_mem_transfer_callback.

Summary:
When -dfsan-event-callbacks is specified, insert a call to
__dfsan_mem_transfer_callback on every memcpy and memmove.

Reviewers: vitalybuka, kcc, pcc

Reviewed By: kcc

Subscribers: eugenis, hiraditya, #sanitizers, llvm-commits

Tags: #sanitizers, #llvm

Differential Revision: https://reviews.llvm.org/D75386
parent 4069dd14
Loading
Loading
Loading
Loading
+32 −2
Original line number Diff line number Diff line
// 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 <assert.h>
#include <sanitizer/dfsan_interface.h>
#include <stdio.h>
#include <string.h>

#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 @@ void __dfsan_load_callback(dfsan_label Label) {
  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 @@ void __dfsan_load_callback(dfsan_label Label) {
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 @@ int main(void) {
  // 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;
}

+19 −4
Original line number Diff line number Diff line
@@ -163,12 +163,14 @@ static cl::opt<bool> ClDebugNonzeroLabels(
    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<bool> ClEventCallbacks(
    "dfsan-event-callbacks",
    cl::desc("Insert calls to __dfsan_*_callback functions on data events."),
@@ -358,6 +360,7 @@ class DataFlowSanitizer : public ModulePass {
  FunctionType *DFSanNonzeroLabelFnTy;
  FunctionType *DFSanVarargWrapperFnTy;
  FunctionType *DFSanLoadStoreCallbackFnTy;
  FunctionType *DFSanMemTransferCallbackFnTy;
  FunctionCallee DFSanUnionFn;
  FunctionCallee DFSanCheckedUnionFn;
  FunctionCallee DFSanUnionLoadFn;
@@ -367,6 +370,7 @@ class DataFlowSanitizer : public ModulePass {
  FunctionCallee DFSanVarargWrapperFn;
  FunctionCallee DFSanLoadCallbackFn;
  FunctionCallee DFSanStoreCallbackFn;
  FunctionCallee DFSanMemTransferCallbackFn;
  MDNode *ColdCallWeights;
  DFSanABIList ABIList;
  DenseMap<Value *, Function *> UnwrappedFnMap;
@@ -600,6 +604,10 @@ bool DataFlowSanitizer::doInitialization(Module &M) {
      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 @@ bool DataFlowSanitizer::runOnModule(Module &M) {
                                                 DFSanLoadStoreCallbackFnTy);
  DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback",
                                                  DFSanLoadStoreCallbackFnTy);
  DFSanMemTransferCallbackFn = Mod->getOrInsertFunction(
      "__dfsan_mem_transfer_callback", DFSanMemTransferCallbackFnTy);

  std::vector<Function *> FnsToInstrument;
  SmallPtrSet<Function *, 2> FnsWithNativeABI;
@@ -817,7 +827,8 @@ bool DataFlowSanitizer::runOnModule(Module &M) {
        &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::visitMemSetInst(MemSetInst &I) {

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<MemTransferInst>(
      IRB.CreateCall(I.getFunctionType(), I.getCalledValue(),
@@ -1538,6 +1549,10 @@ void DFSanVisitor::visitMemTransferInst(MemTransferInst &I) {
    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) {