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