Skip to content

Commit 514580b

Browse files
authored
[MTE] Apply alignment / size in AsmPrinter rather than IR (#111918)
This makes sure no optimizations are applied that assume the bigger alignment or size, which could be incorrect if we link together with non-instrumented code.
1 parent 58cfa39 commit 514580b

File tree

12 files changed

+108
-170
lines changed

12 files changed

+108
-170
lines changed

clang/lib/CodeGen/SanitizerMetadata.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,37 @@ static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
3131
return Mask;
3232
}
3333

34+
static bool shouldTagGlobal(const llvm::GlobalVariable &G) {
35+
// For now, don't instrument constant data, as it'll be in .rodata anyway. It
36+
// may be worth instrumenting these in future to stop them from being used as
37+
// gadgets.
38+
if (G.getName().starts_with("llvm.") || G.isThreadLocal() || G.isConstant())
39+
return false;
40+
41+
// Globals can be placed implicitly or explicitly in sections. There's two
42+
// different types of globals that meet this criteria that cause problems:
43+
// 1. Function pointers that are going into various init arrays (either
44+
// explicitly through `__attribute__((section(<foo>)))` or implicitly
45+
// through `__attribute__((constructor)))`, such as ".(pre)init(_array)",
46+
// ".fini(_array)", ".ctors", and ".dtors". These function pointers end up
47+
// overaligned and overpadded, making iterating over them problematic, and
48+
// each function pointer is individually tagged (so the iteration over
49+
// them causes SIGSEGV/MTE[AS]ERR).
50+
// 2. Global variables put into an explicit section, where the section's name
51+
// is a valid C-style identifier. The linker emits a `__start_<name>` and
52+
// `__stop_<name>` symbol for the section, so that you can iterate over
53+
// globals within this section. Unfortunately, again, these globals would
54+
// be tagged and so iteration causes SIGSEGV/MTE[AS]ERR.
55+
//
56+
// To mitigate both these cases, and because specifying a section is rare
57+
// outside of these two cases, disable MTE protection for globals in any
58+
// section.
59+
if (G.hasSection())
60+
return false;
61+
62+
return true;
63+
}
64+
3465
void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
3566
SourceLocation Loc, StringRef Name,
3667
QualType Ty,
@@ -57,11 +88,15 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
5788
Meta.NoHWAddress |= CGM.isInNoSanitizeList(
5889
FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty);
5990

60-
Meta.Memtag |=
61-
static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals);
62-
Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
63-
Meta.Memtag &= !CGM.isInNoSanitizeList(
64-
FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
91+
if (shouldTagGlobal(*GV)) {
92+
Meta.Memtag |= static_cast<bool>(FsanitizeArgument.Mask &
93+
SanitizerKind::MemtagGlobals);
94+
Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
95+
Meta.Memtag &= !CGM.isInNoSanitizeList(
96+
FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
97+
} else {
98+
Meta.Memtag = false;
99+
}
65100

66101
Meta.IsDynInit = IsDynInit && !Meta.NoAddress &&
67102
FsanitizeArgument.has(SanitizerKind::Address) &&

clang/test/CodeGen/memtag-globals.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// RUN: FileCheck %s --check-prefix=IGNORELIST
1111

1212
int global;
13+
int __attribute__((__section__("my_section"))) section_global;
1314
int __attribute__((no_sanitize("memtag"))) attributed_global;
1415
int __attribute__((disable_sanitizer_instrumentation)) disable_instrumentation_global;
1516
int ignorelisted_global;
@@ -24,6 +25,8 @@ void func() {
2425
// CHECK: @{{.*}}extra_global{{.*}} ={{.*}} sanitize_memtag
2526
// CHECK: @{{.*}}global{{.*}} ={{.*}} sanitize_memtag
2627

28+
// CHECK: @{{.*}}section_global{{.*}} =
29+
// CHECK-NOT: sanitize_memtag
2730
// CHECK: @{{.*}}attributed_global{{.*}} =
2831
// CHECK-NOT: sanitize_memtag
2932
// CHECK: @{{.*}}disable_instrumentation_global{{.*}} =
@@ -32,7 +35,7 @@ void func() {
3235
// CHECK-NOT: sanitize_memtag
3336

3437
// CHECK: @{{.*}}static_var{{.*}} ={{.*}} sanitize_memtag
35-
// CHECK: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}} sanitize_memtag
38+
// CHECK: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}}
3639
// CHECK: @{{.*}}external_global{{.*}} ={{.*}} sanitize_memtag
3740

3841
// IGNORELIST: @{{.*}}extra_global{{.*}} ={{.*}} sanitize_memtag

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2406,12 +2406,50 @@ void AsmPrinter::emitRemarksSection(remarks::RemarkStreamer &RS) {
24062406
OutStreamer->emitBinaryData(Buf);
24072407
}
24082408

2409+
static void tagGlobalDefinition(Module &M, GlobalVariable *G) {
2410+
Constant *Initializer = G->getInitializer();
2411+
uint64_t SizeInBytes =
2412+
M.getDataLayout().getTypeAllocSize(Initializer->getType());
2413+
2414+
uint64_t NewSize = alignTo(SizeInBytes, 16);
2415+
if (SizeInBytes != NewSize) {
2416+
// Pad the initializer out to the next multiple of 16 bytes.
2417+
llvm::SmallVector<uint8_t> Init(NewSize - SizeInBytes, 0);
2418+
Constant *Padding = ConstantDataArray::get(M.getContext(), Init);
2419+
Initializer = ConstantStruct::getAnon({Initializer, Padding});
2420+
auto *NewGV = new GlobalVariable(
2421+
M, Initializer->getType(), G->isConstant(), G->getLinkage(),
2422+
Initializer, "", G, G->getThreadLocalMode(), G->getAddressSpace());
2423+
NewGV->copyAttributesFrom(G);
2424+
NewGV->setComdat(G->getComdat());
2425+
NewGV->copyMetadata(G, 0);
2426+
2427+
NewGV->takeName(G);
2428+
G->replaceAllUsesWith(NewGV);
2429+
G->eraseFromParent();
2430+
G = NewGV;
2431+
}
2432+
2433+
if (G->getAlign().valueOrOne() < 16)
2434+
G->setAlignment(Align(16));
2435+
2436+
// Ensure that tagged globals don't get merged by ICF - as they should have
2437+
// different tags at runtime.
2438+
G->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
2439+
}
2440+
24092441
bool AsmPrinter::doFinalization(Module &M) {
24102442
// Set the MachineFunction to nullptr so that we can catch attempted
24112443
// accesses to MF specific features at the module level and so that
24122444
// we can conditionalize accesses based on whether or not it is nullptr.
24132445
MF = nullptr;
24142446

2447+
for (GlobalVariable &G : make_early_inc_range(M.globals())) {
2448+
if (G.isDeclaration() || !G.isTagged())
2449+
continue;
2450+
tagGlobalDefinition(M, &G);
2451+
}
2452+
24152453
// Gather all GOT equivalent globals in the module. We really need two
24162454
// passes over the globals: one to compute and another to avoid its emission
24172455
// in EmitGlobalVariable, otherwise we would not be able to handle cases

llvm/lib/IR/Verifier.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,10 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
808808
"visibility must be dso_local!",
809809
&GV);
810810

811+
if (GV.isTagged()) {
812+
Check(!GV.hasSection(), "tagged GlobalValue must not be in section.", &GV);
813+
}
814+
811815
forEachUser(&GV, GlobalValueVisited, [&](const Value *V) -> bool {
812816
if (const Instruction *I = dyn_cast<Instruction>(V)) {
813817
if (!I->getParent() || !I->getParent()->getParent())

llvm/lib/Target/AArch64/AArch64.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ FunctionPass *createAArch64PostLegalizerLowering();
7272
FunctionPass *createAArch64PostSelectOptimize();
7373
FunctionPass *createAArch64StackTaggingPass(bool IsOptNone);
7474
FunctionPass *createAArch64StackTaggingPreRAPass();
75-
ModulePass *createAArch64GlobalsTaggingPass();
7675
ModulePass *createAArch64Arm64ECCallLoweringPass();
7776

7877
void initializeAArch64A53Fix835769Pass(PassRegistry&);
@@ -89,7 +88,6 @@ void initializeAArch64ConditionalComparesPass(PassRegistry &);
8988
void initializeAArch64DAGToDAGISelLegacyPass(PassRegistry &);
9089
void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry&);
9190
void initializeAArch64ExpandPseudoPass(PassRegistry &);
92-
void initializeAArch64GlobalsTaggingPass(PassRegistry &);
9391
void initializeAArch64LoadStoreOptPass(PassRegistry&);
9492
void initializeAArch64LowerHomogeneousPrologEpilogPass(PassRegistry &);
9593
void initializeAArch64MIPeepholeOptPass(PassRegistry &);

llvm/lib/Target/AArch64/AArch64GlobalsTagging.cpp

Lines changed: 0 additions & 155 deletions
This file was deleted.

llvm/lib/Target/AArch64/AArch64TargetMachine.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,6 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64Target() {
268268
initializeAArch64StackTaggingPreRAPass(*PR);
269269
initializeAArch64LowerHomogeneousPrologEpilogPass(*PR);
270270
initializeAArch64DAGToDAGISelLegacyPass(*PR);
271-
initializeAArch64GlobalsTaggingPass(*PR);
272271
}
273272

274273
void AArch64TargetMachine::reset() { SubtargetMap.clear(); }
@@ -642,7 +641,6 @@ void AArch64PassConfig::addIRPasses() {
642641
if (getOptLevel() == CodeGenOptLevel::Aggressive && EnableSelectOpt)
643642
addPass(createSelectOptimizePass());
644643

645-
addPass(createAArch64GlobalsTaggingPass());
646644
addPass(createAArch64StackTaggingPass(
647645
/*IsOptNone=*/TM->getOptLevel() == CodeGenOptLevel::None));
648646

llvm/lib/Target/AArch64/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ add_llvm_target(AArch64CodeGen
5757
AArch64FastISel.cpp
5858
AArch64A53Fix835769.cpp
5959
AArch64FrameLowering.cpp
60-
AArch64GlobalsTagging.cpp
6160
AArch64CompressJumpTables.cpp
6261
AArch64ConditionOptimizer.cpp
6362
AArch64RedundantCopyElimination.cpp

llvm/test/CodeGen/AArch64/O0-pipeline.ll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (post inlining)
2626
; CHECK-NEXT: Scalarize Masked Memory Intrinsics
2727
; CHECK-NEXT: Expand reduction intrinsics
28-
; CHECK-NEXT: AArch64 Globals Tagging
29-
; CHECK-NEXT: FunctionPass Manager
3028
; CHECK-NEXT: Dominator Tree Construction
3129
; CHECK-NEXT: Natural Loop Information
3230
; CHECK-NEXT: Lazy Branch Probability Analysis

llvm/test/CodeGen/AArch64/O3-pipeline.ll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@
7171
; CHECK-NEXT: Lazy Block Frequency Analysis
7272
; CHECK-NEXT: Optimization Remark Emitter
7373
; CHECK-NEXT: Optimize selects
74-
; CHECK-NEXT: AArch64 Globals Tagging
7574
; CHECK-NEXT: Stack Safety Analysis
7675
; CHECK-NEXT: FunctionPass Manager
7776
; CHECK-NEXT: Dominator Tree Construction

llvm/unittests/IR/VerifierTest.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/IR/DerivedTypes.h"
1313
#include "llvm/IR/Function.h"
1414
#include "llvm/IR/GlobalAlias.h"
15+
#include "llvm/IR/GlobalValue.h"
1516
#include "llvm/IR/GlobalVariable.h"
1617
#include "llvm/IR/IRBuilder.h"
1718
#include "llvm/IR/Instructions.h"
@@ -415,5 +416,26 @@ TEST(VerifierTest, GetElementPtrInst) {
415416
<< Error;
416417
}
417418

419+
TEST(VerifierTest, DetectTaggedGlobalInSection) {
420+
LLVMContext C;
421+
Module M("M", C);
422+
GlobalVariable *GV = new GlobalVariable(
423+
Type::getInt64Ty(C), false, GlobalValue::InternalLinkage,
424+
ConstantInt::get(Type::getInt64Ty(C), 1));
425+
GV->setDSOLocal(true);
426+
GlobalValue::SanitizerMetadata MD{};
427+
MD.Memtag = true;
428+
GV->setSanitizerMetadata(MD);
429+
GV->setSection("foo");
430+
M.insertGlobalVariable(GV);
431+
432+
std::string Error;
433+
raw_string_ostream ErrorOS(Error);
434+
EXPECT_TRUE(verifyModule(M, &ErrorOS));
435+
EXPECT_TRUE(
436+
StringRef(Error).starts_with("tagged GlobalValue must not be in section"))
437+
<< Error;
438+
}
439+
418440
} // end anonymous namespace
419441
} // end namespace llvm

0 commit comments

Comments
 (0)