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 | |
20 | SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {} |
21 | |
22 | static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) { |
23 | return SS.hasOneOf(K: SanitizerKind::Address | SanitizerKind::KernelAddress | |
24 | SanitizerKind::HWAddress | SanitizerKind::MemTag | |
25 | SanitizerKind::Type); |
26 | } |
27 | |
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 | |
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(SS: FsanitizeArgument)) |
42 | return; |
43 | |
44 | FsanitizeArgument.Mask = expandKernelSanitizerMasks(Mask: FsanitizeArgument.Mask); |
45 | NoSanitizeAttrMask = expandKernelSanitizerMasks(Mask: NoSanitizeAttrMask); |
46 | SanitizerSet NoSanitizeAttrSet = {.Mask: NoSanitizeAttrMask & |
47 | FsanitizeArgument.Mask}; |
48 | |
49 | llvm::GlobalVariable::SanitizerMetadata Meta; |
50 | if (GV->hasSanitizerMetadata()) |
51 | Meta = GV->getSanitizerMetadata(); |
52 | |
53 | Meta.NoAddress |= NoSanitizeAttrSet.hasOneOf(K: SanitizerKind::Address); |
54 | Meta.NoAddress |= CGM.isInNoSanitizeList( |
55 | Kind: FsanitizeArgument.Mask & SanitizerKind::Address, GV, Loc, Ty); |
56 | |
57 | Meta.NoHWAddress |= NoSanitizeAttrSet.hasOneOf(K: SanitizerKind::HWAddress); |
58 | Meta.NoHWAddress |= CGM.isInNoSanitizeList( |
59 | Kind: FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty); |
60 | |
61 | Meta.Memtag |= |
62 | static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals); |
63 | Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(K: SanitizerKind::MemTag); |
64 | Meta.Memtag &= !CGM.isInNoSanitizeList( |
65 | Kind: FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty); |
66 | |
67 | Meta.IsDynInit = IsDynInit && !Meta.NoAddress && |
68 | FsanitizeArgument.has(K: SanitizerKind::Address) && |
69 | !CGM.isInNoSanitizeList(Kind: SanitizerKind::Address | |
70 | SanitizerKind::KernelAddress, |
71 | GV, Loc, Ty, Category: "init" ); |
72 | |
73 | GV->setSanitizerMetadata(Meta); |
74 | |
75 | if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(K: SanitizerKind::Type) || |
76 | NoSanitizeAttrMask & SanitizerKind::Type) |
77 | return; |
78 | |
79 | llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(QTy: Ty); |
80 | if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(QTy: CGM.getContext().CharTy)) |
81 | return; |
82 | |
83 | llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(C: GV), |
84 | TBAAInfo}; |
85 | |
86 | // Metadata for the global already registered. |
87 | if (llvm::MDNode::getIfExists(Context&: CGM.getLLVMContext(), MDs: GlobalMetadata)) |
88 | return; |
89 | |
90 | llvm::MDNode *ThisGlobal = |
91 | llvm::MDNode::get(Context&: CGM.getLLVMContext(), MDs: GlobalMetadata); |
92 | llvm::NamedMDNode *TysanGlobals = |
93 | CGM.getModule().getOrInsertNamedMetadata(Name: "llvm.tysan.globals" ); |
94 | TysanGlobals->addOperand(M: ThisGlobal); |
95 | } |
96 | |
97 | void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, |
98 | bool IsDynInit) { |
99 | if (!isAsanHwasanMemTagOrTysan(SS: 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, Loc: D.getLocation(), Name: QualName, Ty: D.getType(), NoSanitizeAttrMask: getNoSanitizeMask(D), |
122 | IsDynInit); |
123 | } |
124 | |
125 | void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { |
126 | reportGlobal(GV, Loc: SourceLocation(), Name: "" , Ty: QualType(), NoSanitizeAttrMask: SanitizerKind::All); |
127 | } |
128 | |