1 //===--- SanitizerMetadata.cpp - Ignored entities for sanitizers ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // Class which emits metadata consumed by sanitizer instrumentation passes.
11 //===----------------------------------------------------------------------===//
12 #include "SanitizerMetadata.h"
13 #include "CodeGenModule.h"
14 #include "clang/AST/Attr.h"
15 #include "clang/AST/Type.h"
17 using namespace clang
;
18 using namespace CodeGen
;
20 SanitizerMetadata::SanitizerMetadata(CodeGenModule
&CGM
) : CGM(CGM
) {}
22 static bool isAsanHwasanMemTagOrTysan(const SanitizerSet
&SS
) {
23 return SS
.hasOneOf(SanitizerKind::Address
| SanitizerKind::KernelAddress
|
24 SanitizerKind::HWAddress
| SanitizerKind::MemTag
|
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.
35 static bool shouldTagGlobal(const llvm::GlobalVariable
&G
) {
36 // For now, don't instrument constant data, as it'll be in .rodata anyway. It
37 // may be worth instrumenting these in future to stop them from being used as
39 if (G
.getName().starts_with("llvm.") || G
.isThreadLocal() || G
.isConstant())
42 // Globals can be placed implicitly or explicitly in sections. There's two
43 // different types of globals that meet this criteria that cause problems:
44 // 1. Function pointers that are going into various init arrays (either
45 // explicitly through `__attribute__((section(<foo>)))` or implicitly
46 // through `__attribute__((constructor)))`, such as ".(pre)init(_array)",
47 // ".fini(_array)", ".ctors", and ".dtors". These function pointers end up
48 // overaligned and overpadded, making iterating over them problematic, and
49 // each function pointer is individually tagged (so the iteration over
50 // them causes SIGSEGV/MTE[AS]ERR).
51 // 2. Global variables put into an explicit section, where the section's name
52 // is a valid C-style identifier. The linker emits a `__start_<name>` and
53 // `__stop_<name>` symbol for the section, so that you can iterate over
54 // globals within this section. Unfortunately, again, these globals would
55 // be tagged and so iteration causes SIGSEGV/MTE[AS]ERR.
57 // To mitigate both these cases, and because specifying a section is rare
58 // outside of these two cases, disable MTE protection for globals in any
66 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable
*GV
,
67 SourceLocation Loc
, StringRef Name
,
69 SanitizerMask NoSanitizeAttrMask
,
71 SanitizerSet FsanitizeArgument
= CGM
.getLangOpts().Sanitize
;
72 if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument
))
75 FsanitizeArgument
.Mask
= expandKernelSanitizerMasks(FsanitizeArgument
.Mask
);
76 NoSanitizeAttrMask
= expandKernelSanitizerMasks(NoSanitizeAttrMask
);
77 SanitizerSet NoSanitizeAttrSet
= {NoSanitizeAttrMask
&
78 FsanitizeArgument
.Mask
};
80 llvm::GlobalVariable::SanitizerMetadata Meta
;
81 if (GV
->hasSanitizerMetadata())
82 Meta
= GV
->getSanitizerMetadata();
84 Meta
.NoAddress
|= NoSanitizeAttrSet
.hasOneOf(SanitizerKind::Address
);
85 Meta
.NoAddress
|= CGM
.isInNoSanitizeList(
86 FsanitizeArgument
.Mask
& SanitizerKind::Address
, GV
, Loc
, Ty
);
88 Meta
.NoHWAddress
|= NoSanitizeAttrSet
.hasOneOf(SanitizerKind::HWAddress
);
89 Meta
.NoHWAddress
|= CGM
.isInNoSanitizeList(
90 FsanitizeArgument
.Mask
& SanitizerKind::HWAddress
, GV
, Loc
, Ty
);
92 if (shouldTagGlobal(*GV
)) {
93 Meta
.Memtag
|= static_cast<bool>(FsanitizeArgument
.Mask
&
94 SanitizerKind::MemtagGlobals
);
95 Meta
.Memtag
&= !NoSanitizeAttrSet
.hasOneOf(SanitizerKind::MemTag
);
96 Meta
.Memtag
&= !CGM
.isInNoSanitizeList(
97 FsanitizeArgument
.Mask
& SanitizerKind::MemTag
, GV
, Loc
, Ty
);
102 Meta
.IsDynInit
= IsDynInit
&& !Meta
.NoAddress
&&
103 FsanitizeArgument
.has(SanitizerKind::Address
) &&
104 !CGM
.isInNoSanitizeList(SanitizerKind::Address
|
105 SanitizerKind::KernelAddress
,
106 GV
, Loc
, Ty
, "init");
108 GV
->setSanitizerMetadata(Meta
);
110 if (Ty
.isNull() || !CGM
.getLangOpts().Sanitize
.has(SanitizerKind::Type
) ||
111 NoSanitizeAttrMask
& SanitizerKind::Type
)
114 llvm::MDNode
*TBAAInfo
= CGM
.getTBAATypeInfo(Ty
);
115 if (!TBAAInfo
|| TBAAInfo
== CGM
.getTBAATypeInfo(CGM
.getContext().CharTy
))
118 llvm::Metadata
*GlobalMetadata
[] = {llvm::ConstantAsMetadata::get(GV
),
121 // Metadata for the global already registered.
122 if (llvm::MDNode::getIfExists(CGM
.getLLVMContext(), GlobalMetadata
))
125 llvm::MDNode
*ThisGlobal
=
126 llvm::MDNode::get(CGM
.getLLVMContext(), GlobalMetadata
);
127 llvm::NamedMDNode
*TysanGlobals
=
128 CGM
.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
129 TysanGlobals
->addOperand(ThisGlobal
);
132 void SanitizerMetadata::reportGlobal(llvm::GlobalVariable
*GV
, const VarDecl
&D
,
134 if (!isAsanHwasanMemTagOrTysan(CGM
.getLangOpts().Sanitize
))
136 std::string QualName
;
137 llvm::raw_string_ostream
OS(QualName
);
138 D
.printQualifiedName(OS
);
140 auto getNoSanitizeMask
= [](const VarDecl
&D
) {
141 if (D
.hasAttr
<DisableSanitizerInstrumentationAttr
>())
142 return SanitizerKind::All
;
144 SanitizerMask NoSanitizeMask
;
145 for (auto *Attr
: D
.specific_attrs
<NoSanitizeAttr
>())
146 NoSanitizeMask
|= Attr
->getMask();
148 // External definitions and incomplete types get handled at the place they
150 if (D
.hasExternalStorage() || D
.getType()->isIncompleteType())
151 NoSanitizeMask
|= SanitizerKind::Type
;
153 return NoSanitizeMask
;
156 reportGlobal(GV
, D
.getLocation(), QualName
, D
.getType(), getNoSanitizeMask(D
),
160 void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable
*GV
) {
161 reportGlobal(GV
, SourceLocation(), "", QualType(), SanitizerKind::All
);