1 //===--- SanitizerMetadata.cpp - Ignored entities for sanitizers ----------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Class which emits metadata consumed by sanitizer instrumentation passes. 10 // 11 //===----------------------------------------------------------------------===// 12 #include "SanitizerMetadata.h" 13 #include "CodeGenModule.h" 14 #include "clang/AST/Attr.h" 15 #include "clang/AST/Type.h" 16 #include "clang/Basic/SourceManager.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/IR/Constants.h" 19 20 using namespace clang; 21 using namespace CodeGen; 22 23 SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {} 24 25 // TODO(hctim): Can be removed when we migrate off of llvm.asan.globals. This 26 // prevents llvm.asan.globals from being emitted for 27 // __attribute__((disable_sanitizer_instrumentation)) and uses of 28 // -fsanitize-ignorelist when a sanitizer isn't enabled. 29 static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) { 30 return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress | 31 SanitizerKind::HWAddress | SanitizerKind::MemTag); 32 } 33 34 SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) { 35 if (Mask & (SanitizerKind::Address | SanitizerKind::KernelAddress)) 36 Mask |= SanitizerKind::Address | SanitizerKind::KernelAddress; 37 // Note: KHWASan doesn't support globals. 38 return Mask; 39 } 40 41 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, 42 SourceLocation Loc, StringRef Name, 43 QualType Ty, 44 SanitizerMask NoSanitizeAttrMask, 45 bool IsDynInit) { 46 SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize; 47 if (!isAsanHwasanOrMemTag(FsanitizeArgument)) 48 return; 49 50 FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask); 51 NoSanitizeAttrMask = expandKernelSanitizerMasks(NoSanitizeAttrMask); 52 SanitizerSet NoSanitizeAttrSet = {NoSanitizeAttrMask & 53 FsanitizeArgument.Mask}; 54 55 llvm::GlobalVariable::SanitizerMetadata Meta; 56 if (GV->hasSanitizerMetadata()) 57 Meta = GV->getSanitizerMetadata(); 58 59 Meta.NoAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::Address); 60 Meta.NoAddress |= CGM.isInNoSanitizeList( 61 FsanitizeArgument.Mask & SanitizerKind::Address, GV, Loc, Ty); 62 63 Meta.NoHWAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::HWAddress); 64 Meta.NoHWAddress |= CGM.isInNoSanitizeList( 65 FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty); 66 67 Meta.NoMemtag |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag); 68 Meta.NoMemtag |= CGM.isInNoSanitizeList( 69 FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty); 70 71 if (FsanitizeArgument.has(SanitizerKind::Address)) { 72 // TODO(hctim): Make this conditional when we migrate off llvm.asan.globals. 73 IsDynInit &= !CGM.isInNoSanitizeList(SanitizerKind::Address | 74 SanitizerKind::KernelAddress, 75 GV, Loc, Ty, "init"); 76 Meta.IsDynInit = IsDynInit; 77 } 78 79 bool IsExcluded = Meta.NoAddress || Meta.NoHWAddress || Meta.NoMemtag; 80 81 GV->setSanitizerMetadata(Meta); 82 83 // TODO(hctim): Code below can be removed when we migrate off of 84 // llvm.asan.globals onto the new metadata attributes. 85 llvm::Metadata *LocDescr = nullptr; 86 llvm::Metadata *GlobalName = nullptr; 87 llvm::LLVMContext &VMContext = CGM.getLLVMContext(); 88 if (!IsExcluded) { 89 // Don't generate source location and global name if it is on 90 // the NoSanitizeList - it won't be instrumented anyway. 91 LocDescr = getLocationMetadata(Loc); 92 if (!Name.empty()) 93 GlobalName = llvm::MDString::get(VMContext, Name); 94 } 95 96 llvm::Metadata *GlobalMetadata[] = { 97 llvm::ConstantAsMetadata::get(GV), LocDescr, GlobalName, 98 llvm::ConstantAsMetadata::get( 99 llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsDynInit)), 100 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( 101 llvm::Type::getInt1Ty(VMContext), IsExcluded))}; 102 103 llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalMetadata); 104 llvm::NamedMDNode *AsanGlobals = 105 CGM.getModule().getOrInsertNamedMetadata("llvm.asan.globals"); 106 AsanGlobals->addOperand(ThisGlobal); 107 } 108 109 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, 110 bool IsDynInit) { 111 if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize)) 112 return; 113 std::string QualName; 114 llvm::raw_string_ostream OS(QualName); 115 D.printQualifiedName(OS); 116 117 auto getNoSanitizeMask = [](const VarDecl &D) { 118 if (D.hasAttr<DisableSanitizerInstrumentationAttr>()) 119 return SanitizerKind::All; 120 121 SanitizerMask NoSanitizeMask; 122 for (auto *Attr : D.specific_attrs<NoSanitizeAttr>()) 123 NoSanitizeMask |= Attr->getMask(); 124 125 return NoSanitizeMask; 126 }; 127 128 reportGlobal(GV, D.getLocation(), OS.str(), D.getType(), getNoSanitizeMask(D), 129 IsDynInit); 130 } 131 132 void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { 133 reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All); 134 } 135 136 void SanitizerMetadata::disableSanitizerForInstruction(llvm::Instruction *I) { 137 I->setMetadata(llvm::LLVMContext::MD_nosanitize, 138 llvm::MDNode::get(CGM.getLLVMContext(), None)); 139 } 140 141 llvm::MDNode *SanitizerMetadata::getLocationMetadata(SourceLocation Loc) { 142 PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc); 143 if (!PLoc.isValid()) 144 return nullptr; 145 llvm::LLVMContext &VMContext = CGM.getLLVMContext(); 146 llvm::Metadata *LocMetadata[] = { 147 llvm::MDString::get(VMContext, PLoc.getFilename()), 148 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( 149 llvm::Type::getInt32Ty(VMContext), PLoc.getLine())), 150 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( 151 llvm::Type::getInt32Ty(VMContext), PLoc.getColumn())), 152 }; 153 return llvm::MDNode::get(VMContext, LocMetadata); 154 } 155