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 @@ -201,6 +201,14 @@ "to results."), cl::Hidden, cl::init(true)); +// Controls how to track origins. +// * 0: do not track origins. +// * 1: track origins at memory store operations. +// * 2: TODO: track origins at memory store operations and callsites. +static cl::opt ClTrackOrigins("dfsan-track-origins", + cl::desc("Track origins of labels"), + cl::Hidden, cl::init(0)); + static StringRef GetGlobalTypeString(const GlobalValue &G) { // Types of GlobalVariables are always pointer types. Type *GType = G.getValueType(); @@ -321,7 +329,12 @@ friend struct DFSanFunction; friend class DFSanVisitor; - enum { ShadowWidthBits = 16, ShadowWidthBytes = ShadowWidthBits / 8 }; + enum { + ShadowWidthBits = 16, + ShadowWidthBytes = ShadowWidthBits / 8, + OriginWidthBits = 32, + OriginWidthBytes = OriginWidthBits / 8 + }; /// Which ABI should be used for instrumented functions? enum InstrumentedABI { @@ -362,6 +375,8 @@ Module *Mod; LLVMContext *Ctx; Type *Int8Ptr; + IntegerType *OriginTy; + PointerType *OriginPtrTy; /// The shadow type for all primitive types and vector types. IntegerType *PrimitiveShadowTy; PointerType *PrimitiveShadowPtrTy; @@ -370,10 +385,14 @@ ConstantInt *ShadowPtrMask; ConstantInt *ShadowPtrMul; Constant *ArgTLS; + ArrayType *ArgOriginTLSTy; + Constant *ArgOriginTLS; Constant *RetvalTLS; + Constant *RetvalOriginTLS; Constant *ExternalShadowMask; FunctionType *DFSanUnionFnTy; FunctionType *DFSanUnionLoadFnTy; + FunctionType *DFSanLoadLabelAndOriginFnTy; FunctionType *DFSanUnimplementedFnTy; FunctionType *DFSanSetLabelFnTy; FunctionType *DFSanNonzeroLabelFnTy; @@ -381,10 +400,14 @@ FunctionType *DFSanCmpCallbackFnTy; FunctionType *DFSanLoadStoreCallbackFnTy; FunctionType *DFSanMemTransferCallbackFnTy; + FunctionType *DFSanChainOriginFnTy; + FunctionType *DFSanMemOriginTransferFnTy; + FunctionType *DFSanMaybeStoreOriginFnTy; FunctionCallee DFSanUnionFn; FunctionCallee DFSanCheckedUnionFn; FunctionCallee DFSanUnionLoadFn; FunctionCallee DFSanUnionLoadFast16LabelsFn; + FunctionCallee DFSanLoadLabelAndOriginFn; FunctionCallee DFSanUnimplementedFn; FunctionCallee DFSanSetLabelFn; FunctionCallee DFSanNonzeroLabelFn; @@ -393,7 +416,10 @@ FunctionCallee DFSanStoreCallbackFn; FunctionCallee DFSanMemTransferCallbackFn; FunctionCallee DFSanCmpCallbackFn; - SmallPtrSet DFSanRuntimeFunctions; + FunctionCallee DFSanChainOriginFn; + FunctionCallee DFSanMemOriginTransferFn; + FunctionCallee DFSanMaybeStoreOriginFn; + SmallPtrSet DFSanRuntimeFunctions; MDNode *ColdCallWeights; DFSanABIList ABIList; DenseMap UnwrappedFnMap; @@ -418,6 +444,10 @@ bool init(Module &M); + /// Returns whether the pass tracks origins. Support only fast16 mode in TLS + /// ABI mode. + bool shouldTrackOrigins(); + /// Returns whether the pass tracks labels for struct fields and array /// indices. Support only fast16 mode in TLS ABI mode. bool shouldTrackFieldsAndIndices(); @@ -449,6 +479,8 @@ /// Returns the shadow type of of V's type. Type *getShadowTy(Value *V); + const uint64_t kNumOfElementsInArgOrgTLS = kArgTLSSize / OriginWidthBytes; + public: DataFlowSanitizer(const std::vector &ABIListFiles); @@ -670,6 +702,11 @@ return isa(V); } +bool DataFlowSanitizer::shouldTrackOrigins() { + return ClTrackOrigins && getInstrumentedABI() == DataFlowSanitizer::IA_TLS && + ClFast16Labels; +} + bool DataFlowSanitizer::shouldTrackFieldsAndIndices() { return getInstrumentedABI() == DataFlowSanitizer::IA_TLS && ClFast16Labels; } @@ -824,6 +861,8 @@ Mod = &M; Ctx = &M.getContext(); Int8Ptr = Type::getInt8PtrTy(*Ctx); + OriginTy = IntegerType::get(*Ctx, OriginWidthBits); + OriginPtrTy = PointerType::getUnqual(OriginTy); PrimitiveShadowTy = IntegerType::get(*Ctx, ShadowWidthBits); PrimitiveShadowPtrTy = PointerType::getUnqual(PrimitiveShadowTy); IntptrTy = DL.getIntPtrType(*Ctx); @@ -845,6 +884,10 @@ Type *DFSanUnionLoadArgs[2] = {PrimitiveShadowPtrTy, IntptrTy}; DFSanUnionLoadFnTy = FunctionType::get(PrimitiveShadowTy, DFSanUnionLoadArgs, /*isVarArg=*/false); + Type *DFSanLoadLabelAndOriginArgs[2] = {Int8Ptr, IntptrTy}; + DFSanLoadLabelAndOriginFnTy = + FunctionType::get(IntegerType::get(*Ctx, 64), DFSanLoadLabelAndOriginArgs, + /*isVarArg=*/false); DFSanUnimplementedFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); Type *DFSanSetLabelArgs[3] = {PrimitiveShadowTy, Type::getInt8PtrTy(*Ctx), @@ -858,6 +901,15 @@ DFSanCmpCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), PrimitiveShadowTy, /*isVarArg=*/false); + DFSanChainOriginFnTy = + FunctionType::get(OriginTy, OriginTy, /*isVarArg=*/false); + Type *DFSanMaybeStoreOriginArgs[4] = {IntegerType::get(*Ctx, ShadowWidthBits), + Int8Ptr, IntptrTy, OriginTy}; + DFSanMaybeStoreOriginFnTy = FunctionType::get( + Type::getVoidTy(*Ctx), DFSanMaybeStoreOriginArgs, /*isVarArg=*/false); + Type *DFSanMemOriginTransferArgs[3] = {Int8Ptr, Int8Ptr, IntptrTy}; + DFSanMemOriginTransferFnTy = FunctionType::get( + Type::getVoidTy(*Ctx), DFSanMemOriginTransferArgs, /*isVarArg=*/false); Type *DFSanLoadStoreCallbackArgs[2] = {PrimitiveShadowTy, Int8Ptr}; DFSanLoadStoreCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanLoadStoreCallbackArgs, @@ -1037,6 +1089,17 @@ DFSanUnionLoadFast16LabelsFn = Mod->getOrInsertFunction( "__dfsan_union_load_fast16labels", DFSanUnionLoadFnTy, AL); } + { + AttributeList AL; + AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, + Attribute::NoUnwind); + AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, + Attribute::ReadOnly); + AL = AL.addAttribute(M.getContext(), AttributeList::ReturnIndex, + Attribute::ZExt); + DFSanLoadLabelAndOriginFn = Mod->getOrInsertFunction( + "__dfsan_load_label_and_origin", DFSanLoadLabelAndOriginFnTy, AL); + } DFSanUnimplementedFn = Mod->getOrInsertFunction("__dfsan_unimplemented", DFSanUnimplementedFnTy); { @@ -1049,6 +1112,24 @@ Mod->getOrInsertFunction("__dfsan_nonzero_label", DFSanNonzeroLabelFnTy); DFSanVarargWrapperFn = Mod->getOrInsertFunction("__dfsan_vararg_wrapper", DFSanVarargWrapperFnTy); + { + AttributeList AL; + AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt); + AL = AL.addAttribute(M.getContext(), AttributeList::ReturnIndex, + Attribute::ZExt); + DFSanChainOriginFn = Mod->getOrInsertFunction("__dfsan_chain_origin", + DFSanChainOriginFnTy, AL); + } + DFSanMemOriginTransferFn = Mod->getOrInsertFunction( + "__dfsan_mem_origin_transfer", DFSanMemOriginTransferFnTy); + + { + AttributeList AL; + AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt); + AL = AL.addParamAttribute(M.getContext(), 3, Attribute::ZExt); + DFSanMaybeStoreOriginFn = Mod->getOrInsertFunction( + "__dfsan_maybe_store_origin", DFSanMaybeStoreOriginFnTy, AL); + } DFSanRuntimeFunctions.insert(DFSanUnionFn.getCallee()->stripPointerCasts()); DFSanRuntimeFunctions.insert( @@ -1057,6 +1138,8 @@ DFSanUnionLoadFn.getCallee()->stripPointerCasts()); DFSanRuntimeFunctions.insert( DFSanUnionLoadFast16LabelsFn.getCallee()->stripPointerCasts()); + DFSanRuntimeFunctions.insert( + DFSanLoadLabelAndOriginFn.getCallee()->stripPointerCasts()); DFSanRuntimeFunctions.insert( DFSanUnimplementedFn.getCallee()->stripPointerCasts()); DFSanRuntimeFunctions.insert( @@ -1073,6 +1156,12 @@ DFSanMemTransferCallbackFn.getCallee()->stripPointerCasts()); DFSanRuntimeFunctions.insert( DFSanCmpCallbackFn.getCallee()->stripPointerCasts()); + DFSanRuntimeFunctions.insert( + DFSanChainOriginFn.getCallee()->stripPointerCasts()); + DFSanRuntimeFunctions.insert( + DFSanMemOriginTransferFn.getCallee()->stripPointerCasts()); + DFSanRuntimeFunctions.insert( + DFSanMaybeStoreOriginFn.getCallee()->stripPointerCasts()); } // Initializes event callback functions and declare them in the module @@ -1115,6 +1204,17 @@ RetvalTLS = getOrInsertGlobal( "__dfsan_retval_tls", ArrayType::get(Type::getInt64Ty(*Ctx), kRetvalTLSSize / 8)); + ArgOriginTLSTy = ArrayType::get(OriginTy, kNumOfElementsInArgOrgTLS); + ArgOriginTLS = getOrInsertGlobal("__dfsan_arg_origin_tls", ArgOriginTLSTy); + RetvalOriginTLS = getOrInsertGlobal("__dfsan_retval_origin_tls", OriginTy); + + (void)Mod->getOrInsertGlobal("__dfsan_track_origins", OriginTy, [&] { + Changed = true; + return new GlobalVariable( + M, OriginTy, true, GlobalValue::WeakODRLinkage, + ConstantInt::getSigned(OriginTy, shouldTrackOrigins()), + "__dfsan_track_origins"); + }); ExternalShadowMask = Mod->getOrInsertGlobal(kDFSanExternShadowPtrMask, IntptrTy); diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/basic.ll b/llvm/test/Instrumentation/DataFlowSanitizer/basic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/DataFlowSanitizer/basic.ll @@ -0,0 +1,43 @@ +; RUN: opt < %s -dfsan -S | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK_NO_ORIGIN +; RUN: opt < %s -dfsan -dfsan-track-origins=1 -dfsan-fast-16-labels=true -S | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK_ORIGIN +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK: @__dfsan_arg_tls = external thread_local(initialexec) global [100 x i64] +; CHECK: @__dfsan_retval_tls = external thread_local(initialexec) global [100 x i64] +; CHECK: @__dfsan_arg_origin_tls = external thread_local(initialexec) global [200 x i32] +; CHECK: @__dfsan_retval_origin_tls = external thread_local(initialexec) global i32 +; CHECK_NO_ORIGIN: @__dfsan_track_origins = weak_odr constant i32 0 +; CHECK_ORIGIN: @__dfsan_track_origins = weak_odr constant i32 1 +; CHECK: @__dfsan_shadow_ptr_mask = external global i64 +; CHECK: declare void @__dfsan_load_callback(i16, i8*) +; CHECK: declare void @__dfsan_store_callback(i16, i8*) +; CHECK: declare void @__dfsan_mem_transfer_callback(i16*, i64) +; CHECK: declare void @__dfsan_cmp_callback(i16) + +; CHECK: ; Function Attrs: nounwind readnone +; CHECK-NEXT: declare zeroext i16 @__dfsan_union(i16 zeroext, i16 zeroext) #0 + +; CHECK: ; Function Attrs: nounwind readnone +; CHECK-NEXT: declare zeroext i16 @dfsan_union(i16 zeroext, i16 zeroext) #0 + +; CHECK: ; Function Attrs: nounwind readonly +; CHECK-NEXT: declare zeroext i16 @__dfsan_union_load(i16*, i64) #1 + +; CHECK: ; Function Attrs: nounwind readonly +; CHECK-NEXT: declare zeroext i16 @__dfsan_union_load_fast16labels(i16*, i64) #1 + +; CHECK: ; Function Attrs: nounwind readonly +; CHECK-NEXT: declare zeroext i64 @__dfsan_load_label_and_origin(i8*, i64) #1 + +; CHECK: declare void @__dfsan_unimplemented(i8*) +; CHECK: declare void @__dfsan_set_label(i16 zeroext, i8*, i64) +; CHECK: declare void @__dfsan_nonzero_label() +; CHECK: declare void @__dfsan_vararg_wrapper(i8*) +; CHECK: declare zeroext i32 @__dfsan_chain_origin(i32 zeroext) +; CHECK: declare void @__dfsan_mem_origin_transfer(i8*, i8*, i64) +; CHECK: declare void @__dfsan_maybe_store_origin(i16 zeroext, i8*, i64, i32 zeroext) + +define void @foo() { + ret void +}