Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/CFGuard/CFGuard.cpp
35266 views
1
//===-- CFGuard.cpp - Control Flow Guard checks -----------------*- C++ -*-===//
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
/// \file
10
/// This file contains the IR transform to add Microsoft's Control Flow Guard
11
/// checks on Windows targets.
12
///
13
//===----------------------------------------------------------------------===//
14
15
#include "llvm/Transforms/CFGuard.h"
16
#include "llvm/ADT/SmallVector.h"
17
#include "llvm/ADT/Statistic.h"
18
#include "llvm/IR/CallingConv.h"
19
#include "llvm/IR/IRBuilder.h"
20
#include "llvm/IR/Instruction.h"
21
#include "llvm/IR/Module.h"
22
#include "llvm/InitializePasses.h"
23
#include "llvm/Pass.h"
24
#include "llvm/TargetParser/Triple.h"
25
26
using namespace llvm;
27
28
using OperandBundleDef = OperandBundleDefT<Value *>;
29
30
#define DEBUG_TYPE "cfguard"
31
32
STATISTIC(CFGuardCounter, "Number of Control Flow Guard checks added");
33
34
namespace {
35
36
/// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes.
37
/// These checks ensure that the target address corresponds to the start of an
38
/// address-taken function. X86_64 targets use the Mechanism::Dispatch
39
/// mechanism. X86, ARM, and AArch64 targets use the Mechanism::Check machanism.
40
class CFGuardImpl {
41
public:
42
using Mechanism = CFGuardPass::Mechanism;
43
44
CFGuardImpl(Mechanism M) : GuardMechanism(M) {
45
// Get or insert the guard check or dispatch global symbols.
46
switch (GuardMechanism) {
47
case Mechanism::Check:
48
GuardFnName = "__guard_check_icall_fptr";
49
break;
50
case Mechanism::Dispatch:
51
GuardFnName = "__guard_dispatch_icall_fptr";
52
break;
53
}
54
}
55
56
/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
57
/// check mechanism. When the image is loaded, the loader puts the appropriate
58
/// guard check function pointer in the __guard_check_icall_fptr global
59
/// symbol. This checks that the target address is a valid address-taken
60
/// function. The address of the target function is passed to the guard check
61
/// function in an architecture-specific register (e.g. ECX on 32-bit X86,
62
/// X15 on Aarch64, and R0 on ARM). The guard check function has no return
63
/// value (if the target is invalid, the guard check funtion will raise an
64
/// error).
65
///
66
/// For example, the following LLVM IR:
67
/// \code
68
/// %func_ptr = alloca i32 ()*, align 8
69
/// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
70
/// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
71
/// %1 = call i32 %0()
72
/// \endcode
73
///
74
/// is transformed to:
75
/// \code
76
/// %func_ptr = alloca i32 ()*, align 8
77
/// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
78
/// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
79
/// %1 = load void (i8*)*, void (i8*)** @__guard_check_icall_fptr
80
/// %2 = bitcast i32 ()* %0 to i8*
81
/// call cfguard_checkcc void %1(i8* %2)
82
/// %3 = call i32 %0()
83
/// \endcode
84
///
85
/// For example, the following X86 assembly code:
86
/// \code
87
/// movl $_target_func, %eax
88
/// calll *%eax
89
/// \endcode
90
///
91
/// is transformed to:
92
/// \code
93
/// movl $_target_func, %ecx
94
/// calll *___guard_check_icall_fptr
95
/// calll *%ecx
96
/// \endcode
97
///
98
/// \param CB indirect call to instrument.
99
void insertCFGuardCheck(CallBase *CB);
100
101
/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
102
/// dispatch mechanism. When the image is loaded, the loader puts the
103
/// appropriate guard check function pointer in the
104
/// __guard_dispatch_icall_fptr global symbol. This checks that the target
105
/// address is a valid address-taken function and, if so, tail calls the
106
/// target. The target address is passed in an architecture-specific register
107
/// (e.g. RAX on X86_64), with all other arguments for the target function
108
/// passed as usual.
109
///
110
/// For example, the following LLVM IR:
111
/// \code
112
/// %func_ptr = alloca i32 ()*, align 8
113
/// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
114
/// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
115
/// %1 = call i32 %0()
116
/// \endcode
117
///
118
/// is transformed to:
119
/// \code
120
/// %func_ptr = alloca i32 ()*, align 8
121
/// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
122
/// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
123
/// %1 = load i32 ()*, i32 ()** @__guard_dispatch_icall_fptr
124
/// %2 = call i32 %1() [ "cfguardtarget"(i32 ()* %0) ]
125
/// \endcode
126
///
127
/// For example, the following X86_64 assembly code:
128
/// \code
129
/// leaq target_func(%rip), %rax
130
/// callq *%rax
131
/// \endcode
132
///
133
/// is transformed to:
134
/// \code
135
/// leaq target_func(%rip), %rax
136
/// callq *__guard_dispatch_icall_fptr(%rip)
137
/// \endcode
138
///
139
/// \param CB indirect call to instrument.
140
void insertCFGuardDispatch(CallBase *CB);
141
142
bool doInitialization(Module &M);
143
bool runOnFunction(Function &F);
144
145
private:
146
// Only add checks if the module has the cfguard=2 flag.
147
int cfguard_module_flag = 0;
148
StringRef GuardFnName;
149
Mechanism GuardMechanism = Mechanism::Check;
150
FunctionType *GuardFnType = nullptr;
151
PointerType *GuardFnPtrType = nullptr;
152
Constant *GuardFnGlobal = nullptr;
153
};
154
155
class CFGuard : public FunctionPass {
156
CFGuardImpl Impl;
157
158
public:
159
static char ID;
160
161
// Default constructor required for the INITIALIZE_PASS macro.
162
CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {
163
initializeCFGuardPass(*PassRegistry::getPassRegistry());
164
}
165
166
bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
167
bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
168
};
169
170
} // end anonymous namespace
171
172
void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {
173
174
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
175
"Only applicable for Windows targets");
176
assert(CB->isIndirectCall() &&
177
"Control Flow Guard checks can only be added to indirect calls");
178
179
IRBuilder<> B(CB);
180
Value *CalledOperand = CB->getCalledOperand();
181
182
// If the indirect call is called within catchpad or cleanuppad,
183
// we need to copy "funclet" bundle of the call.
184
SmallVector<llvm::OperandBundleDef, 1> Bundles;
185
if (auto Bundle = CB->getOperandBundle(LLVMContext::OB_funclet))
186
Bundles.push_back(OperandBundleDef(*Bundle));
187
188
// Load the global symbol as a pointer to the check function.
189
LoadInst *GuardCheckLoad = B.CreateLoad(GuardFnPtrType, GuardFnGlobal);
190
191
// Create new call instruction. The CFGuard check should always be a call,
192
// even if the original CallBase is an Invoke or CallBr instruction.
193
CallInst *GuardCheck =
194
B.CreateCall(GuardFnType, GuardCheckLoad, {CalledOperand}, Bundles);
195
196
// Ensure that the first argument is passed in the correct register
197
// (e.g. ECX on 32-bit X86 targets).
198
GuardCheck->setCallingConv(CallingConv::CFGuard_Check);
199
}
200
201
void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {
202
203
assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&
204
"Only applicable for Windows targets");
205
assert(CB->isIndirectCall() &&
206
"Control Flow Guard checks can only be added to indirect calls");
207
208
IRBuilder<> B(CB);
209
Value *CalledOperand = CB->getCalledOperand();
210
Type *CalledOperandType = CalledOperand->getType();
211
212
// Load the global as a pointer to a function of the same type.
213
LoadInst *GuardDispatchLoad = B.CreateLoad(CalledOperandType, GuardFnGlobal);
214
215
// Add the original call target as a cfguardtarget operand bundle.
216
SmallVector<llvm::OperandBundleDef, 1> Bundles;
217
CB->getOperandBundlesAsDefs(Bundles);
218
Bundles.emplace_back("cfguardtarget", CalledOperand);
219
220
// Create a copy of the call/invoke instruction and add the new bundle.
221
assert((isa<CallInst>(CB) || isa<InvokeInst>(CB)) &&
222
"Unknown indirect call type");
223
CallBase *NewCB = CallBase::Create(CB, Bundles, CB->getIterator());
224
225
// Change the target of the call to be the guard dispatch function.
226
NewCB->setCalledOperand(GuardDispatchLoad);
227
228
// Replace the original call/invoke with the new instruction.
229
CB->replaceAllUsesWith(NewCB);
230
231
// Delete the original call/invoke.
232
CB->eraseFromParent();
233
}
234
235
bool CFGuardImpl::doInitialization(Module &M) {
236
237
// Check if this module has the cfguard flag and read its value.
238
if (auto *MD =
239
mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("cfguard")))
240
cfguard_module_flag = MD->getZExtValue();
241
242
// Skip modules for which CFGuard checks have been disabled.
243
if (cfguard_module_flag != 2)
244
return false;
245
246
// Set up prototypes for the guard check and dispatch functions.
247
GuardFnType =
248
FunctionType::get(Type::getVoidTy(M.getContext()),
249
{PointerType::getUnqual(M.getContext())}, false);
250
GuardFnPtrType = PointerType::get(GuardFnType, 0);
251
252
GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {
253
auto *Var = new GlobalVariable(M, GuardFnPtrType, false,
254
GlobalVariable::ExternalLinkage, nullptr,
255
GuardFnName);
256
Var->setDSOLocal(true);
257
return Var;
258
});
259
260
return true;
261
}
262
263
bool CFGuardImpl::runOnFunction(Function &F) {
264
265
// Skip modules for which CFGuard checks have been disabled.
266
if (cfguard_module_flag != 2)
267
return false;
268
269
SmallVector<CallBase *, 8> IndirectCalls;
270
271
// Iterate over the instructions to find all indirect call/invoke/callbr
272
// instructions. Make a separate list of pointers to indirect
273
// call/invoke/callbr instructions because the original instructions will be
274
// deleted as the checks are added.
275
for (BasicBlock &BB : F) {
276
for (Instruction &I : BB) {
277
auto *CB = dyn_cast<CallBase>(&I);
278
if (CB && CB->isIndirectCall() && !CB->hasFnAttr("guard_nocf")) {
279
IndirectCalls.push_back(CB);
280
CFGuardCounter++;
281
}
282
}
283
}
284
285
// If no checks are needed, return early.
286
if (IndirectCalls.empty()) {
287
return false;
288
}
289
290
// For each indirect call/invoke, add the appropriate dispatch or check.
291
if (GuardMechanism == Mechanism::Dispatch) {
292
for (CallBase *CB : IndirectCalls) {
293
insertCFGuardDispatch(CB);
294
}
295
} else {
296
for (CallBase *CB : IndirectCalls) {
297
insertCFGuardCheck(CB);
298
}
299
}
300
301
return true;
302
}
303
304
PreservedAnalyses CFGuardPass::run(Function &F, FunctionAnalysisManager &FAM) {
305
CFGuardImpl Impl(GuardMechanism);
306
bool Changed = Impl.doInitialization(*F.getParent());
307
Changed |= Impl.runOnFunction(F);
308
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
309
}
310
311
char CFGuard::ID = 0;
312
INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false)
313
314
FunctionPass *llvm::createCFGuardCheckPass() {
315
return new CFGuard(CFGuardPass::Mechanism::Check);
316
}
317
318
FunctionPass *llvm::createCFGuardDispatchPass() {
319
return new CFGuard(CFGuardPass::Mechanism::Dispatch);
320
}
321
322