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
17 using namespace clang;
18 using namespace CodeGen;
19
SanitizerMetadata(CodeGenModule & CGM)20 SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
21
isAsanHwasanMemTagOrTysan(const SanitizerSet & SS)22 static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) {
23 return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |
24 SanitizerKind::HWAddress | SanitizerKind::MemTag |
25 SanitizerKind::Type);
26 }
27
expandKernelSanitizerMasks(SanitizerMask Mask)28 static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
29 if (Mask & (SanitizerKind::Address | SanitizerKind::KernelAddress))
30 Mask |= SanitizerKind::Address | SanitizerKind::KernelAddress;
31 // Note: KHWASan doesn't support globals.
32 return Mask;
33 }
34
reportGlobal(llvm::GlobalVariable * GV,SourceLocation Loc,StringRef Name,QualType Ty,SanitizerMask NoSanitizeAttrMask,bool IsDynInit)35 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
36 SourceLocation Loc, StringRef Name,
37 QualType Ty,
38 SanitizerMask NoSanitizeAttrMask,
39 bool IsDynInit) {
40 SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
41 if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument))
42 return;
43
44 FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask);
45 NoSanitizeAttrMask = expandKernelSanitizerMasks(NoSanitizeAttrMask);
46 SanitizerSet NoSanitizeAttrSet = {NoSanitizeAttrMask &
47 FsanitizeArgument.Mask};
48
49 llvm::GlobalVariable::SanitizerMetadata Meta;
50 if (GV->hasSanitizerMetadata())
51 Meta = GV->getSanitizerMetadata();
52
53 Meta.NoAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::Address);
54 Meta.NoAddress |= CGM.isInNoSanitizeList(
55 FsanitizeArgument.Mask & SanitizerKind::Address, GV, Loc, Ty);
56
57 Meta.NoHWAddress |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::HWAddress);
58 Meta.NoHWAddress |= CGM.isInNoSanitizeList(
59 FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty);
60
61 Meta.Memtag |=
62 static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals);
63 Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
64 Meta.Memtag &= !CGM.isInNoSanitizeList(
65 FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
66
67 Meta.IsDynInit = IsDynInit && !Meta.NoAddress &&
68 FsanitizeArgument.has(SanitizerKind::Address) &&
69 !CGM.isInNoSanitizeList(SanitizerKind::Address |
70 SanitizerKind::KernelAddress,
71 GV, Loc, Ty, "init");
72
73 GV->setSanitizerMetadata(Meta);
74
75 if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) ||
76 NoSanitizeAttrMask & SanitizerKind::Type)
77 return;
78
79 llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(Ty);
80 if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
81 return;
82
83 llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
84 TBAAInfo};
85
86 // Metadata for the global already registered.
87 if (llvm::MDNode::getIfExists(CGM.getLLVMContext(), GlobalMetadata))
88 return;
89
90 llvm::MDNode *ThisGlobal =
91 llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
92 llvm::NamedMDNode *TysanGlobals =
93 CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
94 TysanGlobals->addOperand(ThisGlobal);
95 }
96
reportGlobal(llvm::GlobalVariable * GV,const VarDecl & D,bool IsDynInit)97 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
98 bool IsDynInit) {
99 if (!isAsanHwasanMemTagOrTysan(CGM.getLangOpts().Sanitize))
100 return;
101 std::string QualName;
102 llvm::raw_string_ostream OS(QualName);
103 D.printQualifiedName(OS);
104
105 auto getNoSanitizeMask = [](const VarDecl &D) {
106 if (D.hasAttr<DisableSanitizerInstrumentationAttr>())
107 return SanitizerKind::All;
108
109 SanitizerMask NoSanitizeMask;
110 for (auto *Attr : D.specific_attrs<NoSanitizeAttr>())
111 NoSanitizeMask |= Attr->getMask();
112
113 // External definitions and incomplete types get handled at the place they
114 // are defined.
115 if (D.hasExternalStorage() || D.getType()->isIncompleteType())
116 NoSanitizeMask |= SanitizerKind::Type;
117
118 return NoSanitizeMask;
119 };
120
121 reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
122 IsDynInit);
123 }
124
disableSanitizerForGlobal(llvm::GlobalVariable * GV)125 void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
126 reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
127 }
128