3502 lines · cpp
1//===- DataFlowSanitizer.cpp - dynamic data flow analysis -----------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9/// \file10/// This file is a part of DataFlowSanitizer, a generalised dynamic data flow11/// analysis.12///13/// Unlike other Sanitizer tools, this tool is not designed to detect a specific14/// class of bugs on its own. Instead, it provides a generic dynamic data flow15/// analysis framework to be used by clients to help detect application-specific16/// issues within their own code.17///18/// The analysis is based on automatic propagation of data flow labels (also19/// known as taint labels) through a program as it performs computation.20///21/// Argument and return value labels are passed through TLS variables22/// __dfsan_arg_tls and __dfsan_retval_tls.23///24/// Each byte of application memory is backed by a shadow memory byte. The25/// shadow byte can represent up to 8 labels. On Linux/x86_64, memory is then26/// laid out as follows:27///28/// +--------------------+ 0x800000000000 (top of memory)29/// | application 3 |30/// +--------------------+ 0x70000000000031/// | invalid |32/// +--------------------+ 0x61000000000033/// | origin 1 |34/// +--------------------+ 0x60000000000035/// | application 2 |36/// +--------------------+ 0x51000000000037/// | shadow 1 |38/// +--------------------+ 0x50000000000039/// | invalid |40/// +--------------------+ 0x40000000000041/// | origin 3 |42/// +--------------------+ 0x30000000000043/// | shadow 3 |44/// +--------------------+ 0x20000000000045/// | origin 2 |46/// +--------------------+ 0x11000000000047/// | invalid |48/// +--------------------+ 0x10000000000049/// | shadow 2 |50/// +--------------------+ 0x01000000000051/// | application 1 |52/// +--------------------+ 0x00000000000053///54/// MEM_TO_SHADOW(mem) = mem ^ 0x50000000000055/// SHADOW_TO_ORIGIN(shadow) = shadow + 0x10000000000056///57/// For more information, please refer to the design document:58/// http://clang.llvm.org/docs/DataFlowSanitizerDesign.html59//60//===----------------------------------------------------------------------===//61 62#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"63#include "llvm/ADT/DenseMap.h"64#include "llvm/ADT/DenseSet.h"65#include "llvm/ADT/DepthFirstIterator.h"66#include "llvm/ADT/SmallPtrSet.h"67#include "llvm/ADT/SmallVector.h"68#include "llvm/ADT/StringRef.h"69#include "llvm/ADT/StringSet.h"70#include "llvm/ADT/iterator.h"71#include "llvm/Analysis/DomTreeUpdater.h"72#include "llvm/Analysis/GlobalsModRef.h"73#include "llvm/Analysis/TargetLibraryInfo.h"74#include "llvm/Analysis/ValueTracking.h"75#include "llvm/IR/Argument.h"76#include "llvm/IR/AttributeMask.h"77#include "llvm/IR/Attributes.h"78#include "llvm/IR/BasicBlock.h"79#include "llvm/IR/Constant.h"80#include "llvm/IR/Constants.h"81#include "llvm/IR/DataLayout.h"82#include "llvm/IR/DerivedTypes.h"83#include "llvm/IR/Dominators.h"84#include "llvm/IR/Function.h"85#include "llvm/IR/GlobalAlias.h"86#include "llvm/IR/GlobalValue.h"87#include "llvm/IR/GlobalVariable.h"88#include "llvm/IR/IRBuilder.h"89#include "llvm/IR/InstVisitor.h"90#include "llvm/IR/InstrTypes.h"91#include "llvm/IR/Instruction.h"92#include "llvm/IR/Instructions.h"93#include "llvm/IR/IntrinsicInst.h"94#include "llvm/IR/MDBuilder.h"95#include "llvm/IR/Module.h"96#include "llvm/IR/PassManager.h"97#include "llvm/IR/Type.h"98#include "llvm/IR/User.h"99#include "llvm/IR/Value.h"100#include "llvm/Support/Alignment.h"101#include "llvm/Support/Casting.h"102#include "llvm/Support/CommandLine.h"103#include "llvm/Support/ErrorHandling.h"104#include "llvm/Support/SpecialCaseList.h"105#include "llvm/Support/VirtualFileSystem.h"106#include "llvm/TargetParser/Triple.h"107#include "llvm/Transforms/Utils/BasicBlockUtils.h"108#include "llvm/Transforms/Utils/Instrumentation.h"109#include "llvm/Transforms/Utils/Local.h"110#include <algorithm>111#include <cassert>112#include <cstddef>113#include <cstdint>114#include <memory>115#include <set>116#include <string>117#include <utility>118#include <vector>119 120using namespace llvm;121 122// This must be consistent with ShadowWidthBits.123static const Align ShadowTLSAlignment = Align(2);124 125static const Align MinOriginAlignment = Align(4);126 127// The size of TLS variables. These constants must be kept in sync with the ones128// in dfsan.cpp.129static const unsigned ArgTLSSize = 800;130static const unsigned RetvalTLSSize = 800;131 132// The -dfsan-preserve-alignment flag controls whether this pass assumes that133// alignment requirements provided by the input IR are correct. For example,134// if the input IR contains a load with alignment 8, this flag will cause135// the shadow load to have alignment 16. This flag is disabled by default as136// we have unfortunately encountered too much code (including Clang itself;137// see PR14291) which performs misaligned access.138static cl::opt<bool> ClPreserveAlignment(139 "dfsan-preserve-alignment",140 cl::desc("respect alignment requirements provided by input IR"), cl::Hidden,141 cl::init(false));142 143// The ABI list files control how shadow parameters are passed. The pass treats144// every function labelled "uninstrumented" in the ABI list file as conforming145// to the "native" (i.e. unsanitized) ABI. Unless the ABI list contains146// additional annotations for those functions, a call to one of those functions147// will produce a warning message, as the labelling behaviour of the function is148// unknown. The other supported annotations for uninstrumented functions are149// "functional" and "discard", which are described below under150// DataFlowSanitizer::WrapperKind.151// Functions will often be labelled with both "uninstrumented" and one of152// "functional" or "discard". This will leave the function unchanged by this153// pass, and create a wrapper function that will call the original.154//155// Instrumented functions can also be annotated as "force_zero_labels", which156// will make all shadow and return values set zero labels.157// Functions should never be labelled with both "force_zero_labels" and158// "uninstrumented" or any of the unistrumented wrapper kinds.159static cl::list<std::string> ClABIListFiles(160 "dfsan-abilist",161 cl::desc("File listing native ABI functions and how the pass treats them"),162 cl::Hidden);163 164// Controls whether the pass includes or ignores the labels of pointers in load165// instructions.166static cl::opt<bool> ClCombinePointerLabelsOnLoad(167 "dfsan-combine-pointer-labels-on-load",168 cl::desc("Combine the label of the pointer with the label of the data when "169 "loading from memory."),170 cl::Hidden, cl::init(true));171 172// Controls whether the pass includes or ignores the labels of pointers in173// stores instructions.174static cl::opt<bool> ClCombinePointerLabelsOnStore(175 "dfsan-combine-pointer-labels-on-store",176 cl::desc("Combine the label of the pointer with the label of the data when "177 "storing in memory."),178 cl::Hidden, cl::init(false));179 180// Controls whether the pass propagates labels of offsets in GEP instructions.181static cl::opt<bool> ClCombineOffsetLabelsOnGEP(182 "dfsan-combine-offset-labels-on-gep",183 cl::desc(184 "Combine the label of the offset with the label of the pointer when "185 "doing pointer arithmetic."),186 cl::Hidden, cl::init(true));187 188static cl::list<std::string> ClCombineTaintLookupTables(189 "dfsan-combine-taint-lookup-table",190 cl::desc(191 "When dfsan-combine-offset-labels-on-gep and/or "192 "dfsan-combine-pointer-labels-on-load are false, this flag can "193 "be used to re-enable combining offset and/or pointer taint when "194 "loading specific constant global variables (i.e. lookup tables)."),195 cl::Hidden);196 197static cl::opt<bool> ClDebugNonzeroLabels(198 "dfsan-debug-nonzero-labels",199 cl::desc("Insert calls to __dfsan_nonzero_label on observing a parameter, "200 "load or return with a nonzero label"),201 cl::Hidden);202 203// Experimental feature that inserts callbacks for certain data events.204// Currently callbacks are only inserted for loads, stores, memory transfers205// (i.e. memcpy and memmove), and comparisons.206//207// If this flag is set to true, the user must provide definitions for the208// following callback functions:209// void __dfsan_load_callback(dfsan_label Label, void* addr);210// void __dfsan_store_callback(dfsan_label Label, void* addr);211// void __dfsan_mem_transfer_callback(dfsan_label *Start, size_t Len);212// void __dfsan_cmp_callback(dfsan_label CombinedLabel);213static cl::opt<bool> ClEventCallbacks(214 "dfsan-event-callbacks",215 cl::desc("Insert calls to __dfsan_*_callback functions on data events."),216 cl::Hidden, cl::init(false));217 218// Experimental feature that inserts callbacks for conditionals, including:219// conditional branch, switch, select.220// This must be true for dfsan_set_conditional_callback() to have effect.221static cl::opt<bool> ClConditionalCallbacks(222 "dfsan-conditional-callbacks",223 cl::desc("Insert calls to callback functions on conditionals."), cl::Hidden,224 cl::init(false));225 226// Experimental feature that inserts callbacks for data reaching a function,227// either via function arguments and loads.228// This must be true for dfsan_set_reaches_function_callback() to have effect.229static cl::opt<bool> ClReachesFunctionCallbacks(230 "dfsan-reaches-function-callbacks",231 cl::desc("Insert calls to callback functions on data reaching a function."),232 cl::Hidden, cl::init(false));233 234// Controls whether the pass tracks the control flow of select instructions.235static cl::opt<bool> ClTrackSelectControlFlow(236 "dfsan-track-select-control-flow",237 cl::desc("Propagate labels from condition values of select instructions "238 "to results."),239 cl::Hidden, cl::init(true));240 241// TODO: This default value follows MSan. DFSan may use a different value.242static cl::opt<int> ClInstrumentWithCallThreshold(243 "dfsan-instrument-with-call-threshold",244 cl::desc("If the function being instrumented requires more than "245 "this number of origin stores, use callbacks instead of "246 "inline checks (-1 means never use callbacks)."),247 cl::Hidden, cl::init(3500));248 249// Controls how to track origins.250// * 0: do not track origins.251// * 1: track origins at memory store operations.252// * 2: track origins at memory load and store operations.253// TODO: track callsites.254static cl::opt<int> ClTrackOrigins("dfsan-track-origins",255 cl::desc("Track origins of labels"),256 cl::Hidden, cl::init(0));257 258static cl::opt<bool> ClIgnorePersonalityRoutine(259 "dfsan-ignore-personality-routine",260 cl::desc("If a personality routine is marked uninstrumented from the ABI "261 "list, do not create a wrapper for it."),262 cl::Hidden, cl::init(false));263 264static cl::opt<bool> ClAddGlobalNameSuffix(265 "dfsan-add-global-name-suffix",266 cl::desc("Whether to add .dfsan suffix to global names"), cl::Hidden,267 cl::init(true));268 269static StringRef getGlobalTypeString(const GlobalValue &G) {270 // Types of GlobalVariables are always pointer types.271 Type *GType = G.getValueType();272 // For now we support excluding struct types only.273 if (StructType *SGType = dyn_cast<StructType>(GType)) {274 if (!SGType->isLiteral())275 return SGType->getName();276 }277 return "<unknown type>";278}279 280namespace {281 282// Memory map parameters used in application-to-shadow address calculation.283// Offset = (Addr & ~AndMask) ^ XorMask284// Shadow = ShadowBase + Offset285// Origin = (OriginBase + Offset) & ~3ULL286struct MemoryMapParams {287 uint64_t AndMask;288 uint64_t XorMask;289 uint64_t ShadowBase;290 uint64_t OriginBase;291};292 293} // end anonymous namespace294 295// NOLINTBEGIN(readability-identifier-naming)296// aarch64 Linux297const MemoryMapParams Linux_AArch64_MemoryMapParams = {298 0, // AndMask (not used)299 0x0B00000000000, // XorMask300 0, // ShadowBase (not used)301 0x0200000000000, // OriginBase302};303 304// x86_64 Linux305const MemoryMapParams Linux_X86_64_MemoryMapParams = {306 0, // AndMask (not used)307 0x500000000000, // XorMask308 0, // ShadowBase (not used)309 0x100000000000, // OriginBase310};311// NOLINTEND(readability-identifier-naming)312 313// loongarch64 Linux314const MemoryMapParams Linux_LoongArch64_MemoryMapParams = {315 0, // AndMask (not used)316 0x500000000000, // XorMask317 0, // ShadowBase (not used)318 0x100000000000, // OriginBase319};320 321namespace {322 323class DFSanABIList {324 std::unique_ptr<SpecialCaseList> SCL;325 326public:327 DFSanABIList() = default;328 329 void set(std::unique_ptr<SpecialCaseList> List) { SCL = std::move(List); }330 331 /// Returns whether either this function or its source file are listed in the332 /// given category.333 bool isIn(const Function &F, StringRef Category) const {334 return isIn(*F.getParent(), Category) ||335 SCL->inSection("dataflow", "fun", F.getName(), Category);336 }337 338 /// Returns whether this global alias is listed in the given category.339 ///340 /// If GA aliases a function, the alias's name is matched as a function name341 /// would be. Similarly, aliases of globals are matched like globals.342 bool isIn(const GlobalAlias &GA, StringRef Category) const {343 if (isIn(*GA.getParent(), Category))344 return true;345 346 if (isa<FunctionType>(GA.getValueType()))347 return SCL->inSection("dataflow", "fun", GA.getName(), Category);348 349 return SCL->inSection("dataflow", "global", GA.getName(), Category) ||350 SCL->inSection("dataflow", "type", getGlobalTypeString(GA),351 Category);352 }353 354 /// Returns whether this module is listed in the given category.355 bool isIn(const Module &M, StringRef Category) const {356 return SCL->inSection("dataflow", "src", M.getModuleIdentifier(), Category);357 }358};359 360/// TransformedFunction is used to express the result of transforming one361/// function type into another. This struct is immutable. It holds metadata362/// useful for updating calls of the old function to the new type.363struct TransformedFunction {364 TransformedFunction(FunctionType *OriginalType, FunctionType *TransformedType,365 const std::vector<unsigned> &ArgumentIndexMapping)366 : OriginalType(OriginalType), TransformedType(TransformedType),367 ArgumentIndexMapping(ArgumentIndexMapping) {}368 369 // Disallow copies.370 TransformedFunction(const TransformedFunction &) = delete;371 TransformedFunction &operator=(const TransformedFunction &) = delete;372 373 // Allow moves.374 TransformedFunction(TransformedFunction &&) = default;375 TransformedFunction &operator=(TransformedFunction &&) = default;376 377 /// Type of the function before the transformation.378 FunctionType *OriginalType;379 380 /// Type of the function after the transformation.381 FunctionType *TransformedType;382 383 /// Transforming a function may change the position of arguments. This384 /// member records the mapping from each argument's old position to its new385 /// position. Argument positions are zero-indexed. If the transformation386 /// from F to F' made the first argument of F into the third argument of F',387 /// then ArgumentIndexMapping[0] will equal 2.388 std::vector<unsigned> ArgumentIndexMapping;389};390 391/// Given function attributes from a call site for the original function,392/// return function attributes appropriate for a call to the transformed393/// function.394AttributeList395transformFunctionAttributes(const TransformedFunction &TransformedFunction,396 LLVMContext &Ctx, AttributeList CallSiteAttrs) {397 398 // Construct a vector of AttributeSet for each function argument.399 std::vector<llvm::AttributeSet> ArgumentAttributes(400 TransformedFunction.TransformedType->getNumParams());401 402 // Copy attributes from the parameter of the original function to the403 // transformed version. 'ArgumentIndexMapping' holds the mapping from404 // old argument position to new.405 for (unsigned I = 0, IE = TransformedFunction.ArgumentIndexMapping.size();406 I < IE; ++I) {407 unsigned TransformedIndex = TransformedFunction.ArgumentIndexMapping[I];408 ArgumentAttributes[TransformedIndex] = CallSiteAttrs.getParamAttrs(I);409 }410 411 // Copy annotations on varargs arguments.412 for (unsigned I = TransformedFunction.OriginalType->getNumParams(),413 IE = CallSiteAttrs.getNumAttrSets();414 I < IE; ++I) {415 ArgumentAttributes.push_back(CallSiteAttrs.getParamAttrs(I));416 }417 418 return AttributeList::get(Ctx, CallSiteAttrs.getFnAttrs(),419 CallSiteAttrs.getRetAttrs(),420 llvm::ArrayRef(ArgumentAttributes));421}422 423class DataFlowSanitizer {424 friend struct DFSanFunction;425 friend class DFSanVisitor;426 427 enum { ShadowWidthBits = 8, ShadowWidthBytes = ShadowWidthBits / 8 };428 429 enum { OriginWidthBits = 32, OriginWidthBytes = OriginWidthBits / 8 };430 431 /// How should calls to uninstrumented functions be handled?432 enum WrapperKind {433 /// This function is present in an uninstrumented form but we don't know434 /// how it should be handled. Print a warning and call the function anyway.435 /// Don't label the return value.436 WK_Warning,437 438 /// This function does not write to (user-accessible) memory, and its return439 /// value is unlabelled.440 WK_Discard,441 442 /// This function does not write to (user-accessible) memory, and the label443 /// of its return value is the union of the label of its arguments.444 WK_Functional,445 446 /// Instead of calling the function, a custom wrapper __dfsw_F is called,447 /// where F is the name of the function. This function may wrap the448 /// original function or provide its own implementation. WK_Custom uses an449 /// extra pointer argument to return the shadow. This allows the wrapped450 /// form of the function type to be expressed in C.451 WK_Custom452 };453 454 Module *Mod;455 LLVMContext *Ctx;456 Type *Int8Ptr;457 IntegerType *OriginTy;458 PointerType *OriginPtrTy;459 ConstantInt *ZeroOrigin;460 /// The shadow type for all primitive types and vector types.461 IntegerType *PrimitiveShadowTy;462 PointerType *PrimitiveShadowPtrTy;463 IntegerType *IntptrTy;464 ConstantInt *ZeroPrimitiveShadow;465 Constant *ArgTLS;466 ArrayType *ArgOriginTLSTy;467 Constant *ArgOriginTLS;468 Constant *RetvalTLS;469 Constant *RetvalOriginTLS;470 FunctionType *DFSanUnionLoadFnTy;471 FunctionType *DFSanLoadLabelAndOriginFnTy;472 FunctionType *DFSanUnimplementedFnTy;473 FunctionType *DFSanWrapperExternWeakNullFnTy;474 FunctionType *DFSanSetLabelFnTy;475 FunctionType *DFSanNonzeroLabelFnTy;476 FunctionType *DFSanVarargWrapperFnTy;477 FunctionType *DFSanConditionalCallbackFnTy;478 FunctionType *DFSanConditionalCallbackOriginFnTy;479 FunctionType *DFSanReachesFunctionCallbackFnTy;480 FunctionType *DFSanReachesFunctionCallbackOriginFnTy;481 FunctionType *DFSanCmpCallbackFnTy;482 FunctionType *DFSanLoadStoreCallbackFnTy;483 FunctionType *DFSanMemTransferCallbackFnTy;484 FunctionType *DFSanChainOriginFnTy;485 FunctionType *DFSanChainOriginIfTaintedFnTy;486 FunctionType *DFSanMemOriginTransferFnTy;487 FunctionType *DFSanMemShadowOriginTransferFnTy;488 FunctionType *DFSanMemShadowOriginConditionalExchangeFnTy;489 FunctionType *DFSanMaybeStoreOriginFnTy;490 FunctionCallee DFSanUnionLoadFn;491 FunctionCallee DFSanLoadLabelAndOriginFn;492 FunctionCallee DFSanUnimplementedFn;493 FunctionCallee DFSanWrapperExternWeakNullFn;494 FunctionCallee DFSanSetLabelFn;495 FunctionCallee DFSanNonzeroLabelFn;496 FunctionCallee DFSanVarargWrapperFn;497 FunctionCallee DFSanLoadCallbackFn;498 FunctionCallee DFSanStoreCallbackFn;499 FunctionCallee DFSanMemTransferCallbackFn;500 FunctionCallee DFSanConditionalCallbackFn;501 FunctionCallee DFSanConditionalCallbackOriginFn;502 FunctionCallee DFSanReachesFunctionCallbackFn;503 FunctionCallee DFSanReachesFunctionCallbackOriginFn;504 FunctionCallee DFSanCmpCallbackFn;505 FunctionCallee DFSanChainOriginFn;506 FunctionCallee DFSanChainOriginIfTaintedFn;507 FunctionCallee DFSanMemOriginTransferFn;508 FunctionCallee DFSanMemShadowOriginTransferFn;509 FunctionCallee DFSanMemShadowOriginConditionalExchangeFn;510 FunctionCallee DFSanMaybeStoreOriginFn;511 SmallPtrSet<Value *, 16> DFSanRuntimeFunctions;512 MDNode *ColdCallWeights;513 MDNode *OriginStoreWeights;514 DFSanABIList ABIList;515 DenseMap<Value *, Function *> UnwrappedFnMap;516 AttributeMask ReadOnlyNoneAttrs;517 StringSet<> CombineTaintLookupTableNames;518 519 /// Memory map parameters used in calculation mapping application addresses520 /// to shadow addresses and origin addresses.521 const MemoryMapParams *MapParams;522 523 Value *getShadowOffset(Value *Addr, IRBuilder<> &IRB);524 Value *getShadowAddress(Value *Addr, BasicBlock::iterator Pos);525 Value *getShadowAddress(Value *Addr, BasicBlock::iterator Pos,526 Value *ShadowOffset);527 std::pair<Value *, Value *> getShadowOriginAddress(Value *Addr,528 Align InstAlignment,529 BasicBlock::iterator Pos);530 bool isInstrumented(const Function *F);531 bool isInstrumented(const GlobalAlias *GA);532 bool isForceZeroLabels(const Function *F);533 TransformedFunction getCustomFunctionType(FunctionType *T);534 WrapperKind getWrapperKind(Function *F);535 void addGlobalNameSuffix(GlobalValue *GV);536 void buildExternWeakCheckIfNeeded(IRBuilder<> &IRB, Function *F);537 Function *buildWrapperFunction(Function *F, StringRef NewFName,538 GlobalValue::LinkageTypes NewFLink,539 FunctionType *NewFT);540 void initializeCallbackFunctions(Module &M);541 void initializeRuntimeFunctions(Module &M);542 bool initializeModule(Module &M);543 544 /// Advances \p OriginAddr to point to the next 32-bit origin and then loads545 /// from it. Returns the origin's loaded value.546 Value *loadNextOrigin(BasicBlock::iterator Pos, Align OriginAlign,547 Value **OriginAddr);548 549 /// Returns whether the given load byte size is amenable to inlined550 /// optimization patterns.551 bool hasLoadSizeForFastPath(uint64_t Size);552 553 /// Returns whether the pass tracks origins. Supports only TLS ABI mode.554 bool shouldTrackOrigins();555 556 /// Returns a zero constant with the shadow type of OrigTy.557 ///558 /// getZeroShadow({T1,T2,...}) = {getZeroShadow(T1),getZeroShadow(T2,...}559 /// getZeroShadow([n x T]) = [n x getZeroShadow(T)]560 /// getZeroShadow(other type) = i16(0)561 Constant *getZeroShadow(Type *OrigTy);562 /// Returns a zero constant with the shadow type of V's type.563 Constant *getZeroShadow(Value *V);564 565 /// Checks if V is a zero shadow.566 bool isZeroShadow(Value *V);567 568 /// Returns the shadow type of OrigTy.569 ///570 /// getShadowTy({T1,T2,...}) = {getShadowTy(T1),getShadowTy(T2),...}571 /// getShadowTy([n x T]) = [n x getShadowTy(T)]572 /// getShadowTy(other type) = i16573 Type *getShadowTy(Type *OrigTy);574 /// Returns the shadow type of V's type.575 Type *getShadowTy(Value *V);576 577 const uint64_t NumOfElementsInArgOrgTLS = ArgTLSSize / OriginWidthBytes;578 579public:580 DataFlowSanitizer(const std::vector<std::string> &ABIListFiles,581 IntrusiveRefCntPtr<vfs::FileSystem> FS);582 583 bool runImpl(Module &M,584 llvm::function_ref<TargetLibraryInfo &(Function &)> GetTLI);585};586 587struct DFSanFunction {588 DataFlowSanitizer &DFS;589 Function *F;590 DominatorTree DT;591 bool IsNativeABI;592 bool IsForceZeroLabels;593 TargetLibraryInfo &TLI;594 AllocaInst *LabelReturnAlloca = nullptr;595 AllocaInst *OriginReturnAlloca = nullptr;596 DenseMap<Value *, Value *> ValShadowMap;597 DenseMap<Value *, Value *> ValOriginMap;598 DenseMap<AllocaInst *, AllocaInst *> AllocaShadowMap;599 DenseMap<AllocaInst *, AllocaInst *> AllocaOriginMap;600 601 struct PHIFixupElement {602 PHINode *Phi;603 PHINode *ShadowPhi;604 PHINode *OriginPhi;605 };606 std::vector<PHIFixupElement> PHIFixups;607 608 DenseSet<Instruction *> SkipInsts;609 std::vector<Value *> NonZeroChecks;610 611 struct CachedShadow {612 BasicBlock *Block; // The block where Shadow is defined.613 Value *Shadow;614 };615 /// Maps a value to its latest shadow value in terms of domination tree.616 DenseMap<std::pair<Value *, Value *>, CachedShadow> CachedShadows;617 /// Maps a value to its latest collapsed shadow value it was converted to in618 /// terms of domination tree. When ClDebugNonzeroLabels is on, this cache is619 /// used at a post process where CFG blocks are split. So it does not cache620 /// BasicBlock like CachedShadows, but uses domination between values.621 DenseMap<Value *, Value *> CachedCollapsedShadows;622 DenseMap<Value *, std::set<Value *>> ShadowElements;623 624 DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI,625 bool IsForceZeroLabels, TargetLibraryInfo &TLI)626 : DFS(DFS), F(F), IsNativeABI(IsNativeABI),627 IsForceZeroLabels(IsForceZeroLabels), TLI(TLI) {628 DT.recalculate(*F);629 }630 631 /// Computes the shadow address for a given function argument.632 ///633 /// Shadow = ArgTLS+ArgOffset.634 Value *getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB);635 636 /// Computes the shadow address for a return value.637 Value *getRetvalTLS(Type *T, IRBuilder<> &IRB);638 639 /// Computes the origin address for a given function argument.640 ///641 /// Origin = ArgOriginTLS[ArgNo].642 Value *getArgOriginTLS(unsigned ArgNo, IRBuilder<> &IRB);643 644 /// Computes the origin address for a return value.645 Value *getRetvalOriginTLS();646 647 Value *getOrigin(Value *V);648 void setOrigin(Instruction *I, Value *Origin);649 /// Generates IR to compute the origin of the last operand with a taint label.650 Value *combineOperandOrigins(Instruction *Inst);651 /// Before the instruction Pos, generates IR to compute the last origin with a652 /// taint label. Labels and origins are from vectors Shadows and Origins653 /// correspondingly. The generated IR is like654 /// Sn-1 != Zero ? On-1: ... S2 != Zero ? O2: S1 != Zero ? O1: O0655 /// When Zero is nullptr, it uses ZeroPrimitiveShadow. Otherwise it can be656 /// zeros with other bitwidths.657 Value *combineOrigins(const std::vector<Value *> &Shadows,658 const std::vector<Value *> &Origins,659 BasicBlock::iterator Pos, ConstantInt *Zero = nullptr);660 661 Value *getShadow(Value *V);662 void setShadow(Instruction *I, Value *Shadow);663 /// Generates IR to compute the union of the two given shadows, inserting it664 /// before Pos. The combined value is with primitive type.665 Value *combineShadows(Value *V1, Value *V2, BasicBlock::iterator Pos);666 /// Combines the shadow values of V1 and V2, then converts the combined value667 /// with primitive type into a shadow value with the original type T.668 Value *combineShadowsThenConvert(Type *T, Value *V1, Value *V2,669 BasicBlock::iterator Pos);670 Value *combineOperandShadows(Instruction *Inst);671 672 /// Generates IR to load shadow and origin corresponding to bytes [\p673 /// Addr, \p Addr + \p Size), where addr has alignment \p674 /// InstAlignment, and take the union of each of those shadows. The returned675 /// shadow always has primitive type.676 ///677 /// When tracking loads is enabled, the returned origin is a chain at the678 /// current stack if the returned shadow is tainted.679 std::pair<Value *, Value *> loadShadowOrigin(Value *Addr, uint64_t Size,680 Align InstAlignment,681 BasicBlock::iterator Pos);682 683 void storePrimitiveShadowOrigin(Value *Addr, uint64_t Size,684 Align InstAlignment, Value *PrimitiveShadow,685 Value *Origin, BasicBlock::iterator Pos);686 /// Applies PrimitiveShadow to all primitive subtypes of T, returning687 /// the expanded shadow value.688 ///689 /// EFP({T1,T2, ...}, PS) = {EFP(T1,PS),EFP(T2,PS),...}690 /// EFP([n x T], PS) = [n x EFP(T,PS)]691 /// EFP(other types, PS) = PS692 Value *expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow,693 BasicBlock::iterator Pos);694 /// Collapses Shadow into a single primitive shadow value, unioning all695 /// primitive shadow values in the process. Returns the final primitive696 /// shadow value.697 ///698 /// CTP({V1,V2, ...}) = UNION(CFP(V1,PS),CFP(V2,PS),...)699 /// CTP([V1,V2,...]) = UNION(CFP(V1,PS),CFP(V2,PS),...)700 /// CTP(other types, PS) = PS701 Value *collapseToPrimitiveShadow(Value *Shadow, BasicBlock::iterator Pos);702 703 void storeZeroPrimitiveShadow(Value *Addr, uint64_t Size, Align ShadowAlign,704 BasicBlock::iterator Pos);705 706 Align getShadowAlign(Align InstAlignment);707 708 // If ClConditionalCallbacks is enabled, insert a callback after a given709 // branch instruction using the given conditional expression.710 void addConditionalCallbacksIfEnabled(Instruction &I, Value *Condition);711 712 // If ClReachesFunctionCallbacks is enabled, insert a callback for each713 // argument and load instruction.714 void addReachesFunctionCallbacksIfEnabled(IRBuilder<> &IRB, Instruction &I,715 Value *Data);716 717 bool isLookupTableConstant(Value *P);718 719private:720 /// Collapses the shadow with aggregate type into a single primitive shadow721 /// value.722 template <class AggregateType>723 Value *collapseAggregateShadow(AggregateType *AT, Value *Shadow,724 IRBuilder<> &IRB);725 726 Value *collapseToPrimitiveShadow(Value *Shadow, IRBuilder<> &IRB);727 728 /// Returns the shadow value of an argument A.729 Value *getShadowForTLSArgument(Argument *A);730 731 /// The fast path of loading shadows.732 std::pair<Value *, Value *>733 loadShadowFast(Value *ShadowAddr, Value *OriginAddr, uint64_t Size,734 Align ShadowAlign, Align OriginAlign, Value *FirstOrigin,735 BasicBlock::iterator Pos);736 737 Align getOriginAlign(Align InstAlignment);738 739 /// Because 4 contiguous bytes share one 4-byte origin, the most accurate load740 /// is __dfsan_load_label_and_origin. This function returns the union of all741 /// labels and the origin of the first taint label. However this is an742 /// additional call with many instructions. To ensure common cases are fast,743 /// checks if it is possible to load labels and origins without using the744 /// callback function.745 ///746 /// When enabling tracking load instructions, we always use747 /// __dfsan_load_label_and_origin to reduce code size.748 bool useCallbackLoadLabelAndOrigin(uint64_t Size, Align InstAlignment);749 750 /// Returns a chain at the current stack with previous origin V.751 Value *updateOrigin(Value *V, IRBuilder<> &IRB);752 753 /// Returns a chain at the current stack with previous origin V if Shadow is754 /// tainted.755 Value *updateOriginIfTainted(Value *Shadow, Value *Origin, IRBuilder<> &IRB);756 757 /// Creates an Intptr = Origin | Origin << 32 if Intptr's size is 64. Returns758 /// Origin otherwise.759 Value *originToIntptr(IRBuilder<> &IRB, Value *Origin);760 761 /// Stores Origin into the address range [StoreOriginAddr, StoreOriginAddr +762 /// Size).763 void paintOrigin(IRBuilder<> &IRB, Value *Origin, Value *StoreOriginAddr,764 uint64_t StoreOriginSize, Align Alignment);765 766 /// Stores Origin in terms of its Shadow value.767 /// * Do not write origins for zero shadows because we do not trace origins768 /// for untainted sinks.769 /// * Use __dfsan_maybe_store_origin if there are too many origin store770 /// instrumentations.771 void storeOrigin(BasicBlock::iterator Pos, Value *Addr, uint64_t Size,772 Value *Shadow, Value *Origin, Value *StoreOriginAddr,773 Align InstAlignment);774 775 /// Convert a scalar value to an i1 by comparing with 0.776 Value *convertToBool(Value *V, IRBuilder<> &IRB, const Twine &Name = "");777 778 bool shouldInstrumentWithCall();779 780 /// Generates IR to load shadow and origin corresponding to bytes [\p781 /// Addr, \p Addr + \p Size), where addr has alignment \p782 /// InstAlignment, and take the union of each of those shadows. The returned783 /// shadow always has primitive type.784 std::pair<Value *, Value *>785 loadShadowOriginSansLoadTracking(Value *Addr, uint64_t Size,786 Align InstAlignment,787 BasicBlock::iterator Pos);788 int NumOriginStores = 0;789};790 791class DFSanVisitor : public InstVisitor<DFSanVisitor> {792public:793 DFSanFunction &DFSF;794 795 DFSanVisitor(DFSanFunction &DFSF) : DFSF(DFSF) {}796 797 const DataLayout &getDataLayout() const {798 return DFSF.F->getDataLayout();799 }800 801 // Combines shadow values and origins for all of I's operands.802 void visitInstOperands(Instruction &I);803 804 void visitUnaryOperator(UnaryOperator &UO);805 void visitBinaryOperator(BinaryOperator &BO);806 void visitBitCastInst(BitCastInst &BCI);807 void visitCastInst(CastInst &CI);808 void visitCmpInst(CmpInst &CI);809 void visitLandingPadInst(LandingPadInst &LPI);810 void visitGetElementPtrInst(GetElementPtrInst &GEPI);811 void visitLoadInst(LoadInst &LI);812 void visitStoreInst(StoreInst &SI);813 void visitAtomicRMWInst(AtomicRMWInst &I);814 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);815 void visitReturnInst(ReturnInst &RI);816 void visitLibAtomicLoad(CallBase &CB);817 void visitLibAtomicStore(CallBase &CB);818 void visitLibAtomicExchange(CallBase &CB);819 void visitLibAtomicCompareExchange(CallBase &CB);820 void visitCallBase(CallBase &CB);821 void visitPHINode(PHINode &PN);822 void visitExtractElementInst(ExtractElementInst &I);823 void visitInsertElementInst(InsertElementInst &I);824 void visitShuffleVectorInst(ShuffleVectorInst &I);825 void visitExtractValueInst(ExtractValueInst &I);826 void visitInsertValueInst(InsertValueInst &I);827 void visitAllocaInst(AllocaInst &I);828 void visitSelectInst(SelectInst &I);829 void visitMemSetInst(MemSetInst &I);830 void visitMemTransferInst(MemTransferInst &I);831 void visitBranchInst(BranchInst &BR);832 void visitSwitchInst(SwitchInst &SW);833 834private:835 void visitCASOrRMW(Align InstAlignment, Instruction &I);836 837 // Returns false when this is an invoke of a custom function.838 bool visitWrappedCallBase(Function &F, CallBase &CB);839 840 // Combines origins for all of I's operands.841 void visitInstOperandOrigins(Instruction &I);842 843 void addShadowArguments(Function &F, CallBase &CB, std::vector<Value *> &Args,844 IRBuilder<> &IRB);845 846 void addOriginArguments(Function &F, CallBase &CB, std::vector<Value *> &Args,847 IRBuilder<> &IRB);848 849 Value *makeAddAcquireOrderingTable(IRBuilder<> &IRB);850 Value *makeAddReleaseOrderingTable(IRBuilder<> &IRB);851};852 853bool LibAtomicFunction(const Function &F) {854 // This is a bit of a hack because TargetLibraryInfo is a function pass.855 // The DFSan pass would need to be refactored to be function pass oriented856 // (like MSan is) in order to fit together nicely with TargetLibraryInfo.857 // We need this check to prevent them from being instrumented, or wrapped.858 // Match on name and number of arguments.859 if (!F.hasName() || F.isVarArg())860 return false;861 switch (F.arg_size()) {862 case 4:863 return F.getName() == "__atomic_load" || F.getName() == "__atomic_store";864 case 5:865 return F.getName() == "__atomic_exchange";866 case 6:867 return F.getName() == "__atomic_compare_exchange";868 default:869 return false;870 }871}872 873} // end anonymous namespace874 875DataFlowSanitizer::DataFlowSanitizer(876 const std::vector<std::string> &ABIListFiles,877 IntrusiveRefCntPtr<vfs::FileSystem> FS) {878 std::vector<std::string> AllABIListFiles(std::move(ABIListFiles));879 llvm::append_range(AllABIListFiles, ClABIListFiles);880 ABIList.set(SpecialCaseList::createOrDie(AllABIListFiles, *FS));881 882 CombineTaintLookupTableNames.insert_range(ClCombineTaintLookupTables);883}884 885TransformedFunction DataFlowSanitizer::getCustomFunctionType(FunctionType *T) {886 SmallVector<Type *, 4> ArgTypes;887 888 // Some parameters of the custom function being constructed are889 // parameters of T. Record the mapping from parameters of T to890 // parameters of the custom function, so that parameter attributes891 // at call sites can be updated.892 std::vector<unsigned> ArgumentIndexMapping;893 for (unsigned I = 0, E = T->getNumParams(); I != E; ++I) {894 Type *ParamType = T->getParamType(I);895 ArgumentIndexMapping.push_back(ArgTypes.size());896 ArgTypes.push_back(ParamType);897 }898 for (unsigned I = 0, E = T->getNumParams(); I != E; ++I)899 ArgTypes.push_back(PrimitiveShadowTy);900 if (T->isVarArg())901 ArgTypes.push_back(PrimitiveShadowPtrTy);902 Type *RetType = T->getReturnType();903 if (!RetType->isVoidTy())904 ArgTypes.push_back(PrimitiveShadowPtrTy);905 906 if (shouldTrackOrigins()) {907 for (unsigned I = 0, E = T->getNumParams(); I != E; ++I)908 ArgTypes.push_back(OriginTy);909 if (T->isVarArg())910 ArgTypes.push_back(OriginPtrTy);911 if (!RetType->isVoidTy())912 ArgTypes.push_back(OriginPtrTy);913 }914 915 return TransformedFunction(916 T, FunctionType::get(T->getReturnType(), ArgTypes, T->isVarArg()),917 ArgumentIndexMapping);918}919 920bool DataFlowSanitizer::isZeroShadow(Value *V) {921 Type *T = V->getType();922 if (!isa<ArrayType>(T) && !isa<StructType>(T)) {923 if (const ConstantInt *CI = dyn_cast<ConstantInt>(V))924 return CI->isZero();925 return false;926 }927 928 return isa<ConstantAggregateZero>(V);929}930 931bool DataFlowSanitizer::hasLoadSizeForFastPath(uint64_t Size) {932 uint64_t ShadowSize = Size * ShadowWidthBytes;933 return ShadowSize % 8 == 0 || ShadowSize == 4;934}935 936bool DataFlowSanitizer::shouldTrackOrigins() {937 static const bool ShouldTrackOrigins = ClTrackOrigins;938 return ShouldTrackOrigins;939}940 941Constant *DataFlowSanitizer::getZeroShadow(Type *OrigTy) {942 if (!isa<ArrayType>(OrigTy) && !isa<StructType>(OrigTy))943 return ZeroPrimitiveShadow;944 Type *ShadowTy = getShadowTy(OrigTy);945 return ConstantAggregateZero::get(ShadowTy);946}947 948Constant *DataFlowSanitizer::getZeroShadow(Value *V) {949 return getZeroShadow(V->getType());950}951 952static Value *expandFromPrimitiveShadowRecursive(953 Value *Shadow, SmallVector<unsigned, 4> &Indices, Type *SubShadowTy,954 Value *PrimitiveShadow, IRBuilder<> &IRB) {955 if (!isa<ArrayType>(SubShadowTy) && !isa<StructType>(SubShadowTy))956 return IRB.CreateInsertValue(Shadow, PrimitiveShadow, Indices);957 958 if (ArrayType *AT = dyn_cast<ArrayType>(SubShadowTy)) {959 for (unsigned Idx = 0; Idx < AT->getNumElements(); Idx++) {960 Indices.push_back(Idx);961 Shadow = expandFromPrimitiveShadowRecursive(962 Shadow, Indices, AT->getElementType(), PrimitiveShadow, IRB);963 Indices.pop_back();964 }965 return Shadow;966 }967 968 if (StructType *ST = dyn_cast<StructType>(SubShadowTy)) {969 for (unsigned Idx = 0; Idx < ST->getNumElements(); Idx++) {970 Indices.push_back(Idx);971 Shadow = expandFromPrimitiveShadowRecursive(972 Shadow, Indices, ST->getElementType(Idx), PrimitiveShadow, IRB);973 Indices.pop_back();974 }975 return Shadow;976 }977 llvm_unreachable("Unexpected shadow type");978}979 980bool DFSanFunction::shouldInstrumentWithCall() {981 return ClInstrumentWithCallThreshold >= 0 &&982 NumOriginStores >= ClInstrumentWithCallThreshold;983}984 985Value *DFSanFunction::expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow,986 BasicBlock::iterator Pos) {987 Type *ShadowTy = DFS.getShadowTy(T);988 989 if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy))990 return PrimitiveShadow;991 992 if (DFS.isZeroShadow(PrimitiveShadow))993 return DFS.getZeroShadow(ShadowTy);994 995 IRBuilder<> IRB(Pos->getParent(), Pos);996 SmallVector<unsigned, 4> Indices;997 Value *Shadow = UndefValue::get(ShadowTy);998 Shadow = expandFromPrimitiveShadowRecursive(Shadow, Indices, ShadowTy,999 PrimitiveShadow, IRB);1000 1001 // Caches the primitive shadow value that built the shadow value.1002 CachedCollapsedShadows[Shadow] = PrimitiveShadow;1003 return Shadow;1004}1005 1006template <class AggregateType>1007Value *DFSanFunction::collapseAggregateShadow(AggregateType *AT, Value *Shadow,1008 IRBuilder<> &IRB) {1009 if (!AT->getNumElements())1010 return DFS.ZeroPrimitiveShadow;1011 1012 Value *FirstItem = IRB.CreateExtractValue(Shadow, 0);1013 Value *Aggregator = collapseToPrimitiveShadow(FirstItem, IRB);1014 1015 for (unsigned Idx = 1; Idx < AT->getNumElements(); Idx++) {1016 Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx);1017 Value *ShadowInner = collapseToPrimitiveShadow(ShadowItem, IRB);1018 Aggregator = IRB.CreateOr(Aggregator, ShadowInner);1019 }1020 return Aggregator;1021}1022 1023Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow,1024 IRBuilder<> &IRB) {1025 Type *ShadowTy = Shadow->getType();1026 if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy))1027 return Shadow;1028 if (ArrayType *AT = dyn_cast<ArrayType>(ShadowTy))1029 return collapseAggregateShadow<>(AT, Shadow, IRB);1030 if (StructType *ST = dyn_cast<StructType>(ShadowTy))1031 return collapseAggregateShadow<>(ST, Shadow, IRB);1032 llvm_unreachable("Unexpected shadow type");1033}1034 1035Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow,1036 BasicBlock::iterator Pos) {1037 Type *ShadowTy = Shadow->getType();1038 if (!isa<ArrayType>(ShadowTy) && !isa<StructType>(ShadowTy))1039 return Shadow;1040 1041 // Checks if the cached collapsed shadow value dominates Pos.1042 Value *&CS = CachedCollapsedShadows[Shadow];1043 if (CS && DT.dominates(CS, Pos))1044 return CS;1045 1046 IRBuilder<> IRB(Pos->getParent(), Pos);1047 Value *PrimitiveShadow = collapseToPrimitiveShadow(Shadow, IRB);1048 // Caches the converted primitive shadow value.1049 CS = PrimitiveShadow;1050 return PrimitiveShadow;1051}1052 1053void DFSanFunction::addConditionalCallbacksIfEnabled(Instruction &I,1054 Value *Condition) {1055 if (!ClConditionalCallbacks) {1056 return;1057 }1058 IRBuilder<> IRB(&I);1059 Value *CondShadow = getShadow(Condition);1060 CallInst *CI;1061 if (DFS.shouldTrackOrigins()) {1062 Value *CondOrigin = getOrigin(Condition);1063 CI = IRB.CreateCall(DFS.DFSanConditionalCallbackOriginFn,1064 {CondShadow, CondOrigin});1065 } else {1066 CI = IRB.CreateCall(DFS.DFSanConditionalCallbackFn, {CondShadow});1067 }1068 CI->addParamAttr(0, Attribute::ZExt);1069}1070 1071void DFSanFunction::addReachesFunctionCallbacksIfEnabled(IRBuilder<> &IRB,1072 Instruction &I,1073 Value *Data) {1074 if (!ClReachesFunctionCallbacks) {1075 return;1076 }1077 const DebugLoc &dbgloc = I.getDebugLoc();1078 Value *DataShadow = collapseToPrimitiveShadow(getShadow(Data), IRB);1079 ConstantInt *CILine;1080 llvm::Value *FilePathPtr;1081 1082 if (dbgloc.get() == nullptr) {1083 CILine = llvm::ConstantInt::get(I.getContext(), llvm::APInt(32, 0));1084 FilePathPtr = IRB.CreateGlobalString(1085 I.getFunction()->getParent()->getSourceFileName());1086 } else {1087 CILine = llvm::ConstantInt::get(I.getContext(),1088 llvm::APInt(32, dbgloc.getLine()));1089 FilePathPtr = IRB.CreateGlobalString(dbgloc->getFilename());1090 }1091 1092 llvm::Value *FunctionNamePtr =1093 IRB.CreateGlobalString(I.getFunction()->getName());1094 1095 CallInst *CB;1096 std::vector<Value *> args;1097 1098 if (DFS.shouldTrackOrigins()) {1099 Value *DataOrigin = getOrigin(Data);1100 args = { DataShadow, DataOrigin, FilePathPtr, CILine, FunctionNamePtr };1101 CB = IRB.CreateCall(DFS.DFSanReachesFunctionCallbackOriginFn, args);1102 } else {1103 args = { DataShadow, FilePathPtr, CILine, FunctionNamePtr };1104 CB = IRB.CreateCall(DFS.DFSanReachesFunctionCallbackFn, args);1105 }1106 CB->addParamAttr(0, Attribute::ZExt);1107 CB->setDebugLoc(dbgloc);1108}1109 1110Type *DataFlowSanitizer::getShadowTy(Type *OrigTy) {1111 if (!OrigTy->isSized())1112 return PrimitiveShadowTy;1113 if (isa<IntegerType>(OrigTy))1114 return PrimitiveShadowTy;1115 if (isa<VectorType>(OrigTy))1116 return PrimitiveShadowTy;1117 if (ArrayType *AT = dyn_cast<ArrayType>(OrigTy))1118 return ArrayType::get(getShadowTy(AT->getElementType()),1119 AT->getNumElements());1120 if (StructType *ST = dyn_cast<StructType>(OrigTy)) {1121 SmallVector<Type *, 4> Elements;1122 for (unsigned I = 0, N = ST->getNumElements(); I < N; ++I)1123 Elements.push_back(getShadowTy(ST->getElementType(I)));1124 return StructType::get(*Ctx, Elements);1125 }1126 return PrimitiveShadowTy;1127}1128 1129Type *DataFlowSanitizer::getShadowTy(Value *V) {1130 return getShadowTy(V->getType());1131}1132 1133bool DataFlowSanitizer::initializeModule(Module &M) {1134 Triple TargetTriple(M.getTargetTriple());1135 const DataLayout &DL = M.getDataLayout();1136 1137 if (TargetTriple.getOS() != Triple::Linux)1138 report_fatal_error("unsupported operating system");1139 switch (TargetTriple.getArch()) {1140 case Triple::aarch64:1141 MapParams = &Linux_AArch64_MemoryMapParams;1142 break;1143 case Triple::x86_64:1144 MapParams = &Linux_X86_64_MemoryMapParams;1145 break;1146 case Triple::loongarch64:1147 MapParams = &Linux_LoongArch64_MemoryMapParams;1148 break;1149 default:1150 report_fatal_error("unsupported architecture");1151 }1152 1153 Mod = &M;1154 Ctx = &M.getContext();1155 Int8Ptr = PointerType::getUnqual(*Ctx);1156 OriginTy = IntegerType::get(*Ctx, OriginWidthBits);1157 OriginPtrTy = PointerType::getUnqual(*Ctx);1158 PrimitiveShadowTy = IntegerType::get(*Ctx, ShadowWidthBits);1159 PrimitiveShadowPtrTy = PointerType::getUnqual(*Ctx);1160 IntptrTy = DL.getIntPtrType(*Ctx);1161 ZeroPrimitiveShadow = ConstantInt::getSigned(PrimitiveShadowTy, 0);1162 ZeroOrigin = ConstantInt::getSigned(OriginTy, 0);1163 1164 Type *DFSanUnionLoadArgs[2] = {PrimitiveShadowPtrTy, IntptrTy};1165 DFSanUnionLoadFnTy = FunctionType::get(PrimitiveShadowTy, DFSanUnionLoadArgs,1166 /*isVarArg=*/false);1167 Type *DFSanLoadLabelAndOriginArgs[2] = {Int8Ptr, IntptrTy};1168 DFSanLoadLabelAndOriginFnTy =1169 FunctionType::get(IntegerType::get(*Ctx, 64), DFSanLoadLabelAndOriginArgs,1170 /*isVarArg=*/false);1171 DFSanUnimplementedFnTy = FunctionType::get(1172 Type::getVoidTy(*Ctx), PointerType::getUnqual(*Ctx), /*isVarArg=*/false);1173 Type *DFSanWrapperExternWeakNullArgs[2] = {Int8Ptr, Int8Ptr};1174 DFSanWrapperExternWeakNullFnTy =1175 FunctionType::get(Type::getVoidTy(*Ctx), DFSanWrapperExternWeakNullArgs,1176 /*isVarArg=*/false);1177 Type *DFSanSetLabelArgs[4] = {PrimitiveShadowTy, OriginTy,1178 PointerType::getUnqual(*Ctx), IntptrTy};1179 DFSanSetLabelFnTy = FunctionType::get(Type::getVoidTy(*Ctx),1180 DFSanSetLabelArgs, /*isVarArg=*/false);1181 DFSanNonzeroLabelFnTy = FunctionType::get(Type::getVoidTy(*Ctx), {},1182 /*isVarArg=*/false);1183 DFSanVarargWrapperFnTy = FunctionType::get(1184 Type::getVoidTy(*Ctx), PointerType::getUnqual(*Ctx), /*isVarArg=*/false);1185 DFSanConditionalCallbackFnTy =1186 FunctionType::get(Type::getVoidTy(*Ctx), PrimitiveShadowTy,1187 /*isVarArg=*/false);1188 Type *DFSanConditionalCallbackOriginArgs[2] = {PrimitiveShadowTy, OriginTy};1189 DFSanConditionalCallbackOriginFnTy = FunctionType::get(1190 Type::getVoidTy(*Ctx), DFSanConditionalCallbackOriginArgs,1191 /*isVarArg=*/false);1192 Type *DFSanReachesFunctionCallbackArgs[4] = {PrimitiveShadowTy, Int8Ptr,1193 OriginTy, Int8Ptr};1194 DFSanReachesFunctionCallbackFnTy =1195 FunctionType::get(Type::getVoidTy(*Ctx), DFSanReachesFunctionCallbackArgs,1196 /*isVarArg=*/false);1197 Type *DFSanReachesFunctionCallbackOriginArgs[5] = {1198 PrimitiveShadowTy, OriginTy, Int8Ptr, OriginTy, Int8Ptr};1199 DFSanReachesFunctionCallbackOriginFnTy = FunctionType::get(1200 Type::getVoidTy(*Ctx), DFSanReachesFunctionCallbackOriginArgs,1201 /*isVarArg=*/false);1202 DFSanCmpCallbackFnTy =1203 FunctionType::get(Type::getVoidTy(*Ctx), PrimitiveShadowTy,1204 /*isVarArg=*/false);1205 DFSanChainOriginFnTy =1206 FunctionType::get(OriginTy, OriginTy, /*isVarArg=*/false);1207 Type *DFSanChainOriginIfTaintedArgs[2] = {PrimitiveShadowTy, OriginTy};1208 DFSanChainOriginIfTaintedFnTy = FunctionType::get(1209 OriginTy, DFSanChainOriginIfTaintedArgs, /*isVarArg=*/false);1210 Type *DFSanMaybeStoreOriginArgs[4] = {IntegerType::get(*Ctx, ShadowWidthBits),1211 Int8Ptr, IntptrTy, OriginTy};1212 DFSanMaybeStoreOriginFnTy = FunctionType::get(1213 Type::getVoidTy(*Ctx), DFSanMaybeStoreOriginArgs, /*isVarArg=*/false);1214 Type *DFSanMemOriginTransferArgs[3] = {Int8Ptr, Int8Ptr, IntptrTy};1215 DFSanMemOriginTransferFnTy = FunctionType::get(1216 Type::getVoidTy(*Ctx), DFSanMemOriginTransferArgs, /*isVarArg=*/false);1217 Type *DFSanMemShadowOriginTransferArgs[3] = {Int8Ptr, Int8Ptr, IntptrTy};1218 DFSanMemShadowOriginTransferFnTy =1219 FunctionType::get(Type::getVoidTy(*Ctx), DFSanMemShadowOriginTransferArgs,1220 /*isVarArg=*/false);1221 Type *DFSanMemShadowOriginConditionalExchangeArgs[5] = {1222 IntegerType::get(*Ctx, 8), Int8Ptr, Int8Ptr, Int8Ptr, IntptrTy};1223 DFSanMemShadowOriginConditionalExchangeFnTy = FunctionType::get(1224 Type::getVoidTy(*Ctx), DFSanMemShadowOriginConditionalExchangeArgs,1225 /*isVarArg=*/false);1226 Type *DFSanLoadStoreCallbackArgs[2] = {PrimitiveShadowTy, Int8Ptr};1227 DFSanLoadStoreCallbackFnTy =1228 FunctionType::get(Type::getVoidTy(*Ctx), DFSanLoadStoreCallbackArgs,1229 /*isVarArg=*/false);1230 Type *DFSanMemTransferCallbackArgs[2] = {PrimitiveShadowPtrTy, IntptrTy};1231 DFSanMemTransferCallbackFnTy =1232 FunctionType::get(Type::getVoidTy(*Ctx), DFSanMemTransferCallbackArgs,1233 /*isVarArg=*/false);1234 1235 ColdCallWeights = MDBuilder(*Ctx).createUnlikelyBranchWeights();1236 OriginStoreWeights = MDBuilder(*Ctx).createUnlikelyBranchWeights();1237 return true;1238}1239 1240bool DataFlowSanitizer::isInstrumented(const Function *F) {1241 return !ABIList.isIn(*F, "uninstrumented");1242}1243 1244bool DataFlowSanitizer::isInstrumented(const GlobalAlias *GA) {1245 return !ABIList.isIn(*GA, "uninstrumented");1246}1247 1248bool DataFlowSanitizer::isForceZeroLabels(const Function *F) {1249 return ABIList.isIn(*F, "force_zero_labels");1250}1251 1252DataFlowSanitizer::WrapperKind DataFlowSanitizer::getWrapperKind(Function *F) {1253 if (ABIList.isIn(*F, "functional"))1254 return WK_Functional;1255 if (ABIList.isIn(*F, "discard"))1256 return WK_Discard;1257 if (ABIList.isIn(*F, "custom"))1258 return WK_Custom;1259 1260 return WK_Warning;1261}1262 1263void DataFlowSanitizer::addGlobalNameSuffix(GlobalValue *GV) {1264 if (!ClAddGlobalNameSuffix)1265 return;1266 1267 std::string GVName = std::string(GV->getName()), Suffix = ".dfsan";1268 GV->setName(GVName + Suffix);1269 1270 // Try to change the name of the function in module inline asm. We only do1271 // this for specific asm directives, currently only ".symver", to try to avoid1272 // corrupting asm which happens to contain the symbol name as a substring.1273 // Note that the substitution for .symver assumes that the versioned symbol1274 // also has an instrumented name.1275 std::string Asm = GV->getParent()->getModuleInlineAsm();1276 std::string SearchStr = ".symver " + GVName + ",";1277 size_t Pos = Asm.find(SearchStr);1278 if (Pos != std::string::npos) {1279 Asm.replace(Pos, SearchStr.size(), ".symver " + GVName + Suffix + ",");1280 Pos = Asm.find('@');1281 1282 if (Pos == std::string::npos)1283 report_fatal_error(Twine("unsupported .symver: ", Asm));1284 1285 Asm.replace(Pos, 1, Suffix + "@");1286 GV->getParent()->setModuleInlineAsm(Asm);1287 }1288}1289 1290void DataFlowSanitizer::buildExternWeakCheckIfNeeded(IRBuilder<> &IRB,1291 Function *F) {1292 // If the function we are wrapping was ExternWeak, it may be null.1293 // The original code before calling this wrapper may have checked for null,1294 // but replacing with a known-to-not-be-null wrapper can break this check.1295 // When replacing uses of the extern weak function with the wrapper we try1296 // to avoid replacing uses in conditionals, but this is not perfect.1297 // In the case where we fail, and accidentally optimize out a null check1298 // for a extern weak function, add a check here to help identify the issue.1299 if (GlobalValue::isExternalWeakLinkage(F->getLinkage())) {1300 std::vector<Value *> Args;1301 Args.push_back(F);1302 Args.push_back(IRB.CreateGlobalString(F->getName()));1303 IRB.CreateCall(DFSanWrapperExternWeakNullFn, Args);1304 }1305}1306 1307Function *1308DataFlowSanitizer::buildWrapperFunction(Function *F, StringRef NewFName,1309 GlobalValue::LinkageTypes NewFLink,1310 FunctionType *NewFT) {1311 FunctionType *FT = F->getFunctionType();1312 Function *NewF = Function::Create(NewFT, NewFLink, F->getAddressSpace(),1313 NewFName, F->getParent());1314 NewF->copyAttributesFrom(F);1315 NewF->removeRetAttrs(AttributeFuncs::typeIncompatible(1316 NewFT->getReturnType(), NewF->getAttributes().getRetAttrs()));1317 1318 BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", NewF);1319 if (F->isVarArg()) {1320 NewF->removeFnAttr("split-stack");1321 CallInst::Create(DFSanVarargWrapperFn,1322 IRBuilder<>(BB).CreateGlobalString(F->getName()), "", BB);1323 new UnreachableInst(*Ctx, BB);1324 } else {1325 auto ArgIt = pointer_iterator<Argument *>(NewF->arg_begin());1326 std::vector<Value *> Args(ArgIt, ArgIt + FT->getNumParams());1327 1328 CallInst *CI = CallInst::Create(F, Args, "", BB);1329 if (FT->getReturnType()->isVoidTy())1330 ReturnInst::Create(*Ctx, BB);1331 else1332 ReturnInst::Create(*Ctx, CI, BB);1333 }1334 1335 return NewF;1336}1337 1338// Initialize DataFlowSanitizer runtime functions and declare them in the module1339void DataFlowSanitizer::initializeRuntimeFunctions(Module &M) {1340 LLVMContext &C = M.getContext();1341 {1342 AttributeList AL;1343 AL = AL.addFnAttribute(C, Attribute::NoUnwind);1344 AL = AL.addFnAttribute(1345 C, Attribute::getWithMemoryEffects(C, MemoryEffects::readOnly()));1346 AL = AL.addRetAttribute(C, Attribute::ZExt);1347 DFSanUnionLoadFn =1348 Mod->getOrInsertFunction("__dfsan_union_load", DFSanUnionLoadFnTy, AL);1349 }1350 {1351 AttributeList AL;1352 AL = AL.addFnAttribute(C, Attribute::NoUnwind);1353 AL = AL.addFnAttribute(1354 C, Attribute::getWithMemoryEffects(C, MemoryEffects::readOnly()));1355 AL = AL.addRetAttribute(C, Attribute::ZExt);1356 DFSanLoadLabelAndOriginFn = Mod->getOrInsertFunction(1357 "__dfsan_load_label_and_origin", DFSanLoadLabelAndOriginFnTy, AL);1358 }1359 DFSanUnimplementedFn =1360 Mod->getOrInsertFunction("__dfsan_unimplemented", DFSanUnimplementedFnTy);1361 DFSanWrapperExternWeakNullFn = Mod->getOrInsertFunction(1362 "__dfsan_wrapper_extern_weak_null", DFSanWrapperExternWeakNullFnTy);1363 {1364 AttributeList AL;1365 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1366 AL = AL.addParamAttribute(M.getContext(), 1, Attribute::ZExt);1367 DFSanSetLabelFn =1368 Mod->getOrInsertFunction("__dfsan_set_label", DFSanSetLabelFnTy, AL);1369 }1370 DFSanNonzeroLabelFn =1371 Mod->getOrInsertFunction("__dfsan_nonzero_label", DFSanNonzeroLabelFnTy);1372 DFSanVarargWrapperFn = Mod->getOrInsertFunction("__dfsan_vararg_wrapper",1373 DFSanVarargWrapperFnTy);1374 {1375 AttributeList AL;1376 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1377 AL = AL.addRetAttribute(M.getContext(), Attribute::ZExt);1378 DFSanChainOriginFn = Mod->getOrInsertFunction("__dfsan_chain_origin",1379 DFSanChainOriginFnTy, AL);1380 }1381 {1382 AttributeList AL;1383 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1384 AL = AL.addParamAttribute(M.getContext(), 1, Attribute::ZExt);1385 AL = AL.addRetAttribute(M.getContext(), Attribute::ZExt);1386 DFSanChainOriginIfTaintedFn = Mod->getOrInsertFunction(1387 "__dfsan_chain_origin_if_tainted", DFSanChainOriginIfTaintedFnTy, AL);1388 }1389 DFSanMemOriginTransferFn = Mod->getOrInsertFunction(1390 "__dfsan_mem_origin_transfer", DFSanMemOriginTransferFnTy);1391 1392 DFSanMemShadowOriginTransferFn = Mod->getOrInsertFunction(1393 "__dfsan_mem_shadow_origin_transfer", DFSanMemShadowOriginTransferFnTy);1394 1395 DFSanMemShadowOriginConditionalExchangeFn =1396 Mod->getOrInsertFunction("__dfsan_mem_shadow_origin_conditional_exchange",1397 DFSanMemShadowOriginConditionalExchangeFnTy);1398 1399 {1400 AttributeList AL;1401 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1402 AL = AL.addParamAttribute(M.getContext(), 3, Attribute::ZExt);1403 DFSanMaybeStoreOriginFn = Mod->getOrInsertFunction(1404 "__dfsan_maybe_store_origin", DFSanMaybeStoreOriginFnTy, AL);1405 }1406 1407 DFSanRuntimeFunctions.insert(1408 DFSanUnionLoadFn.getCallee()->stripPointerCasts());1409 DFSanRuntimeFunctions.insert(1410 DFSanLoadLabelAndOriginFn.getCallee()->stripPointerCasts());1411 DFSanRuntimeFunctions.insert(1412 DFSanUnimplementedFn.getCallee()->stripPointerCasts());1413 DFSanRuntimeFunctions.insert(1414 DFSanWrapperExternWeakNullFn.getCallee()->stripPointerCasts());1415 DFSanRuntimeFunctions.insert(1416 DFSanSetLabelFn.getCallee()->stripPointerCasts());1417 DFSanRuntimeFunctions.insert(1418 DFSanNonzeroLabelFn.getCallee()->stripPointerCasts());1419 DFSanRuntimeFunctions.insert(1420 DFSanVarargWrapperFn.getCallee()->stripPointerCasts());1421 DFSanRuntimeFunctions.insert(1422 DFSanLoadCallbackFn.getCallee()->stripPointerCasts());1423 DFSanRuntimeFunctions.insert(1424 DFSanStoreCallbackFn.getCallee()->stripPointerCasts());1425 DFSanRuntimeFunctions.insert(1426 DFSanMemTransferCallbackFn.getCallee()->stripPointerCasts());1427 DFSanRuntimeFunctions.insert(1428 DFSanConditionalCallbackFn.getCallee()->stripPointerCasts());1429 DFSanRuntimeFunctions.insert(1430 DFSanConditionalCallbackOriginFn.getCallee()->stripPointerCasts());1431 DFSanRuntimeFunctions.insert(1432 DFSanReachesFunctionCallbackFn.getCallee()->stripPointerCasts());1433 DFSanRuntimeFunctions.insert(1434 DFSanReachesFunctionCallbackOriginFn.getCallee()->stripPointerCasts());1435 DFSanRuntimeFunctions.insert(1436 DFSanCmpCallbackFn.getCallee()->stripPointerCasts());1437 DFSanRuntimeFunctions.insert(1438 DFSanChainOriginFn.getCallee()->stripPointerCasts());1439 DFSanRuntimeFunctions.insert(1440 DFSanChainOriginIfTaintedFn.getCallee()->stripPointerCasts());1441 DFSanRuntimeFunctions.insert(1442 DFSanMemOriginTransferFn.getCallee()->stripPointerCasts());1443 DFSanRuntimeFunctions.insert(1444 DFSanMemShadowOriginTransferFn.getCallee()->stripPointerCasts());1445 DFSanRuntimeFunctions.insert(1446 DFSanMemShadowOriginConditionalExchangeFn.getCallee()1447 ->stripPointerCasts());1448 DFSanRuntimeFunctions.insert(1449 DFSanMaybeStoreOriginFn.getCallee()->stripPointerCasts());1450}1451 1452// Initializes event callback functions and declare them in the module1453void DataFlowSanitizer::initializeCallbackFunctions(Module &M) {1454 {1455 AttributeList AL;1456 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1457 DFSanLoadCallbackFn = Mod->getOrInsertFunction(1458 "__dfsan_load_callback", DFSanLoadStoreCallbackFnTy, AL);1459 }1460 {1461 AttributeList AL;1462 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1463 DFSanStoreCallbackFn = Mod->getOrInsertFunction(1464 "__dfsan_store_callback", DFSanLoadStoreCallbackFnTy, AL);1465 }1466 DFSanMemTransferCallbackFn = Mod->getOrInsertFunction(1467 "__dfsan_mem_transfer_callback", DFSanMemTransferCallbackFnTy);1468 {1469 AttributeList AL;1470 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1471 DFSanCmpCallbackFn = Mod->getOrInsertFunction("__dfsan_cmp_callback",1472 DFSanCmpCallbackFnTy, AL);1473 }1474 {1475 AttributeList AL;1476 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1477 DFSanConditionalCallbackFn = Mod->getOrInsertFunction(1478 "__dfsan_conditional_callback", DFSanConditionalCallbackFnTy, AL);1479 }1480 {1481 AttributeList AL;1482 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1483 DFSanConditionalCallbackOriginFn =1484 Mod->getOrInsertFunction("__dfsan_conditional_callback_origin",1485 DFSanConditionalCallbackOriginFnTy, AL);1486 }1487 {1488 AttributeList AL;1489 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1490 DFSanReachesFunctionCallbackFn =1491 Mod->getOrInsertFunction("__dfsan_reaches_function_callback",1492 DFSanReachesFunctionCallbackFnTy, AL);1493 }1494 {1495 AttributeList AL;1496 AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt);1497 DFSanReachesFunctionCallbackOriginFn =1498 Mod->getOrInsertFunction("__dfsan_reaches_function_callback_origin",1499 DFSanReachesFunctionCallbackOriginFnTy, AL);1500 }1501}1502 1503bool DataFlowSanitizer::runImpl(1504 Module &M, llvm::function_ref<TargetLibraryInfo &(Function &)> GetTLI) {1505 initializeModule(M);1506 1507 if (ABIList.isIn(M, "skip"))1508 return false;1509 1510 const unsigned InitialGlobalSize = M.global_size();1511 const unsigned InitialModuleSize = M.size();1512 1513 bool Changed = false;1514 1515 auto GetOrInsertGlobal = [this, &Changed](StringRef Name,1516 Type *Ty) -> Constant * {1517 GlobalVariable *G = Mod->getOrInsertGlobal(Name, Ty);1518 Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel;1519 G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel);1520 return G;1521 };1522 1523 // These globals must be kept in sync with the ones in dfsan.cpp.1524 ArgTLS =1525 GetOrInsertGlobal("__dfsan_arg_tls",1526 ArrayType::get(Type::getInt64Ty(*Ctx), ArgTLSSize / 8));1527 RetvalTLS = GetOrInsertGlobal(1528 "__dfsan_retval_tls",1529 ArrayType::get(Type::getInt64Ty(*Ctx), RetvalTLSSize / 8));1530 ArgOriginTLSTy = ArrayType::get(OriginTy, NumOfElementsInArgOrgTLS);1531 ArgOriginTLS = GetOrInsertGlobal("__dfsan_arg_origin_tls", ArgOriginTLSTy);1532 RetvalOriginTLS = GetOrInsertGlobal("__dfsan_retval_origin_tls", OriginTy);1533 1534 (void)Mod->getOrInsertGlobal("__dfsan_track_origins", OriginTy, [&] {1535 Changed = true;1536 return new GlobalVariable(1537 M, OriginTy, true, GlobalValue::WeakODRLinkage,1538 ConstantInt::getSigned(OriginTy,1539 shouldTrackOrigins() ? ClTrackOrigins : 0),1540 "__dfsan_track_origins");1541 });1542 1543 initializeCallbackFunctions(M);1544 initializeRuntimeFunctions(M);1545 1546 std::vector<Function *> FnsToInstrument;1547 SmallPtrSet<Function *, 2> FnsWithNativeABI;1548 SmallPtrSet<Function *, 2> FnsWithForceZeroLabel;1549 SmallPtrSet<Constant *, 1> PersonalityFns;1550 for (Function &F : M)1551 if (!F.isIntrinsic() && !DFSanRuntimeFunctions.contains(&F) &&1552 !LibAtomicFunction(F) &&1553 !F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation)) {1554 FnsToInstrument.push_back(&F);1555 if (F.hasPersonalityFn())1556 PersonalityFns.insert(F.getPersonalityFn()->stripPointerCasts());1557 }1558 1559 if (ClIgnorePersonalityRoutine) {1560 for (auto *C : PersonalityFns) {1561 assert(isa<Function>(C) && "Personality routine is not a function!");1562 Function *F = cast<Function>(C);1563 if (!isInstrumented(F))1564 llvm::erase(FnsToInstrument, F);1565 }1566 }1567 1568 // Give function aliases prefixes when necessary, and build wrappers where the1569 // instrumentedness is inconsistent.1570 for (GlobalAlias &GA : llvm::make_early_inc_range(M.aliases())) {1571 // Don't stop on weak. We assume people aren't playing games with the1572 // instrumentedness of overridden weak aliases.1573 auto *F = dyn_cast<Function>(GA.getAliaseeObject());1574 if (!F)1575 continue;1576 1577 bool GAInst = isInstrumented(&GA), FInst = isInstrumented(F);1578 if (GAInst && FInst) {1579 addGlobalNameSuffix(&GA);1580 } else if (GAInst != FInst) {1581 // Non-instrumented alias of an instrumented function, or vice versa.1582 // Replace the alias with a native-ABI wrapper of the aliasee. The pass1583 // below will take care of instrumenting it.1584 Function *NewF =1585 buildWrapperFunction(F, "", GA.getLinkage(), F->getFunctionType());1586 GA.replaceAllUsesWith(NewF);1587 NewF->takeName(&GA);1588 GA.eraseFromParent();1589 FnsToInstrument.push_back(NewF);1590 }1591 }1592 1593 // TODO: This could be more precise.1594 ReadOnlyNoneAttrs.addAttribute(Attribute::Memory);1595 1596 // First, change the ABI of every function in the module. ABI-listed1597 // functions keep their original ABI and get a wrapper function.1598 for (std::vector<Function *>::iterator FI = FnsToInstrument.begin(),1599 FE = FnsToInstrument.end();1600 FI != FE; ++FI) {1601 Function &F = **FI;1602 FunctionType *FT = F.getFunctionType();1603 1604 bool IsZeroArgsVoidRet = (FT->getNumParams() == 0 && !FT->isVarArg() &&1605 FT->getReturnType()->isVoidTy());1606 1607 if (isInstrumented(&F)) {1608 if (isForceZeroLabels(&F))1609 FnsWithForceZeroLabel.insert(&F);1610 1611 // Instrumented functions get a '.dfsan' suffix. This allows us to more1612 // easily identify cases of mismatching ABIs. This naming scheme is1613 // mangling-compatible (see Itanium ABI), using a vendor-specific suffix.1614 addGlobalNameSuffix(&F);1615 } else if (!IsZeroArgsVoidRet || getWrapperKind(&F) == WK_Custom) {1616 // Build a wrapper function for F. The wrapper simply calls F, and is1617 // added to FnsToInstrument so that any instrumentation according to its1618 // WrapperKind is done in the second pass below.1619 1620 // If the function being wrapped has local linkage, then preserve the1621 // function's linkage in the wrapper function.1622 GlobalValue::LinkageTypes WrapperLinkage =1623 F.hasLocalLinkage() ? F.getLinkage()1624 : GlobalValue::LinkOnceODRLinkage;1625 1626 Function *NewF = buildWrapperFunction(1627 &F,1628 (shouldTrackOrigins() ? std::string("dfso$") : std::string("dfsw$")) +1629 std::string(F.getName()),1630 WrapperLinkage, FT);1631 NewF->removeFnAttrs(ReadOnlyNoneAttrs);1632 1633 // Extern weak functions can sometimes be null at execution time.1634 // Code will sometimes check if an extern weak function is null.1635 // This could look something like:1636 // declare extern_weak i8 @my_func(i8)1637 // br i1 icmp ne (i8 (i8)* @my_func, i8 (i8)* null), label %use_my_func,1638 // label %avoid_my_func1639 // The @"dfsw$my_func" wrapper is never null, so if we replace this use1640 // in the comparison, the icmp will simplify to false and we have1641 // accidentally optimized away a null check that is necessary.1642 // This can lead to a crash when the null extern_weak my_func is called.1643 //1644 // To prevent (the most common pattern of) this problem,1645 // do not replace uses in comparisons with the wrapper.1646 // We definitely want to replace uses in call instructions.1647 // Other uses (e.g. store the function address somewhere) might be1648 // called or compared or both - this case may not be handled correctly.1649 // We will default to replacing with wrapper in cases we are unsure.1650 auto IsNotCmpUse = [](Use &U) -> bool {1651 User *Usr = U.getUser();1652 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Usr)) {1653 // This is the most common case for icmp ne null1654 if (CE->getOpcode() == Instruction::ICmp) {1655 return false;1656 }1657 }1658 if (Instruction *I = dyn_cast<Instruction>(Usr)) {1659 if (I->getOpcode() == Instruction::ICmp) {1660 return false;1661 }1662 }1663 return true;1664 };1665 F.replaceUsesWithIf(NewF, IsNotCmpUse);1666 1667 UnwrappedFnMap[NewF] = &F;1668 *FI = NewF;1669 1670 if (!F.isDeclaration()) {1671 // This function is probably defining an interposition of an1672 // uninstrumented function and hence needs to keep the original ABI.1673 // But any functions it may call need to use the instrumented ABI, so1674 // we instrument it in a mode which preserves the original ABI.1675 FnsWithNativeABI.insert(&F);1676 1677 // This code needs to rebuild the iterators, as they may be invalidated1678 // by the push_back, taking care that the new range does not include1679 // any functions added by this code.1680 size_t N = FI - FnsToInstrument.begin(),1681 Count = FE - FnsToInstrument.begin();1682 FnsToInstrument.push_back(&F);1683 FI = FnsToInstrument.begin() + N;1684 FE = FnsToInstrument.begin() + Count;1685 }1686 // Hopefully, nobody will try to indirectly call a vararg1687 // function... yet.1688 } else if (FT->isVarArg()) {1689 UnwrappedFnMap[&F] = &F;1690 *FI = nullptr;1691 }1692 }1693 1694 for (Function *F : FnsToInstrument) {1695 if (!F || F->isDeclaration())1696 continue;1697 1698 removeUnreachableBlocks(*F);1699 1700 DFSanFunction DFSF(*this, F, FnsWithNativeABI.count(F),1701 FnsWithForceZeroLabel.count(F), GetTLI(*F));1702 1703 if (ClReachesFunctionCallbacks) {1704 // Add callback for arguments reaching this function.1705 for (auto &FArg : F->args()) {1706 Instruction *Next = &F->getEntryBlock().front();1707 Value *FArgShadow = DFSF.getShadow(&FArg);1708 if (isZeroShadow(FArgShadow))1709 continue;1710 if (Instruction *FArgShadowInst = dyn_cast<Instruction>(FArgShadow)) {1711 Next = FArgShadowInst->getNextNode();1712 }1713 if (shouldTrackOrigins()) {1714 if (Instruction *Origin =1715 dyn_cast<Instruction>(DFSF.getOrigin(&FArg))) {1716 // Ensure IRB insertion point is after loads for shadow and origin.1717 Instruction *OriginNext = Origin->getNextNode();1718 if (Next->comesBefore(OriginNext)) {1719 Next = OriginNext;1720 }1721 }1722 }1723 IRBuilder<> IRB(Next);1724 DFSF.addReachesFunctionCallbacksIfEnabled(IRB, *Next, &FArg);1725 }1726 }1727 1728 // DFSanVisitor may create new basic blocks, which confuses df_iterator.1729 // Build a copy of the list before iterating over it.1730 SmallVector<BasicBlock *, 4> BBList(depth_first(&F->getEntryBlock()));1731 1732 for (BasicBlock *BB : BBList) {1733 Instruction *Inst = &BB->front();1734 while (true) {1735 // DFSanVisitor may split the current basic block, changing the current1736 // instruction's next pointer and moving the next instruction to the1737 // tail block from which we should continue.1738 Instruction *Next = Inst->getNextNode();1739 // DFSanVisitor may delete Inst, so keep track of whether it was a1740 // terminator.1741 bool IsTerminator = Inst->isTerminator();1742 if (!DFSF.SkipInsts.count(Inst))1743 DFSanVisitor(DFSF).visit(Inst);1744 if (IsTerminator)1745 break;1746 Inst = Next;1747 }1748 }1749 1750 // We will not necessarily be able to compute the shadow for every phi node1751 // until we have visited every block. Therefore, the code that handles phi1752 // nodes adds them to the PHIFixups list so that they can be properly1753 // handled here.1754 for (DFSanFunction::PHIFixupElement &P : DFSF.PHIFixups) {1755 for (unsigned Val = 0, N = P.Phi->getNumIncomingValues(); Val != N;1756 ++Val) {1757 P.ShadowPhi->setIncomingValue(1758 Val, DFSF.getShadow(P.Phi->getIncomingValue(Val)));1759 if (P.OriginPhi)1760 P.OriginPhi->setIncomingValue(1761 Val, DFSF.getOrigin(P.Phi->getIncomingValue(Val)));1762 }1763 }1764 1765 // -dfsan-debug-nonzero-labels will split the CFG in all kinds of crazy1766 // places (i.e. instructions in basic blocks we haven't even begun visiting1767 // yet). To make our life easier, do this work in a pass after the main1768 // instrumentation.1769 if (ClDebugNonzeroLabels) {1770 for (Value *V : DFSF.NonZeroChecks) {1771 BasicBlock::iterator Pos;1772 if (Instruction *I = dyn_cast<Instruction>(V))1773 Pos = std::next(I->getIterator());1774 else1775 Pos = DFSF.F->getEntryBlock().begin();1776 while (isa<PHINode>(Pos) || isa<AllocaInst>(Pos))1777 Pos = std::next(Pos->getIterator());1778 IRBuilder<> IRB(Pos->getParent(), Pos);1779 Value *PrimitiveShadow = DFSF.collapseToPrimitiveShadow(V, Pos);1780 Value *Ne =1781 IRB.CreateICmpNE(PrimitiveShadow, DFSF.DFS.ZeroPrimitiveShadow);1782 BranchInst *BI = cast<BranchInst>(SplitBlockAndInsertIfThen(1783 Ne, Pos, /*Unreachable=*/false, ColdCallWeights));1784 IRBuilder<> ThenIRB(BI);1785 ThenIRB.CreateCall(DFSF.DFS.DFSanNonzeroLabelFn, {});1786 }1787 }1788 }1789 1790 return Changed || !FnsToInstrument.empty() ||1791 M.global_size() != InitialGlobalSize || M.size() != InitialModuleSize;1792}1793 1794Value *DFSanFunction::getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB) {1795 return IRB.CreatePtrAdd(DFS.ArgTLS, ConstantInt::get(DFS.IntptrTy, ArgOffset),1796 "_dfsarg");1797}1798 1799Value *DFSanFunction::getRetvalTLS(Type *T, IRBuilder<> &IRB) {1800 return IRB.CreatePointerCast(DFS.RetvalTLS, PointerType::get(*DFS.Ctx, 0),1801 "_dfsret");1802}1803 1804Value *DFSanFunction::getRetvalOriginTLS() { return DFS.RetvalOriginTLS; }1805 1806Value *DFSanFunction::getArgOriginTLS(unsigned ArgNo, IRBuilder<> &IRB) {1807 return IRB.CreateConstInBoundsGEP2_64(DFS.ArgOriginTLSTy, DFS.ArgOriginTLS, 0,1808 ArgNo, "_dfsarg_o");1809}1810 1811Value *DFSanFunction::getOrigin(Value *V) {1812 assert(DFS.shouldTrackOrigins());1813 if (!isa<Argument>(V) && !isa<Instruction>(V))1814 return DFS.ZeroOrigin;1815 Value *&Origin = ValOriginMap[V];1816 if (!Origin) {1817 if (Argument *A = dyn_cast<Argument>(V)) {1818 if (IsNativeABI)1819 return DFS.ZeroOrigin;1820 if (A->getArgNo() < DFS.NumOfElementsInArgOrgTLS) {1821 Instruction *ArgOriginTLSPos = &*F->getEntryBlock().begin();1822 IRBuilder<> IRB(ArgOriginTLSPos);1823 Value *ArgOriginPtr = getArgOriginTLS(A->getArgNo(), IRB);1824 Origin = IRB.CreateLoad(DFS.OriginTy, ArgOriginPtr);1825 } else {1826 // Overflow1827 Origin = DFS.ZeroOrigin;1828 }1829 } else {1830 Origin = DFS.ZeroOrigin;1831 }1832 }1833 return Origin;1834}1835 1836void DFSanFunction::setOrigin(Instruction *I, Value *Origin) {1837 if (!DFS.shouldTrackOrigins())1838 return;1839 assert(!ValOriginMap.count(I));1840 assert(Origin->getType() == DFS.OriginTy);1841 ValOriginMap[I] = Origin;1842}1843 1844Value *DFSanFunction::getShadowForTLSArgument(Argument *A) {1845 unsigned ArgOffset = 0;1846 const DataLayout &DL = F->getDataLayout();1847 for (auto &FArg : F->args()) {1848 if (!FArg.getType()->isSized()) {1849 if (A == &FArg)1850 break;1851 continue;1852 }1853 1854 unsigned Size = DL.getTypeAllocSize(DFS.getShadowTy(&FArg));1855 if (A != &FArg) {1856 ArgOffset += alignTo(Size, ShadowTLSAlignment);1857 if (ArgOffset > ArgTLSSize)1858 break; // ArgTLS overflows, uses a zero shadow.1859 continue;1860 }1861 1862 if (ArgOffset + Size > ArgTLSSize)1863 break; // ArgTLS overflows, uses a zero shadow.1864 1865 Instruction *ArgTLSPos = &*F->getEntryBlock().begin();1866 IRBuilder<> IRB(ArgTLSPos);1867 Value *ArgShadowPtr = getArgTLS(FArg.getType(), ArgOffset, IRB);1868 return IRB.CreateAlignedLoad(DFS.getShadowTy(&FArg), ArgShadowPtr,1869 ShadowTLSAlignment);1870 }1871 1872 return DFS.getZeroShadow(A);1873}1874 1875Value *DFSanFunction::getShadow(Value *V) {1876 if (!isa<Argument>(V) && !isa<Instruction>(V))1877 return DFS.getZeroShadow(V);1878 if (IsForceZeroLabels)1879 return DFS.getZeroShadow(V);1880 Value *&Shadow = ValShadowMap[V];1881 if (!Shadow) {1882 if (Argument *A = dyn_cast<Argument>(V)) {1883 if (IsNativeABI)1884 return DFS.getZeroShadow(V);1885 Shadow = getShadowForTLSArgument(A);1886 NonZeroChecks.push_back(Shadow);1887 } else {1888 Shadow = DFS.getZeroShadow(V);1889 }1890 }1891 return Shadow;1892}1893 1894void DFSanFunction::setShadow(Instruction *I, Value *Shadow) {1895 assert(!ValShadowMap.count(I));1896 ValShadowMap[I] = Shadow;1897}1898 1899/// Compute the integer shadow offset that corresponds to a given1900/// application address.1901///1902/// Offset = (Addr & ~AndMask) ^ XorMask1903Value *DataFlowSanitizer::getShadowOffset(Value *Addr, IRBuilder<> &IRB) {1904 assert(Addr != RetvalTLS && "Reinstrumenting?");1905 Value *OffsetLong = IRB.CreatePointerCast(Addr, IntptrTy);1906 1907 uint64_t AndMask = MapParams->AndMask;1908 if (AndMask)1909 OffsetLong =1910 IRB.CreateAnd(OffsetLong, ConstantInt::get(IntptrTy, ~AndMask));1911 1912 uint64_t XorMask = MapParams->XorMask;1913 if (XorMask)1914 OffsetLong = IRB.CreateXor(OffsetLong, ConstantInt::get(IntptrTy, XorMask));1915 return OffsetLong;1916}1917 1918std::pair<Value *, Value *>1919DataFlowSanitizer::getShadowOriginAddress(Value *Addr, Align InstAlignment,1920 BasicBlock::iterator Pos) {1921 // Returns ((Addr & shadow_mask) + origin_base - shadow_base) & ~4UL1922 IRBuilder<> IRB(Pos->getParent(), Pos);1923 Value *ShadowOffset = getShadowOffset(Addr, IRB);1924 Value *ShadowLong = ShadowOffset;1925 uint64_t ShadowBase = MapParams->ShadowBase;1926 if (ShadowBase != 0) {1927 ShadowLong =1928 IRB.CreateAdd(ShadowLong, ConstantInt::get(IntptrTy, ShadowBase));1929 }1930 Value *ShadowPtr = IRB.CreateIntToPtr(ShadowLong, PointerType::get(*Ctx, 0));1931 Value *OriginPtr = nullptr;1932 if (shouldTrackOrigins()) {1933 Value *OriginLong = ShadowOffset;1934 uint64_t OriginBase = MapParams->OriginBase;1935 if (OriginBase != 0)1936 OriginLong =1937 IRB.CreateAdd(OriginLong, ConstantInt::get(IntptrTy, OriginBase));1938 const Align Alignment = llvm::assumeAligned(InstAlignment.value());1939 // When alignment is >= 4, Addr must be aligned to 4, otherwise it is UB.1940 // So Mask is unnecessary.1941 if (Alignment < MinOriginAlignment) {1942 uint64_t Mask = MinOriginAlignment.value() - 1;1943 OriginLong = IRB.CreateAnd(OriginLong, ConstantInt::get(IntptrTy, ~Mask));1944 }1945 OriginPtr = IRB.CreateIntToPtr(OriginLong, OriginPtrTy);1946 }1947 return std::make_pair(ShadowPtr, OriginPtr);1948}1949 1950Value *DataFlowSanitizer::getShadowAddress(Value *Addr,1951 BasicBlock::iterator Pos,1952 Value *ShadowOffset) {1953 IRBuilder<> IRB(Pos->getParent(), Pos);1954 return IRB.CreateIntToPtr(ShadowOffset, PrimitiveShadowPtrTy);1955}1956 1957Value *DataFlowSanitizer::getShadowAddress(Value *Addr,1958 BasicBlock::iterator Pos) {1959 IRBuilder<> IRB(Pos->getParent(), Pos);1960 Value *ShadowAddr = getShadowOffset(Addr, IRB);1961 uint64_t ShadowBase = MapParams->ShadowBase;1962 if (ShadowBase != 0)1963 ShadowAddr =1964 IRB.CreateAdd(ShadowAddr, ConstantInt::get(IntptrTy, ShadowBase));1965 return getShadowAddress(Addr, Pos, ShadowAddr);1966}1967 1968Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2,1969 BasicBlock::iterator Pos) {1970 Value *PrimitiveValue = combineShadows(V1, V2, Pos);1971 return expandFromPrimitiveShadow(T, PrimitiveValue, Pos);1972}1973 1974// Generates IR to compute the union of the two given shadows, inserting it1975// before Pos. The combined value is with primitive type.1976Value *DFSanFunction::combineShadows(Value *V1, Value *V2,1977 BasicBlock::iterator Pos) {1978 if (DFS.isZeroShadow(V1))1979 return collapseToPrimitiveShadow(V2, Pos);1980 if (DFS.isZeroShadow(V2))1981 return collapseToPrimitiveShadow(V1, Pos);1982 if (V1 == V2)1983 return collapseToPrimitiveShadow(V1, Pos);1984 1985 auto V1Elems = ShadowElements.find(V1);1986 auto V2Elems = ShadowElements.find(V2);1987 if (V1Elems != ShadowElements.end() && V2Elems != ShadowElements.end()) {1988 if (llvm::includes(V1Elems->second, V2Elems->second)) {1989 return collapseToPrimitiveShadow(V1, Pos);1990 }1991 if (llvm::includes(V2Elems->second, V1Elems->second)) {1992 return collapseToPrimitiveShadow(V2, Pos);1993 }1994 } else if (V1Elems != ShadowElements.end()) {1995 if (V1Elems->second.count(V2))1996 return collapseToPrimitiveShadow(V1, Pos);1997 } else if (V2Elems != ShadowElements.end()) {1998 if (V2Elems->second.count(V1))1999 return collapseToPrimitiveShadow(V2, Pos);2000 }2001 2002 auto Key = std::make_pair(V1, V2);2003 if (V1 > V2)2004 std::swap(Key.first, Key.second);2005 CachedShadow &CCS = CachedShadows[Key];2006 if (CCS.Block && DT.dominates(CCS.Block, Pos->getParent()))2007 return CCS.Shadow;2008 2009 // Converts inputs shadows to shadows with primitive types.2010 Value *PV1 = collapseToPrimitiveShadow(V1, Pos);2011 Value *PV2 = collapseToPrimitiveShadow(V2, Pos);2012 2013 IRBuilder<> IRB(Pos->getParent(), Pos);2014 CCS.Block = Pos->getParent();2015 CCS.Shadow = IRB.CreateOr(PV1, PV2);2016 2017 std::set<Value *> UnionElems;2018 if (V1Elems != ShadowElements.end()) {2019 UnionElems = V1Elems->second;2020 } else {2021 UnionElems.insert(V1);2022 }2023 if (V2Elems != ShadowElements.end()) {2024 UnionElems.insert(V2Elems->second.begin(), V2Elems->second.end());2025 } else {2026 UnionElems.insert(V2);2027 }2028 ShadowElements[CCS.Shadow] = std::move(UnionElems);2029 2030 return CCS.Shadow;2031}2032 2033// A convenience function which folds the shadows of each of the operands2034// of the provided instruction Inst, inserting the IR before Inst. Returns2035// the computed union Value.2036Value *DFSanFunction::combineOperandShadows(Instruction *Inst) {2037 if (Inst->getNumOperands() == 0)2038 return DFS.getZeroShadow(Inst);2039 2040 Value *Shadow = getShadow(Inst->getOperand(0));2041 for (unsigned I = 1, N = Inst->getNumOperands(); I < N; ++I)2042 Shadow = combineShadows(Shadow, getShadow(Inst->getOperand(I)),2043 Inst->getIterator());2044 2045 return expandFromPrimitiveShadow(Inst->getType(), Shadow,2046 Inst->getIterator());2047}2048 2049void DFSanVisitor::visitInstOperands(Instruction &I) {2050 Value *CombinedShadow = DFSF.combineOperandShadows(&I);2051 DFSF.setShadow(&I, CombinedShadow);2052 visitInstOperandOrigins(I);2053}2054 2055Value *DFSanFunction::combineOrigins(const std::vector<Value *> &Shadows,2056 const std::vector<Value *> &Origins,2057 BasicBlock::iterator Pos,2058 ConstantInt *Zero) {2059 assert(Shadows.size() == Origins.size());2060 size_t Size = Origins.size();2061 if (Size == 0)2062 return DFS.ZeroOrigin;2063 Value *Origin = nullptr;2064 if (!Zero)2065 Zero = DFS.ZeroPrimitiveShadow;2066 for (size_t I = 0; I != Size; ++I) {2067 Value *OpOrigin = Origins[I];2068 Constant *ConstOpOrigin = dyn_cast<Constant>(OpOrigin);2069 if (ConstOpOrigin && ConstOpOrigin->isNullValue())2070 continue;2071 if (!Origin) {2072 Origin = OpOrigin;2073 continue;2074 }2075 Value *OpShadow = Shadows[I];2076 Value *PrimitiveShadow = collapseToPrimitiveShadow(OpShadow, Pos);2077 IRBuilder<> IRB(Pos->getParent(), Pos);2078 Value *Cond = IRB.CreateICmpNE(PrimitiveShadow, Zero);2079 Origin = IRB.CreateSelect(Cond, OpOrigin, Origin);2080 }2081 return Origin ? Origin : DFS.ZeroOrigin;2082}2083 2084Value *DFSanFunction::combineOperandOrigins(Instruction *Inst) {2085 size_t Size = Inst->getNumOperands();2086 std::vector<Value *> Shadows(Size);2087 std::vector<Value *> Origins(Size);2088 for (unsigned I = 0; I != Size; ++I) {2089 Shadows[I] = getShadow(Inst->getOperand(I));2090 Origins[I] = getOrigin(Inst->getOperand(I));2091 }2092 return combineOrigins(Shadows, Origins, Inst->getIterator());2093}2094 2095void DFSanVisitor::visitInstOperandOrigins(Instruction &I) {2096 if (!DFSF.DFS.shouldTrackOrigins())2097 return;2098 Value *CombinedOrigin = DFSF.combineOperandOrigins(&I);2099 DFSF.setOrigin(&I, CombinedOrigin);2100}2101 2102Align DFSanFunction::getShadowAlign(Align InstAlignment) {2103 const Align Alignment = ClPreserveAlignment ? InstAlignment : Align(1);2104 return Align(Alignment.value() * DFS.ShadowWidthBytes);2105}2106 2107Align DFSanFunction::getOriginAlign(Align InstAlignment) {2108 const Align Alignment = llvm::assumeAligned(InstAlignment.value());2109 return Align(std::max(MinOriginAlignment, Alignment));2110}2111 2112bool DFSanFunction::isLookupTableConstant(Value *P) {2113 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(P->stripPointerCasts()))2114 if (GV->isConstant() && GV->hasName())2115 return DFS.CombineTaintLookupTableNames.count(GV->getName());2116 2117 return false;2118}2119 2120bool DFSanFunction::useCallbackLoadLabelAndOrigin(uint64_t Size,2121 Align InstAlignment) {2122 // When enabling tracking load instructions, we always use2123 // __dfsan_load_label_and_origin to reduce code size.2124 if (ClTrackOrigins == 2)2125 return true;2126 2127 assert(Size != 0);2128 // * if Size == 1, it is sufficient to load its origin aligned at 4.2129 // * if Size == 2, we assume most cases Addr % 2 == 0, so it is sufficient to2130 // load its origin aligned at 4. If not, although origins may be lost, it2131 // should not happen very often.2132 // * if align >= 4, Addr must be aligned to 4, otherwise it is UB. When2133 // Size % 4 == 0, it is more efficient to load origins without callbacks.2134 // * Otherwise we use __dfsan_load_label_and_origin.2135 // This should ensure that common cases run efficiently.2136 if (Size <= 2)2137 return false;2138 2139 const Align Alignment = llvm::assumeAligned(InstAlignment.value());2140 return Alignment < MinOriginAlignment || !DFS.hasLoadSizeForFastPath(Size);2141}2142 2143Value *DataFlowSanitizer::loadNextOrigin(BasicBlock::iterator Pos,2144 Align OriginAlign,2145 Value **OriginAddr) {2146 IRBuilder<> IRB(Pos->getParent(), Pos);2147 *OriginAddr =2148 IRB.CreateGEP(OriginTy, *OriginAddr, ConstantInt::get(IntptrTy, 1));2149 return IRB.CreateAlignedLoad(OriginTy, *OriginAddr, OriginAlign);2150}2151 2152std::pair<Value *, Value *> DFSanFunction::loadShadowFast(2153 Value *ShadowAddr, Value *OriginAddr, uint64_t Size, Align ShadowAlign,2154 Align OriginAlign, Value *FirstOrigin, BasicBlock::iterator Pos) {2155 const bool ShouldTrackOrigins = DFS.shouldTrackOrigins();2156 const uint64_t ShadowSize = Size * DFS.ShadowWidthBytes;2157 2158 assert(Size >= 4 && "Not large enough load size for fast path!");2159 2160 // Used for origin tracking.2161 std::vector<Value *> Shadows;2162 std::vector<Value *> Origins;2163 2164 // Load instructions in LLVM can have arbitrary byte sizes (e.g., 3, 12, 20)2165 // but this function is only used in a subset of cases that make it possible2166 // to optimize the instrumentation.2167 //2168 // Specifically, when the shadow size in bytes (i.e., loaded bytes x shadow2169 // per byte) is either:2170 // - a multiple of 8 (common)2171 // - equal to 4 (only for load32)2172 //2173 // For the second case, we can fit the wide shadow in a 32-bit integer. In all2174 // other cases, we use a 64-bit integer to hold the wide shadow.2175 Type *WideShadowTy =2176 ShadowSize == 4 ? Type::getInt32Ty(*DFS.Ctx) : Type::getInt64Ty(*DFS.Ctx);2177 2178 IRBuilder<> IRB(Pos->getParent(), Pos);2179 Value *CombinedWideShadow =2180 IRB.CreateAlignedLoad(WideShadowTy, ShadowAddr, ShadowAlign);2181 2182 unsigned WideShadowBitWidth = WideShadowTy->getIntegerBitWidth();2183 const uint64_t BytesPerWideShadow = WideShadowBitWidth / DFS.ShadowWidthBits;2184 2185 auto AppendWideShadowAndOrigin = [&](Value *WideShadow, Value *Origin) {2186 if (BytesPerWideShadow > 4) {2187 assert(BytesPerWideShadow == 8);2188 // The wide shadow relates to two origin pointers: one for the first four2189 // application bytes, and one for the latest four. We use a left shift to2190 // get just the shadow bytes that correspond to the first origin pointer,2191 // and then the entire shadow for the second origin pointer (which will be2192 // chosen by combineOrigins() iff the least-significant half of the wide2193 // shadow was empty but the other half was not).2194 Value *WideShadowLo =2195 F->getParent()->getDataLayout().isLittleEndian()2196 ? IRB.CreateShl(2197 WideShadow,2198 ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2))2199 : IRB.CreateAnd(2200 WideShadow,2201 ConstantInt::get(WideShadowTy,2202 (1 - (1 << (WideShadowBitWidth / 2)))2203 << (WideShadowBitWidth / 2)));2204 Shadows.push_back(WideShadow);2205 Origins.push_back(DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr));2206 2207 Shadows.push_back(WideShadowLo);2208 Origins.push_back(Origin);2209 } else {2210 Shadows.push_back(WideShadow);2211 Origins.push_back(Origin);2212 }2213 };2214 2215 if (ShouldTrackOrigins)2216 AppendWideShadowAndOrigin(CombinedWideShadow, FirstOrigin);2217 2218 // First OR all the WideShadows (i.e., 64bit or 32bit shadow chunks) linearly;2219 // then OR individual shadows within the combined WideShadow by binary ORing.2220 // This is fewer instructions than ORing shadows individually, since it2221 // needs logN shift/or instructions (N being the bytes of the combined wide2222 // shadow).2223 for (uint64_t ByteOfs = BytesPerWideShadow; ByteOfs < Size;2224 ByteOfs += BytesPerWideShadow) {2225 ShadowAddr = IRB.CreateGEP(WideShadowTy, ShadowAddr,2226 ConstantInt::get(DFS.IntptrTy, 1));2227 Value *NextWideShadow =2228 IRB.CreateAlignedLoad(WideShadowTy, ShadowAddr, ShadowAlign);2229 CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, NextWideShadow);2230 if (ShouldTrackOrigins) {2231 Value *NextOrigin = DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr);2232 AppendWideShadowAndOrigin(NextWideShadow, NextOrigin);2233 }2234 }2235 for (unsigned Width = WideShadowBitWidth / 2; Width >= DFS.ShadowWidthBits;2236 Width >>= 1) {2237 Value *ShrShadow = IRB.CreateLShr(CombinedWideShadow, Width);2238 CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, ShrShadow);2239 }2240 return {IRB.CreateTrunc(CombinedWideShadow, DFS.PrimitiveShadowTy),2241 ShouldTrackOrigins2242 ? combineOrigins(Shadows, Origins, Pos,2243 ConstantInt::getSigned(IRB.getInt64Ty(), 0))2244 : DFS.ZeroOrigin};2245}2246 2247std::pair<Value *, Value *> DFSanFunction::loadShadowOriginSansLoadTracking(2248 Value *Addr, uint64_t Size, Align InstAlignment, BasicBlock::iterator Pos) {2249 const bool ShouldTrackOrigins = DFS.shouldTrackOrigins();2250 2251 // Non-escaped loads.2252 if (AllocaInst *AI = dyn_cast<AllocaInst>(Addr)) {2253 const auto SI = AllocaShadowMap.find(AI);2254 if (SI != AllocaShadowMap.end()) {2255 IRBuilder<> IRB(Pos->getParent(), Pos);2256 Value *ShadowLI = IRB.CreateLoad(DFS.PrimitiveShadowTy, SI->second);2257 const auto OI = AllocaOriginMap.find(AI);2258 assert(!ShouldTrackOrigins || OI != AllocaOriginMap.end());2259 return {ShadowLI, ShouldTrackOrigins2260 ? IRB.CreateLoad(DFS.OriginTy, OI->second)2261 : nullptr};2262 }2263 }2264 2265 // Load from constant addresses.2266 SmallVector<const Value *, 2> Objs;2267 getUnderlyingObjects(Addr, Objs);2268 bool AllConstants = true;2269 for (const Value *Obj : Objs) {2270 if (isa<Function>(Obj) || isa<BlockAddress>(Obj))2271 continue;2272 if (isa<GlobalVariable>(Obj) && cast<GlobalVariable>(Obj)->isConstant())2273 continue;2274 2275 AllConstants = false;2276 break;2277 }2278 if (AllConstants)2279 return {DFS.ZeroPrimitiveShadow,2280 ShouldTrackOrigins ? DFS.ZeroOrigin : nullptr};2281 2282 if (Size == 0)2283 return {DFS.ZeroPrimitiveShadow,2284 ShouldTrackOrigins ? DFS.ZeroOrigin : nullptr};2285 2286 // Use callback to load if this is not an optimizable case for origin2287 // tracking.2288 if (ShouldTrackOrigins &&2289 useCallbackLoadLabelAndOrigin(Size, InstAlignment)) {2290 IRBuilder<> IRB(Pos->getParent(), Pos);2291 CallInst *Call =2292 IRB.CreateCall(DFS.DFSanLoadLabelAndOriginFn,2293 {Addr, ConstantInt::get(DFS.IntptrTy, Size)});2294 Call->addRetAttr(Attribute::ZExt);2295 return {IRB.CreateTrunc(IRB.CreateLShr(Call, DFS.OriginWidthBits),2296 DFS.PrimitiveShadowTy),2297 IRB.CreateTrunc(Call, DFS.OriginTy)};2298 }2299 2300 // Other cases that support loading shadows or origins in a fast way.2301 Value *ShadowAddr, *OriginAddr;2302 std::tie(ShadowAddr, OriginAddr) =2303 DFS.getShadowOriginAddress(Addr, InstAlignment, Pos);2304 2305 const Align ShadowAlign = getShadowAlign(InstAlignment);2306 const Align OriginAlign = getOriginAlign(InstAlignment);2307 Value *Origin = nullptr;2308 if (ShouldTrackOrigins) {2309 IRBuilder<> IRB(Pos->getParent(), Pos);2310 Origin = IRB.CreateAlignedLoad(DFS.OriginTy, OriginAddr, OriginAlign);2311 }2312 2313 // When the byte size is small enough, we can load the shadow directly with2314 // just a few instructions.2315 switch (Size) {2316 case 1: {2317 LoadInst *LI = new LoadInst(DFS.PrimitiveShadowTy, ShadowAddr, "", Pos);2318 LI->setAlignment(ShadowAlign);2319 return {LI, Origin};2320 }2321 case 2: {2322 IRBuilder<> IRB(Pos->getParent(), Pos);2323 Value *ShadowAddr1 = IRB.CreateGEP(DFS.PrimitiveShadowTy, ShadowAddr,2324 ConstantInt::get(DFS.IntptrTy, 1));2325 Value *Load =2326 IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr, ShadowAlign);2327 Value *Load1 =2328 IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr1, ShadowAlign);2329 return {combineShadows(Load, Load1, Pos), Origin};2330 }2331 }2332 bool HasSizeForFastPath = DFS.hasLoadSizeForFastPath(Size);2333 2334 if (HasSizeForFastPath)2335 return loadShadowFast(ShadowAddr, OriginAddr, Size, ShadowAlign,2336 OriginAlign, Origin, Pos);2337 2338 IRBuilder<> IRB(Pos->getParent(), Pos);2339 CallInst *FallbackCall = IRB.CreateCall(2340 DFS.DFSanUnionLoadFn, {ShadowAddr, ConstantInt::get(DFS.IntptrTy, Size)});2341 FallbackCall->addRetAttr(Attribute::ZExt);2342 return {FallbackCall, Origin};2343}2344 2345std::pair<Value *, Value *>2346DFSanFunction::loadShadowOrigin(Value *Addr, uint64_t Size, Align InstAlignment,2347 BasicBlock::iterator Pos) {2348 Value *PrimitiveShadow, *Origin;2349 std::tie(PrimitiveShadow, Origin) =2350 loadShadowOriginSansLoadTracking(Addr, Size, InstAlignment, Pos);2351 if (DFS.shouldTrackOrigins()) {2352 if (ClTrackOrigins == 2) {2353 IRBuilder<> IRB(Pos->getParent(), Pos);2354 auto *ConstantShadow = dyn_cast<Constant>(PrimitiveShadow);2355 if (!ConstantShadow || !ConstantShadow->isZeroValue())2356 Origin = updateOriginIfTainted(PrimitiveShadow, Origin, IRB);2357 }2358 }2359 return {PrimitiveShadow, Origin};2360}2361 2362static AtomicOrdering addAcquireOrdering(AtomicOrdering AO) {2363 switch (AO) {2364 case AtomicOrdering::NotAtomic:2365 return AtomicOrdering::NotAtomic;2366 case AtomicOrdering::Unordered:2367 case AtomicOrdering::Monotonic:2368 case AtomicOrdering::Acquire:2369 return AtomicOrdering::Acquire;2370 case AtomicOrdering::Release:2371 case AtomicOrdering::AcquireRelease:2372 return AtomicOrdering::AcquireRelease;2373 case AtomicOrdering::SequentiallyConsistent:2374 return AtomicOrdering::SequentiallyConsistent;2375 }2376 llvm_unreachable("Unknown ordering");2377}2378 2379Value *StripPointerGEPsAndCasts(Value *V) {2380 if (!V->getType()->isPointerTy())2381 return V;2382 2383 // DFSan pass should be running on valid IR, but we'll2384 // keep a seen set to ensure there are no issues.2385 SmallPtrSet<const Value *, 4> Visited;2386 Visited.insert(V);2387 do {2388 if (auto *GEP = dyn_cast<GEPOperator>(V)) {2389 V = GEP->getPointerOperand();2390 } else if (Operator::getOpcode(V) == Instruction::BitCast) {2391 V = cast<Operator>(V)->getOperand(0);2392 if (!V->getType()->isPointerTy())2393 return V;2394 } else if (isa<GlobalAlias>(V)) {2395 V = cast<GlobalAlias>(V)->getAliasee();2396 }2397 } while (Visited.insert(V).second);2398 2399 return V;2400}2401 2402void DFSanVisitor::visitLoadInst(LoadInst &LI) {2403 auto &DL = LI.getDataLayout();2404 uint64_t Size = DL.getTypeStoreSize(LI.getType());2405 if (Size == 0) {2406 DFSF.setShadow(&LI, DFSF.DFS.getZeroShadow(&LI));2407 DFSF.setOrigin(&LI, DFSF.DFS.ZeroOrigin);2408 return;2409 }2410 2411 // When an application load is atomic, increase atomic ordering between2412 // atomic application loads and stores to ensure happen-before order; load2413 // shadow data after application data; store zero shadow data before2414 // application data. This ensure shadow loads return either labels of the2415 // initial application data or zeros.2416 if (LI.isAtomic())2417 LI.setOrdering(addAcquireOrdering(LI.getOrdering()));2418 2419 BasicBlock::iterator AfterLi = std::next(LI.getIterator());2420 BasicBlock::iterator Pos = LI.getIterator();2421 if (LI.isAtomic())2422 Pos = std::next(Pos);2423 2424 std::vector<Value *> Shadows;2425 std::vector<Value *> Origins;2426 Value *PrimitiveShadow, *Origin;2427 std::tie(PrimitiveShadow, Origin) =2428 DFSF.loadShadowOrigin(LI.getPointerOperand(), Size, LI.getAlign(), Pos);2429 const bool ShouldTrackOrigins = DFSF.DFS.shouldTrackOrigins();2430 if (ShouldTrackOrigins) {2431 Shadows.push_back(PrimitiveShadow);2432 Origins.push_back(Origin);2433 }2434 if (ClCombinePointerLabelsOnLoad ||2435 DFSF.isLookupTableConstant(2436 StripPointerGEPsAndCasts(LI.getPointerOperand()))) {2437 Value *PtrShadow = DFSF.getShadow(LI.getPointerOperand());2438 PrimitiveShadow = DFSF.combineShadows(PrimitiveShadow, PtrShadow, Pos);2439 if (ShouldTrackOrigins) {2440 Shadows.push_back(PtrShadow);2441 Origins.push_back(DFSF.getOrigin(LI.getPointerOperand()));2442 }2443 }2444 if (!DFSF.DFS.isZeroShadow(PrimitiveShadow))2445 DFSF.NonZeroChecks.push_back(PrimitiveShadow);2446 2447 Value *Shadow =2448 DFSF.expandFromPrimitiveShadow(LI.getType(), PrimitiveShadow, Pos);2449 DFSF.setShadow(&LI, Shadow);2450 2451 if (ShouldTrackOrigins) {2452 DFSF.setOrigin(&LI, DFSF.combineOrigins(Shadows, Origins, Pos));2453 }2454 2455 if (ClEventCallbacks) {2456 IRBuilder<> IRB(Pos->getParent(), Pos);2457 Value *Addr = LI.getPointerOperand();2458 CallInst *CI =2459 IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {PrimitiveShadow, Addr});2460 CI->addParamAttr(0, Attribute::ZExt);2461 }2462 2463 IRBuilder<> IRB(AfterLi->getParent(), AfterLi);2464 DFSF.addReachesFunctionCallbacksIfEnabled(IRB, LI, &LI);2465}2466 2467Value *DFSanFunction::updateOriginIfTainted(Value *Shadow, Value *Origin,2468 IRBuilder<> &IRB) {2469 assert(DFS.shouldTrackOrigins());2470 return IRB.CreateCall(DFS.DFSanChainOriginIfTaintedFn, {Shadow, Origin});2471}2472 2473Value *DFSanFunction::updateOrigin(Value *V, IRBuilder<> &IRB) {2474 if (!DFS.shouldTrackOrigins())2475 return V;2476 return IRB.CreateCall(DFS.DFSanChainOriginFn, V);2477}2478 2479Value *DFSanFunction::originToIntptr(IRBuilder<> &IRB, Value *Origin) {2480 const unsigned OriginSize = DataFlowSanitizer::OriginWidthBytes;2481 const DataLayout &DL = F->getDataLayout();2482 unsigned IntptrSize = DL.getTypeStoreSize(DFS.IntptrTy);2483 if (IntptrSize == OriginSize)2484 return Origin;2485 assert(IntptrSize == OriginSize * 2);2486 Origin = IRB.CreateIntCast(Origin, DFS.IntptrTy, /* isSigned */ false);2487 return IRB.CreateOr(Origin, IRB.CreateShl(Origin, OriginSize * 8));2488}2489 2490void DFSanFunction::paintOrigin(IRBuilder<> &IRB, Value *Origin,2491 Value *StoreOriginAddr,2492 uint64_t StoreOriginSize, Align Alignment) {2493 const unsigned OriginSize = DataFlowSanitizer::OriginWidthBytes;2494 const DataLayout &DL = F->getDataLayout();2495 const Align IntptrAlignment = DL.getABITypeAlign(DFS.IntptrTy);2496 unsigned IntptrSize = DL.getTypeStoreSize(DFS.IntptrTy);2497 assert(IntptrAlignment >= MinOriginAlignment);2498 assert(IntptrSize >= OriginSize);2499 2500 unsigned Ofs = 0;2501 Align CurrentAlignment = Alignment;2502 if (Alignment >= IntptrAlignment && IntptrSize > OriginSize) {2503 Value *IntptrOrigin = originToIntptr(IRB, Origin);2504 Value *IntptrStoreOriginPtr =2505 IRB.CreatePointerCast(StoreOriginAddr, PointerType::get(*DFS.Ctx, 0));2506 for (unsigned I = 0; I < StoreOriginSize / IntptrSize; ++I) {2507 Value *Ptr =2508 I ? IRB.CreateConstGEP1_32(DFS.IntptrTy, IntptrStoreOriginPtr, I)2509 : IntptrStoreOriginPtr;2510 IRB.CreateAlignedStore(IntptrOrigin, Ptr, CurrentAlignment);2511 Ofs += IntptrSize / OriginSize;2512 CurrentAlignment = IntptrAlignment;2513 }2514 }2515 2516 for (unsigned I = Ofs; I < (StoreOriginSize + OriginSize - 1) / OriginSize;2517 ++I) {2518 Value *GEP = I ? IRB.CreateConstGEP1_32(DFS.OriginTy, StoreOriginAddr, I)2519 : StoreOriginAddr;2520 IRB.CreateAlignedStore(Origin, GEP, CurrentAlignment);2521 CurrentAlignment = MinOriginAlignment;2522 }2523}2524 2525Value *DFSanFunction::convertToBool(Value *V, IRBuilder<> &IRB,2526 const Twine &Name) {2527 Type *VTy = V->getType();2528 assert(VTy->isIntegerTy());2529 if (VTy->getIntegerBitWidth() == 1)2530 // Just converting a bool to a bool, so do nothing.2531 return V;2532 return IRB.CreateICmpNE(V, ConstantInt::get(VTy, 0), Name);2533}2534 2535void DFSanFunction::storeOrigin(BasicBlock::iterator Pos, Value *Addr,2536 uint64_t Size, Value *Shadow, Value *Origin,2537 Value *StoreOriginAddr, Align InstAlignment) {2538 // Do not write origins for zero shadows because we do not trace origins for2539 // untainted sinks.2540 const Align OriginAlignment = getOriginAlign(InstAlignment);2541 Value *CollapsedShadow = collapseToPrimitiveShadow(Shadow, Pos);2542 IRBuilder<> IRB(Pos->getParent(), Pos);2543 if (auto *ConstantShadow = dyn_cast<Constant>(CollapsedShadow)) {2544 if (!ConstantShadow->isZeroValue())2545 paintOrigin(IRB, updateOrigin(Origin, IRB), StoreOriginAddr, Size,2546 OriginAlignment);2547 return;2548 }2549 2550 if (shouldInstrumentWithCall()) {2551 IRB.CreateCall(2552 DFS.DFSanMaybeStoreOriginFn,2553 {CollapsedShadow, Addr, ConstantInt::get(DFS.IntptrTy, Size), Origin});2554 } else {2555 Value *Cmp = convertToBool(CollapsedShadow, IRB, "_dfscmp");2556 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);2557 Instruction *CheckTerm = SplitBlockAndInsertIfThen(2558 Cmp, &*IRB.GetInsertPoint(), false, DFS.OriginStoreWeights, &DTU);2559 IRBuilder<> IRBNew(CheckTerm);2560 paintOrigin(IRBNew, updateOrigin(Origin, IRBNew), StoreOriginAddr, Size,2561 OriginAlignment);2562 ++NumOriginStores;2563 }2564}2565 2566void DFSanFunction::storeZeroPrimitiveShadow(Value *Addr, uint64_t Size,2567 Align ShadowAlign,2568 BasicBlock::iterator Pos) {2569 IRBuilder<> IRB(Pos->getParent(), Pos);2570 IntegerType *ShadowTy =2571 IntegerType::get(*DFS.Ctx, Size * DFS.ShadowWidthBits);2572 Value *ExtZeroShadow = ConstantInt::get(ShadowTy, 0);2573 Value *ShadowAddr = DFS.getShadowAddress(Addr, Pos);2574 IRB.CreateAlignedStore(ExtZeroShadow, ShadowAddr, ShadowAlign);2575 // Do not write origins for 0 shadows because we do not trace origins for2576 // untainted sinks.2577}2578 2579void DFSanFunction::storePrimitiveShadowOrigin(Value *Addr, uint64_t Size,2580 Align InstAlignment,2581 Value *PrimitiveShadow,2582 Value *Origin,2583 BasicBlock::iterator Pos) {2584 const bool ShouldTrackOrigins = DFS.shouldTrackOrigins() && Origin;2585 2586 if (AllocaInst *AI = dyn_cast<AllocaInst>(Addr)) {2587 const auto SI = AllocaShadowMap.find(AI);2588 if (SI != AllocaShadowMap.end()) {2589 IRBuilder<> IRB(Pos->getParent(), Pos);2590 IRB.CreateStore(PrimitiveShadow, SI->second);2591 2592 // Do not write origins for 0 shadows because we do not trace origins for2593 // untainted sinks.2594 if (ShouldTrackOrigins && !DFS.isZeroShadow(PrimitiveShadow)) {2595 const auto OI = AllocaOriginMap.find(AI);2596 assert(OI != AllocaOriginMap.end() && Origin);2597 IRB.CreateStore(Origin, OI->second);2598 }2599 return;2600 }2601 }2602 2603 const Align ShadowAlign = getShadowAlign(InstAlignment);2604 if (DFS.isZeroShadow(PrimitiveShadow)) {2605 storeZeroPrimitiveShadow(Addr, Size, ShadowAlign, Pos);2606 return;2607 }2608 2609 IRBuilder<> IRB(Pos->getParent(), Pos);2610 Value *ShadowAddr, *OriginAddr;2611 std::tie(ShadowAddr, OriginAddr) =2612 DFS.getShadowOriginAddress(Addr, InstAlignment, Pos);2613 2614 const unsigned ShadowVecSize = 8;2615 assert(ShadowVecSize * DFS.ShadowWidthBits <= 128 &&2616 "Shadow vector is too large!");2617 2618 uint64_t Offset = 0;2619 uint64_t LeftSize = Size;2620 if (LeftSize >= ShadowVecSize) {2621 auto *ShadowVecTy =2622 FixedVectorType::get(DFS.PrimitiveShadowTy, ShadowVecSize);2623 Value *ShadowVec = PoisonValue::get(ShadowVecTy);2624 for (unsigned I = 0; I != ShadowVecSize; ++I) {2625 ShadowVec = IRB.CreateInsertElement(2626 ShadowVec, PrimitiveShadow,2627 ConstantInt::get(Type::getInt32Ty(*DFS.Ctx), I));2628 }2629 do {2630 Value *CurShadowVecAddr =2631 IRB.CreateConstGEP1_32(ShadowVecTy, ShadowAddr, Offset);2632 IRB.CreateAlignedStore(ShadowVec, CurShadowVecAddr, ShadowAlign);2633 LeftSize -= ShadowVecSize;2634 ++Offset;2635 } while (LeftSize >= ShadowVecSize);2636 Offset *= ShadowVecSize;2637 }2638 while (LeftSize > 0) {2639 Value *CurShadowAddr =2640 IRB.CreateConstGEP1_32(DFS.PrimitiveShadowTy, ShadowAddr, Offset);2641 IRB.CreateAlignedStore(PrimitiveShadow, CurShadowAddr, ShadowAlign);2642 --LeftSize;2643 ++Offset;2644 }2645 2646 if (ShouldTrackOrigins) {2647 storeOrigin(Pos, Addr, Size, PrimitiveShadow, Origin, OriginAddr,2648 InstAlignment);2649 }2650}2651 2652static AtomicOrdering addReleaseOrdering(AtomicOrdering AO) {2653 switch (AO) {2654 case AtomicOrdering::NotAtomic:2655 return AtomicOrdering::NotAtomic;2656 case AtomicOrdering::Unordered:2657 case AtomicOrdering::Monotonic:2658 case AtomicOrdering::Release:2659 return AtomicOrdering::Release;2660 case AtomicOrdering::Acquire:2661 case AtomicOrdering::AcquireRelease:2662 return AtomicOrdering::AcquireRelease;2663 case AtomicOrdering::SequentiallyConsistent:2664 return AtomicOrdering::SequentiallyConsistent;2665 }2666 llvm_unreachable("Unknown ordering");2667}2668 2669void DFSanVisitor::visitStoreInst(StoreInst &SI) {2670 auto &DL = SI.getDataLayout();2671 Value *Val = SI.getValueOperand();2672 uint64_t Size = DL.getTypeStoreSize(Val->getType());2673 if (Size == 0)2674 return;2675 2676 // When an application store is atomic, increase atomic ordering between2677 // atomic application loads and stores to ensure happen-before order; load2678 // shadow data after application data; store zero shadow data before2679 // application data. This ensure shadow loads return either labels of the2680 // initial application data or zeros.2681 if (SI.isAtomic())2682 SI.setOrdering(addReleaseOrdering(SI.getOrdering()));2683 2684 const bool ShouldTrackOrigins =2685 DFSF.DFS.shouldTrackOrigins() && !SI.isAtomic();2686 std::vector<Value *> Shadows;2687 std::vector<Value *> Origins;2688 2689 Value *Shadow =2690 SI.isAtomic() ? DFSF.DFS.getZeroShadow(Val) : DFSF.getShadow(Val);2691 2692 if (ShouldTrackOrigins) {2693 Shadows.push_back(Shadow);2694 Origins.push_back(DFSF.getOrigin(Val));2695 }2696 2697 Value *PrimitiveShadow;2698 if (ClCombinePointerLabelsOnStore) {2699 Value *PtrShadow = DFSF.getShadow(SI.getPointerOperand());2700 if (ShouldTrackOrigins) {2701 Shadows.push_back(PtrShadow);2702 Origins.push_back(DFSF.getOrigin(SI.getPointerOperand()));2703 }2704 PrimitiveShadow = DFSF.combineShadows(Shadow, PtrShadow, SI.getIterator());2705 } else {2706 PrimitiveShadow = DFSF.collapseToPrimitiveShadow(Shadow, SI.getIterator());2707 }2708 Value *Origin = nullptr;2709 if (ShouldTrackOrigins)2710 Origin = DFSF.combineOrigins(Shadows, Origins, SI.getIterator());2711 DFSF.storePrimitiveShadowOrigin(SI.getPointerOperand(), Size, SI.getAlign(),2712 PrimitiveShadow, Origin, SI.getIterator());2713 if (ClEventCallbacks) {2714 IRBuilder<> IRB(&SI);2715 Value *Addr = SI.getPointerOperand();2716 CallInst *CI =2717 IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {PrimitiveShadow, Addr});2718 CI->addParamAttr(0, Attribute::ZExt);2719 }2720}2721 2722void DFSanVisitor::visitCASOrRMW(Align InstAlignment, Instruction &I) {2723 assert(isa<AtomicRMWInst>(I) || isa<AtomicCmpXchgInst>(I));2724 2725 Value *Val = I.getOperand(1);2726 const auto &DL = I.getDataLayout();2727 uint64_t Size = DL.getTypeStoreSize(Val->getType());2728 if (Size == 0)2729 return;2730 2731 // Conservatively set data at stored addresses and return with zero shadow to2732 // prevent shadow data races.2733 IRBuilder<> IRB(&I);2734 Value *Addr = I.getOperand(0);2735 const Align ShadowAlign = DFSF.getShadowAlign(InstAlignment);2736 DFSF.storeZeroPrimitiveShadow(Addr, Size, ShadowAlign, I.getIterator());2737 DFSF.setShadow(&I, DFSF.DFS.getZeroShadow(&I));2738 DFSF.setOrigin(&I, DFSF.DFS.ZeroOrigin);2739}2740 2741void DFSanVisitor::visitAtomicRMWInst(AtomicRMWInst &I) {2742 visitCASOrRMW(I.getAlign(), I);2743 // TODO: The ordering change follows MSan. It is possible not to change2744 // ordering because we always set and use 0 shadows.2745 I.setOrdering(addReleaseOrdering(I.getOrdering()));2746}2747 2748void DFSanVisitor::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {2749 visitCASOrRMW(I.getAlign(), I);2750 // TODO: The ordering change follows MSan. It is possible not to change2751 // ordering because we always set and use 0 shadows.2752 I.setSuccessOrdering(addReleaseOrdering(I.getSuccessOrdering()));2753}2754 2755void DFSanVisitor::visitUnaryOperator(UnaryOperator &UO) {2756 visitInstOperands(UO);2757}2758 2759void DFSanVisitor::visitBinaryOperator(BinaryOperator &BO) {2760 visitInstOperands(BO);2761}2762 2763void DFSanVisitor::visitBitCastInst(BitCastInst &BCI) {2764 // Special case: if this is the bitcast (there is exactly 1 allowed) between2765 // a musttail call and a ret, don't instrument. New instructions are not2766 // allowed after a musttail call.2767 if (auto *CI = dyn_cast<CallInst>(BCI.getOperand(0)))2768 if (CI->isMustTailCall())2769 return;2770 visitInstOperands(BCI);2771}2772 2773void DFSanVisitor::visitCastInst(CastInst &CI) { visitInstOperands(CI); }2774 2775void DFSanVisitor::visitCmpInst(CmpInst &CI) {2776 visitInstOperands(CI);2777 if (ClEventCallbacks) {2778 IRBuilder<> IRB(&CI);2779 Value *CombinedShadow = DFSF.getShadow(&CI);2780 CallInst *CallI =2781 IRB.CreateCall(DFSF.DFS.DFSanCmpCallbackFn, CombinedShadow);2782 CallI->addParamAttr(0, Attribute::ZExt);2783 }2784}2785 2786void DFSanVisitor::visitLandingPadInst(LandingPadInst &LPI) {2787 // We do not need to track data through LandingPadInst.2788 //2789 // For the C++ exceptions, if a value is thrown, this value will be stored2790 // in a memory location provided by __cxa_allocate_exception(...) (on the2791 // throw side) or __cxa_begin_catch(...) (on the catch side).2792 // This memory will have a shadow, so with the loads and stores we will be2793 // able to propagate labels on data thrown through exceptions, without any2794 // special handling of the LandingPadInst.2795 //2796 // The second element in the pair result of the LandingPadInst is a2797 // register value, but it is for a type ID and should never be tainted.2798 DFSF.setShadow(&LPI, DFSF.DFS.getZeroShadow(&LPI));2799 DFSF.setOrigin(&LPI, DFSF.DFS.ZeroOrigin);2800}2801 2802void DFSanVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) {2803 if (ClCombineOffsetLabelsOnGEP ||2804 DFSF.isLookupTableConstant(2805 StripPointerGEPsAndCasts(GEPI.getPointerOperand()))) {2806 visitInstOperands(GEPI);2807 return;2808 }2809 2810 // Only propagate shadow/origin of base pointer value but ignore those of2811 // offset operands.2812 Value *BasePointer = GEPI.getPointerOperand();2813 DFSF.setShadow(&GEPI, DFSF.getShadow(BasePointer));2814 if (DFSF.DFS.shouldTrackOrigins())2815 DFSF.setOrigin(&GEPI, DFSF.getOrigin(BasePointer));2816}2817 2818void DFSanVisitor::visitExtractElementInst(ExtractElementInst &I) {2819 visitInstOperands(I);2820}2821 2822void DFSanVisitor::visitInsertElementInst(InsertElementInst &I) {2823 visitInstOperands(I);2824}2825 2826void DFSanVisitor::visitShuffleVectorInst(ShuffleVectorInst &I) {2827 visitInstOperands(I);2828}2829 2830void DFSanVisitor::visitExtractValueInst(ExtractValueInst &I) {2831 IRBuilder<> IRB(&I);2832 Value *Agg = I.getAggregateOperand();2833 Value *AggShadow = DFSF.getShadow(Agg);2834 Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices());2835 DFSF.setShadow(&I, ResShadow);2836 visitInstOperandOrigins(I);2837}2838 2839void DFSanVisitor::visitInsertValueInst(InsertValueInst &I) {2840 IRBuilder<> IRB(&I);2841 Value *AggShadow = DFSF.getShadow(I.getAggregateOperand());2842 Value *InsShadow = DFSF.getShadow(I.getInsertedValueOperand());2843 Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices());2844 DFSF.setShadow(&I, Res);2845 visitInstOperandOrigins(I);2846}2847 2848void DFSanVisitor::visitAllocaInst(AllocaInst &I) {2849 bool AllLoadsStores = true;2850 for (User *U : I.users()) {2851 if (isa<LoadInst>(U))2852 continue;2853 2854 if (StoreInst *SI = dyn_cast<StoreInst>(U)) {2855 if (SI->getPointerOperand() == &I)2856 continue;2857 }2858 2859 AllLoadsStores = false;2860 break;2861 }2862 if (AllLoadsStores) {2863 IRBuilder<> IRB(&I);2864 DFSF.AllocaShadowMap[&I] = IRB.CreateAlloca(DFSF.DFS.PrimitiveShadowTy);2865 if (DFSF.DFS.shouldTrackOrigins()) {2866 DFSF.AllocaOriginMap[&I] =2867 IRB.CreateAlloca(DFSF.DFS.OriginTy, nullptr, "_dfsa");2868 }2869 }2870 DFSF.setShadow(&I, DFSF.DFS.ZeroPrimitiveShadow);2871 DFSF.setOrigin(&I, DFSF.DFS.ZeroOrigin);2872}2873 2874void DFSanVisitor::visitSelectInst(SelectInst &I) {2875 Value *CondShadow = DFSF.getShadow(I.getCondition());2876 Value *TrueShadow = DFSF.getShadow(I.getTrueValue());2877 Value *FalseShadow = DFSF.getShadow(I.getFalseValue());2878 Value *ShadowSel = nullptr;2879 const bool ShouldTrackOrigins = DFSF.DFS.shouldTrackOrigins();2880 std::vector<Value *> Shadows;2881 std::vector<Value *> Origins;2882 Value *TrueOrigin =2883 ShouldTrackOrigins ? DFSF.getOrigin(I.getTrueValue()) : nullptr;2884 Value *FalseOrigin =2885 ShouldTrackOrigins ? DFSF.getOrigin(I.getFalseValue()) : nullptr;2886 2887 DFSF.addConditionalCallbacksIfEnabled(I, I.getCondition());2888 2889 if (isa<VectorType>(I.getCondition()->getType())) {2890 ShadowSel = DFSF.combineShadowsThenConvert(I.getType(), TrueShadow,2891 FalseShadow, I.getIterator());2892 if (ShouldTrackOrigins) {2893 Shadows.push_back(TrueShadow);2894 Shadows.push_back(FalseShadow);2895 Origins.push_back(TrueOrigin);2896 Origins.push_back(FalseOrigin);2897 }2898 } else {2899 if (TrueShadow == FalseShadow) {2900 ShadowSel = TrueShadow;2901 if (ShouldTrackOrigins) {2902 Shadows.push_back(TrueShadow);2903 Origins.push_back(TrueOrigin);2904 }2905 } else {2906 ShadowSel = SelectInst::Create(I.getCondition(), TrueShadow, FalseShadow,2907 "", I.getIterator());2908 if (ShouldTrackOrigins) {2909 Shadows.push_back(ShadowSel);2910 Origins.push_back(SelectInst::Create(I.getCondition(), TrueOrigin,2911 FalseOrigin, "", I.getIterator()));2912 }2913 }2914 }2915 DFSF.setShadow(&I, ClTrackSelectControlFlow ? DFSF.combineShadowsThenConvert(2916 I.getType(), CondShadow,2917 ShadowSel, I.getIterator())2918 : ShadowSel);2919 if (ShouldTrackOrigins) {2920 if (ClTrackSelectControlFlow) {2921 Shadows.push_back(CondShadow);2922 Origins.push_back(DFSF.getOrigin(I.getCondition()));2923 }2924 DFSF.setOrigin(&I, DFSF.combineOrigins(Shadows, Origins, I.getIterator()));2925 }2926}2927 2928void DFSanVisitor::visitMemSetInst(MemSetInst &I) {2929 IRBuilder<> IRB(&I);2930 Value *ValShadow = DFSF.getShadow(I.getValue());2931 Value *ValOrigin = DFSF.DFS.shouldTrackOrigins()2932 ? DFSF.getOrigin(I.getValue())2933 : DFSF.DFS.ZeroOrigin;2934 IRB.CreateCall(DFSF.DFS.DFSanSetLabelFn,2935 {ValShadow, ValOrigin, I.getDest(),2936 IRB.CreateZExtOrTrunc(I.getLength(), DFSF.DFS.IntptrTy)});2937}2938 2939void DFSanVisitor::visitMemTransferInst(MemTransferInst &I) {2940 IRBuilder<> IRB(&I);2941 2942 // CopyOrMoveOrigin transfers origins by refering to their shadows. So we2943 // need to move origins before moving shadows.2944 if (DFSF.DFS.shouldTrackOrigins()) {2945 IRB.CreateCall(2946 DFSF.DFS.DFSanMemOriginTransferFn,2947 {I.getArgOperand(0), I.getArgOperand(1),2948 IRB.CreateIntCast(I.getArgOperand(2), DFSF.DFS.IntptrTy, false)});2949 }2950 2951 Value *DestShadow = DFSF.DFS.getShadowAddress(I.getDest(), I.getIterator());2952 Value *SrcShadow = DFSF.DFS.getShadowAddress(I.getSource(), I.getIterator());2953 Value *LenShadow =2954 IRB.CreateMul(I.getLength(), ConstantInt::get(I.getLength()->getType(),2955 DFSF.DFS.ShadowWidthBytes));2956 auto *MTI = cast<MemTransferInst>(2957 IRB.CreateCall(I.getFunctionType(), I.getCalledOperand(),2958 {DestShadow, SrcShadow, LenShadow, I.getVolatileCst()}));2959 MTI->setDestAlignment(DFSF.getShadowAlign(I.getDestAlign().valueOrOne()));2960 MTI->setSourceAlignment(DFSF.getShadowAlign(I.getSourceAlign().valueOrOne()));2961 if (ClEventCallbacks) {2962 IRB.CreateCall(2963 DFSF.DFS.DFSanMemTransferCallbackFn,2964 {DestShadow, IRB.CreateZExtOrTrunc(I.getLength(), DFSF.DFS.IntptrTy)});2965 }2966}2967 2968void DFSanVisitor::visitBranchInst(BranchInst &BR) {2969 if (!BR.isConditional())2970 return;2971 2972 DFSF.addConditionalCallbacksIfEnabled(BR, BR.getCondition());2973}2974 2975void DFSanVisitor::visitSwitchInst(SwitchInst &SW) {2976 DFSF.addConditionalCallbacksIfEnabled(SW, SW.getCondition());2977}2978 2979static bool isAMustTailRetVal(Value *RetVal) {2980 // Tail call may have a bitcast between return.2981 if (auto *I = dyn_cast<BitCastInst>(RetVal)) {2982 RetVal = I->getOperand(0);2983 }2984 if (auto *I = dyn_cast<CallInst>(RetVal)) {2985 return I->isMustTailCall();2986 }2987 return false;2988}2989 2990void DFSanVisitor::visitReturnInst(ReturnInst &RI) {2991 if (!DFSF.IsNativeABI && RI.getReturnValue()) {2992 // Don't emit the instrumentation for musttail call returns.2993 if (isAMustTailRetVal(RI.getReturnValue()))2994 return;2995 2996 Value *S = DFSF.getShadow(RI.getReturnValue());2997 IRBuilder<> IRB(&RI);2998 Type *RT = DFSF.F->getFunctionType()->getReturnType();2999 unsigned Size = getDataLayout().getTypeAllocSize(DFSF.DFS.getShadowTy(RT));3000 if (Size <= RetvalTLSSize) {3001 // If the size overflows, stores nothing. At callsite, oversized return3002 // shadows are set to zero.3003 IRB.CreateAlignedStore(S, DFSF.getRetvalTLS(RT, IRB), ShadowTLSAlignment);3004 }3005 if (DFSF.DFS.shouldTrackOrigins()) {3006 Value *O = DFSF.getOrigin(RI.getReturnValue());3007 IRB.CreateStore(O, DFSF.getRetvalOriginTLS());3008 }3009 }3010}3011 3012void DFSanVisitor::addShadowArguments(Function &F, CallBase &CB,3013 std::vector<Value *> &Args,3014 IRBuilder<> &IRB) {3015 FunctionType *FT = F.getFunctionType();3016 3017 auto *I = CB.arg_begin();3018 3019 // Adds non-variable argument shadows.3020 for (unsigned N = FT->getNumParams(); N != 0; ++I, --N)3021 Args.push_back(3022 DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*I), CB.getIterator()));3023 3024 // Adds variable argument shadows.3025 if (FT->isVarArg()) {3026 auto *LabelVATy = ArrayType::get(DFSF.DFS.PrimitiveShadowTy,3027 CB.arg_size() - FT->getNumParams());3028 auto *LabelVAAlloca =3029 new AllocaInst(LabelVATy, getDataLayout().getAllocaAddrSpace(),3030 "labelva", DFSF.F->getEntryBlock().begin());3031 3032 for (unsigned N = 0; I != CB.arg_end(); ++I, ++N) {3033 auto *LabelVAPtr = IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, N);3034 IRB.CreateStore(3035 DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*I), CB.getIterator()),3036 LabelVAPtr);3037 }3038 3039 Args.push_back(IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, 0));3040 }3041 3042 // Adds the return value shadow.3043 if (!FT->getReturnType()->isVoidTy()) {3044 if (!DFSF.LabelReturnAlloca) {3045 DFSF.LabelReturnAlloca = new AllocaInst(3046 DFSF.DFS.PrimitiveShadowTy, getDataLayout().getAllocaAddrSpace(),3047 "labelreturn", DFSF.F->getEntryBlock().begin());3048 }3049 Args.push_back(DFSF.LabelReturnAlloca);3050 }3051}3052 3053void DFSanVisitor::addOriginArguments(Function &F, CallBase &CB,3054 std::vector<Value *> &Args,3055 IRBuilder<> &IRB) {3056 FunctionType *FT = F.getFunctionType();3057 3058 auto *I = CB.arg_begin();3059 3060 // Add non-variable argument origins.3061 for (unsigned N = FT->getNumParams(); N != 0; ++I, --N)3062 Args.push_back(DFSF.getOrigin(*I));3063 3064 // Add variable argument origins.3065 if (FT->isVarArg()) {3066 auto *OriginVATy =3067 ArrayType::get(DFSF.DFS.OriginTy, CB.arg_size() - FT->getNumParams());3068 auto *OriginVAAlloca =3069 new AllocaInst(OriginVATy, getDataLayout().getAllocaAddrSpace(),3070 "originva", DFSF.F->getEntryBlock().begin());3071 3072 for (unsigned N = 0; I != CB.arg_end(); ++I, ++N) {3073 auto *OriginVAPtr = IRB.CreateStructGEP(OriginVATy, OriginVAAlloca, N);3074 IRB.CreateStore(DFSF.getOrigin(*I), OriginVAPtr);3075 }3076 3077 Args.push_back(IRB.CreateStructGEP(OriginVATy, OriginVAAlloca, 0));3078 }3079 3080 // Add the return value origin.3081 if (!FT->getReturnType()->isVoidTy()) {3082 if (!DFSF.OriginReturnAlloca) {3083 DFSF.OriginReturnAlloca = new AllocaInst(3084 DFSF.DFS.OriginTy, getDataLayout().getAllocaAddrSpace(),3085 "originreturn", DFSF.F->getEntryBlock().begin());3086 }3087 Args.push_back(DFSF.OriginReturnAlloca);3088 }3089}3090 3091bool DFSanVisitor::visitWrappedCallBase(Function &F, CallBase &CB) {3092 IRBuilder<> IRB(&CB);3093 switch (DFSF.DFS.getWrapperKind(&F)) {3094 case DataFlowSanitizer::WK_Warning:3095 CB.setCalledFunction(&F);3096 IRB.CreateCall(DFSF.DFS.DFSanUnimplementedFn,3097 IRB.CreateGlobalString(F.getName()));3098 DFSF.DFS.buildExternWeakCheckIfNeeded(IRB, &F);3099 DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB));3100 DFSF.setOrigin(&CB, DFSF.DFS.ZeroOrigin);3101 return true;3102 case DataFlowSanitizer::WK_Discard:3103 CB.setCalledFunction(&F);3104 DFSF.DFS.buildExternWeakCheckIfNeeded(IRB, &F);3105 DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB));3106 DFSF.setOrigin(&CB, DFSF.DFS.ZeroOrigin);3107 return true;3108 case DataFlowSanitizer::WK_Functional:3109 CB.setCalledFunction(&F);3110 DFSF.DFS.buildExternWeakCheckIfNeeded(IRB, &F);3111 visitInstOperands(CB);3112 return true;3113 case DataFlowSanitizer::WK_Custom:3114 // Don't try to handle invokes of custom functions, it's too complicated.3115 // Instead, invoke the dfsw$ wrapper, which will in turn call the __dfsw_3116 // wrapper.3117 CallInst *CI = dyn_cast<CallInst>(&CB);3118 if (!CI)3119 return false;3120 3121 const bool ShouldTrackOrigins = DFSF.DFS.shouldTrackOrigins();3122 FunctionType *FT = F.getFunctionType();3123 TransformedFunction CustomFn = DFSF.DFS.getCustomFunctionType(FT);3124 std::string CustomFName = ShouldTrackOrigins ? "__dfso_" : "__dfsw_";3125 CustomFName += F.getName();3126 FunctionCallee CustomF = DFSF.DFS.Mod->getOrInsertFunction(3127 CustomFName, CustomFn.TransformedType);3128 if (Function *CustomFn = dyn_cast<Function>(CustomF.getCallee())) {3129 CustomFn->copyAttributesFrom(&F);3130 3131 // Custom functions returning non-void will write to the return label.3132 if (!FT->getReturnType()->isVoidTy()) {3133 CustomFn->removeFnAttrs(DFSF.DFS.ReadOnlyNoneAttrs);3134 }3135 }3136 3137 std::vector<Value *> Args;3138 3139 // Adds non-variable arguments.3140 auto *I = CB.arg_begin();3141 for (unsigned N = FT->getNumParams(); N != 0; ++I, --N) {3142 Args.push_back(*I);3143 }3144 3145 // Adds shadow arguments.3146 const unsigned ShadowArgStart = Args.size();3147 addShadowArguments(F, CB, Args, IRB);3148 3149 // Adds origin arguments.3150 const unsigned OriginArgStart = Args.size();3151 if (ShouldTrackOrigins)3152 addOriginArguments(F, CB, Args, IRB);3153 3154 // Adds variable arguments.3155 append_range(Args, drop_begin(CB.args(), FT->getNumParams()));3156 3157 CallInst *CustomCI = IRB.CreateCall(CustomF, Args);3158 CustomCI->setCallingConv(CI->getCallingConv());3159 CustomCI->setAttributes(transformFunctionAttributes(3160 CustomFn, CI->getContext(), CI->getAttributes()));3161 3162 // Update the parameter attributes of the custom call instruction to3163 // zero extend the shadow parameters. This is required for targets3164 // which consider PrimitiveShadowTy an illegal type.3165 for (unsigned N = 0; N < FT->getNumParams(); N++) {3166 const unsigned ArgNo = ShadowArgStart + N;3167 if (CustomCI->getArgOperand(ArgNo)->getType() ==3168 DFSF.DFS.PrimitiveShadowTy)3169 CustomCI->addParamAttr(ArgNo, Attribute::ZExt);3170 if (ShouldTrackOrigins) {3171 const unsigned OriginArgNo = OriginArgStart + N;3172 if (CustomCI->getArgOperand(OriginArgNo)->getType() ==3173 DFSF.DFS.OriginTy)3174 CustomCI->addParamAttr(OriginArgNo, Attribute::ZExt);3175 }3176 }3177 3178 // Loads the return value shadow and origin.3179 if (!FT->getReturnType()->isVoidTy()) {3180 LoadInst *LabelLoad =3181 IRB.CreateLoad(DFSF.DFS.PrimitiveShadowTy, DFSF.LabelReturnAlloca);3182 DFSF.setShadow(CustomCI,3183 DFSF.expandFromPrimitiveShadow(3184 FT->getReturnType(), LabelLoad, CB.getIterator()));3185 if (ShouldTrackOrigins) {3186 LoadInst *OriginLoad =3187 IRB.CreateLoad(DFSF.DFS.OriginTy, DFSF.OriginReturnAlloca);3188 DFSF.setOrigin(CustomCI, OriginLoad);3189 }3190 }3191 3192 CI->replaceAllUsesWith(CustomCI);3193 CI->eraseFromParent();3194 return true;3195 }3196 return false;3197}3198 3199Value *DFSanVisitor::makeAddAcquireOrderingTable(IRBuilder<> &IRB) {3200 constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1;3201 uint32_t OrderingTable[NumOrderings] = {};3202 3203 OrderingTable[(int)AtomicOrderingCABI::relaxed] =3204 OrderingTable[(int)AtomicOrderingCABI::acquire] =3205 OrderingTable[(int)AtomicOrderingCABI::consume] =3206 (int)AtomicOrderingCABI::acquire;3207 OrderingTable[(int)AtomicOrderingCABI::release] =3208 OrderingTable[(int)AtomicOrderingCABI::acq_rel] =3209 (int)AtomicOrderingCABI::acq_rel;3210 OrderingTable[(int)AtomicOrderingCABI::seq_cst] =3211 (int)AtomicOrderingCABI::seq_cst;3212 3213 return ConstantDataVector::get(IRB.getContext(), OrderingTable);3214}3215 3216void DFSanVisitor::visitLibAtomicLoad(CallBase &CB) {3217 // Since we use getNextNode here, we can't have CB terminate the BB.3218 assert(isa<CallInst>(CB));3219 3220 IRBuilder<> IRB(&CB);3221 Value *Size = CB.getArgOperand(0);3222 Value *SrcPtr = CB.getArgOperand(1);3223 Value *DstPtr = CB.getArgOperand(2);3224 Value *Ordering = CB.getArgOperand(3);3225 // Convert the call to have at least Acquire ordering to make sure3226 // the shadow operations aren't reordered before it.3227 Value *NewOrdering =3228 IRB.CreateExtractElement(makeAddAcquireOrderingTable(IRB), Ordering);3229 CB.setArgOperand(3, NewOrdering);3230 3231 IRBuilder<> NextIRB(CB.getNextNode());3232 NextIRB.SetCurrentDebugLocation(CB.getDebugLoc());3233 3234 // TODO: Support ClCombinePointerLabelsOnLoad3235 // TODO: Support ClEventCallbacks3236 3237 NextIRB.CreateCall(3238 DFSF.DFS.DFSanMemShadowOriginTransferFn,3239 {DstPtr, SrcPtr, NextIRB.CreateIntCast(Size, DFSF.DFS.IntptrTy, false)});3240}3241 3242Value *DFSanVisitor::makeAddReleaseOrderingTable(IRBuilder<> &IRB) {3243 constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1;3244 uint32_t OrderingTable[NumOrderings] = {};3245 3246 OrderingTable[(int)AtomicOrderingCABI::relaxed] =3247 OrderingTable[(int)AtomicOrderingCABI::release] =3248 (int)AtomicOrderingCABI::release;3249 OrderingTable[(int)AtomicOrderingCABI::consume] =3250 OrderingTable[(int)AtomicOrderingCABI::acquire] =3251 OrderingTable[(int)AtomicOrderingCABI::acq_rel] =3252 (int)AtomicOrderingCABI::acq_rel;3253 OrderingTable[(int)AtomicOrderingCABI::seq_cst] =3254 (int)AtomicOrderingCABI::seq_cst;3255 3256 return ConstantDataVector::get(IRB.getContext(), OrderingTable);3257}3258 3259void DFSanVisitor::visitLibAtomicStore(CallBase &CB) {3260 IRBuilder<> IRB(&CB);3261 Value *Size = CB.getArgOperand(0);3262 Value *SrcPtr = CB.getArgOperand(1);3263 Value *DstPtr = CB.getArgOperand(2);3264 Value *Ordering = CB.getArgOperand(3);3265 // Convert the call to have at least Release ordering to make sure3266 // the shadow operations aren't reordered after it.3267 Value *NewOrdering =3268 IRB.CreateExtractElement(makeAddReleaseOrderingTable(IRB), Ordering);3269 CB.setArgOperand(3, NewOrdering);3270 3271 // TODO: Support ClCombinePointerLabelsOnStore3272 // TODO: Support ClEventCallbacks3273 3274 IRB.CreateCall(3275 DFSF.DFS.DFSanMemShadowOriginTransferFn,3276 {DstPtr, SrcPtr, IRB.CreateIntCast(Size, DFSF.DFS.IntptrTy, false)});3277}3278 3279void DFSanVisitor::visitLibAtomicExchange(CallBase &CB) {3280 // void __atomic_exchange(size_t size, void *ptr, void *val, void *ret, int3281 // ordering)3282 IRBuilder<> IRB(&CB);3283 Value *Size = CB.getArgOperand(0);3284 Value *TargetPtr = CB.getArgOperand(1);3285 Value *SrcPtr = CB.getArgOperand(2);3286 Value *DstPtr = CB.getArgOperand(3);3287 3288 // This operation is not atomic for the shadow and origin memory.3289 // This could result in DFSan false positives or false negatives.3290 // For now we will assume these operations are rare, and3291 // the additional complexity to address this is not warrented.3292 3293 // Current Target to Dest3294 IRB.CreateCall(3295 DFSF.DFS.DFSanMemShadowOriginTransferFn,3296 {DstPtr, TargetPtr, IRB.CreateIntCast(Size, DFSF.DFS.IntptrTy, false)});3297 3298 // Current Src to Target (overriding)3299 IRB.CreateCall(3300 DFSF.DFS.DFSanMemShadowOriginTransferFn,3301 {TargetPtr, SrcPtr, IRB.CreateIntCast(Size, DFSF.DFS.IntptrTy, false)});3302}3303 3304void DFSanVisitor::visitLibAtomicCompareExchange(CallBase &CB) {3305 // bool __atomic_compare_exchange(size_t size, void *ptr, void *expected, void3306 // *desired, int success_order, int failure_order)3307 Value *Size = CB.getArgOperand(0);3308 Value *TargetPtr = CB.getArgOperand(1);3309 Value *ExpectedPtr = CB.getArgOperand(2);3310 Value *DesiredPtr = CB.getArgOperand(3);3311 3312 // This operation is not atomic for the shadow and origin memory.3313 // This could result in DFSan false positives or false negatives.3314 // For now we will assume these operations are rare, and3315 // the additional complexity to address this is not warrented.3316 3317 IRBuilder<> NextIRB(CB.getNextNode());3318 NextIRB.SetCurrentDebugLocation(CB.getDebugLoc());3319 3320 DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB));3321 3322 // If original call returned true, copy Desired to Target.3323 // If original call returned false, copy Target to Expected.3324 NextIRB.CreateCall(DFSF.DFS.DFSanMemShadowOriginConditionalExchangeFn,3325 {NextIRB.CreateIntCast(&CB, NextIRB.getInt8Ty(), false),3326 TargetPtr, ExpectedPtr, DesiredPtr,3327 NextIRB.CreateIntCast(Size, DFSF.DFS.IntptrTy, false)});3328}3329 3330void DFSanVisitor::visitCallBase(CallBase &CB) {3331 Function *F = CB.getCalledFunction();3332 if ((F && F->isIntrinsic()) || CB.isInlineAsm()) {3333 visitInstOperands(CB);3334 return;3335 }3336 3337 // Calls to this function are synthesized in wrappers, and we shouldn't3338 // instrument them.3339 if (F == DFSF.DFS.DFSanVarargWrapperFn.getCallee()->stripPointerCasts())3340 return;3341 3342 LibFunc LF;3343 if (DFSF.TLI.getLibFunc(CB, LF)) {3344 // libatomic.a functions need to have special handling because there isn't3345 // a good way to intercept them or compile the library with3346 // instrumentation.3347 switch (LF) {3348 case LibFunc_atomic_load:3349 if (!isa<CallInst>(CB)) {3350 llvm::errs() << "DFSAN -- cannot instrument invoke of libatomic load. "3351 "Ignoring!\n";3352 break;3353 }3354 visitLibAtomicLoad(CB);3355 return;3356 case LibFunc_atomic_store:3357 visitLibAtomicStore(CB);3358 return;3359 default:3360 break;3361 }3362 }3363 3364 // TODO: These are not supported by TLI? They are not in the enum.3365 if (F && F->hasName() && !F->isVarArg()) {3366 if (F->getName() == "__atomic_exchange") {3367 visitLibAtomicExchange(CB);3368 return;3369 }3370 if (F->getName() == "__atomic_compare_exchange") {3371 visitLibAtomicCompareExchange(CB);3372 return;3373 }3374 }3375 3376 DenseMap<Value *, Function *>::iterator UnwrappedFnIt =3377 DFSF.DFS.UnwrappedFnMap.find(CB.getCalledOperand());3378 if (UnwrappedFnIt != DFSF.DFS.UnwrappedFnMap.end())3379 if (visitWrappedCallBase(*UnwrappedFnIt->second, CB))3380 return;3381 3382 IRBuilder<> IRB(&CB);3383 3384 const bool ShouldTrackOrigins = DFSF.DFS.shouldTrackOrigins();3385 FunctionType *FT = CB.getFunctionType();3386 const DataLayout &DL = getDataLayout();3387 3388 // Stores argument shadows.3389 unsigned ArgOffset = 0;3390 for (unsigned I = 0, N = FT->getNumParams(); I != N; ++I) {3391 if (ShouldTrackOrigins) {3392 // Ignore overflowed origins3393 Value *ArgShadow = DFSF.getShadow(CB.getArgOperand(I));3394 if (I < DFSF.DFS.NumOfElementsInArgOrgTLS &&3395 !DFSF.DFS.isZeroShadow(ArgShadow))3396 IRB.CreateStore(DFSF.getOrigin(CB.getArgOperand(I)),3397 DFSF.getArgOriginTLS(I, IRB));3398 }3399 3400 unsigned Size =3401 DL.getTypeAllocSize(DFSF.DFS.getShadowTy(FT->getParamType(I)));3402 // Stop storing if arguments' size overflows. Inside a function, arguments3403 // after overflow have zero shadow values.3404 if (ArgOffset + Size > ArgTLSSize)3405 break;3406 IRB.CreateAlignedStore(DFSF.getShadow(CB.getArgOperand(I)),3407 DFSF.getArgTLS(FT->getParamType(I), ArgOffset, IRB),3408 ShadowTLSAlignment);3409 ArgOffset += alignTo(Size, ShadowTLSAlignment);3410 }3411 3412 Instruction *Next = nullptr;3413 if (!CB.getType()->isVoidTy()) {3414 if (InvokeInst *II = dyn_cast<InvokeInst>(&CB)) {3415 if (II->getNormalDest()->getSinglePredecessor()) {3416 Next = &II->getNormalDest()->front();3417 } else {3418 BasicBlock *NewBB =3419 SplitEdge(II->getParent(), II->getNormalDest(), &DFSF.DT);3420 Next = &NewBB->front();3421 }3422 } else {3423 assert(CB.getIterator() != CB.getParent()->end());3424 Next = CB.getNextNode();3425 }3426 3427 // Don't emit the epilogue for musttail call returns.3428 if (isa<CallInst>(CB) && cast<CallInst>(CB).isMustTailCall())3429 return;3430 3431 // Loads the return value shadow.3432 IRBuilder<> NextIRB(Next);3433 unsigned Size = DL.getTypeAllocSize(DFSF.DFS.getShadowTy(&CB));3434 if (Size > RetvalTLSSize) {3435 // Set overflowed return shadow to be zero.3436 DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB));3437 } else {3438 LoadInst *LI = NextIRB.CreateAlignedLoad(3439 DFSF.DFS.getShadowTy(&CB), DFSF.getRetvalTLS(CB.getType(), NextIRB),3440 ShadowTLSAlignment, "_dfsret");3441 DFSF.SkipInsts.insert(LI);3442 DFSF.setShadow(&CB, LI);3443 DFSF.NonZeroChecks.push_back(LI);3444 }3445 3446 if (ShouldTrackOrigins) {3447 LoadInst *LI = NextIRB.CreateLoad(DFSF.DFS.OriginTy,3448 DFSF.getRetvalOriginTLS(), "_dfsret_o");3449 DFSF.SkipInsts.insert(LI);3450 DFSF.setOrigin(&CB, LI);3451 }3452 3453 DFSF.addReachesFunctionCallbacksIfEnabled(NextIRB, CB, &CB);3454 }3455}3456 3457void DFSanVisitor::visitPHINode(PHINode &PN) {3458 Type *ShadowTy = DFSF.DFS.getShadowTy(&PN);3459 PHINode *ShadowPN = PHINode::Create(ShadowTy, PN.getNumIncomingValues(), "",3460 PN.getIterator());3461 3462 // Give the shadow phi node valid predecessors to fool SplitEdge into working.3463 Value *PoisonShadow = PoisonValue::get(ShadowTy);3464 for (BasicBlock *BB : PN.blocks())3465 ShadowPN->addIncoming(PoisonShadow, BB);3466 3467 DFSF.setShadow(&PN, ShadowPN);3468 3469 PHINode *OriginPN = nullptr;3470 if (DFSF.DFS.shouldTrackOrigins()) {3471 OriginPN = PHINode::Create(DFSF.DFS.OriginTy, PN.getNumIncomingValues(), "",3472 PN.getIterator());3473 Value *PoisonOrigin = PoisonValue::get(DFSF.DFS.OriginTy);3474 for (BasicBlock *BB : PN.blocks())3475 OriginPN->addIncoming(PoisonOrigin, BB);3476 DFSF.setOrigin(&PN, OriginPN);3477 }3478 3479 DFSF.PHIFixups.push_back({&PN, ShadowPN, OriginPN});3480}3481 3482PreservedAnalyses DataFlowSanitizerPass::run(Module &M,3483 ModuleAnalysisManager &AM) {3484 // Return early if nosanitize_dataflow module flag is present for the module.3485 if (checkIfAlreadyInstrumented(M, "nosanitize_dataflow"))3486 return PreservedAnalyses::all();3487 auto GetTLI = [&](Function &F) -> TargetLibraryInfo & {3488 auto &FAM =3489 AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();3490 return FAM.getResult<TargetLibraryAnalysis>(F);3491 };3492 if (!DataFlowSanitizer(ABIListFiles, FS).runImpl(M, GetTLI))3493 return PreservedAnalyses::all();3494 3495 PreservedAnalyses PA = PreservedAnalyses::none();3496 // GlobalsAA is considered stateless and does not get invalidated unless3497 // explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers3498 // make changes that require GlobalsAA to be invalidated.3499 PA.abandon<GlobalsAA>();3500 return PA;3501}3502