LLVM 24.0.0git
CFGuard.cpp
Go to the documentation of this file.
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
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/Pass.h"
24
25using namespace llvm;
26
28
29#define DEBUG_TYPE "cfguard"
30
31STATISTIC(CFGuardCounter, "Number of Control Flow Guard checks added");
32
33constexpr StringRef GuardCheckFunctionName = "__guard_check_icall_fptr";
34constexpr StringRef GuardDispatchFunctionName = "__guard_dispatch_icall_fptr";
35
36namespace {
37
38/// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes.
39/// These checks ensure that the target address corresponds to the start of an
40/// address-taken function.
41class CFGuardImpl {
42public:
43 using Mechanism = CFGuardPass::Mechanism;
44
45 /// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
46 /// check mechanism. When the image is loaded, the loader puts the appropriate
47 /// guard check function pointer in the __guard_check_icall_fptr global
48 /// symbol. This checks that the target address is a valid address-taken
49 /// function. The address of the target function is passed to the guard check
50 /// function in an architecture-specific register (e.g. ECX on 32-bit X86,
51 /// X15 on Aarch64, and R0 on ARM). The guard check function has no return
52 /// value (if the target is invalid, the guard check funtion will raise an
53 /// error).
54 ///
55 /// For example, the following LLVM IR:
56 /// \code
57 /// %func_ptr = alloca i32 ()*, align 8
58 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
59 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
60 /// %1 = call i32 %0()
61 /// \endcode
62 ///
63 /// is transformed to:
64 /// \code
65 /// %func_ptr = alloca i32 ()*, align 8
66 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
67 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
68 /// %1 = load void (i8*)*, void (i8*)** @__guard_check_icall_fptr
69 /// %2 = bitcast i32 ()* %0 to i8*
70 /// call cfguard_checkcc void %1(i8* %2)
71 /// %3 = call i32 %0()
72 /// \endcode
73 ///
74 /// For example, the following X86 assembly code:
75 /// \code
76 /// movl $_target_func, %eax
77 /// calll *%eax
78 /// \endcode
79 ///
80 /// is transformed to:
81 /// \code
82 /// movl $_target_func, %ecx
83 /// calll *___guard_check_icall_fptr
84 /// calll *%ecx
85 /// \endcode
86 ///
87 /// \param CB indirect call to instrument.
88 void insertCFGuardCheck(CallBase *CB);
89
90 /// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
91 /// dispatch mechanism. When the image is loaded, the loader puts the
92 /// appropriate guard check function pointer in the
93 /// __guard_dispatch_icall_fptr global symbol. This checks that the target
94 /// address is a valid address-taken function and, if so, tail calls the
95 /// target. The target address is passed in an architecture-specific register
96 /// (e.g. RAX on X86_64), with all other arguments for the target function
97 /// passed as usual.
98 ///
99 /// For example, the following LLVM IR:
100 /// \code
101 /// %func_ptr = alloca i32 ()*, align 8
102 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
103 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
104 /// %1 = call i32 %0()
105 /// \endcode
106 ///
107 /// is transformed to:
108 /// \code
109 /// %func_ptr = alloca i32 ()*, align 8
110 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
111 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
112 /// %1 = load i32 ()*, i32 ()** @__guard_dispatch_icall_fptr
113 /// %2 = call i32 %1() [ "cfguardtarget"(i32 ()* %0) ]
114 /// \endcode
115 ///
116 /// For example, the following X86_64 assembly code:
117 /// \code
118 /// leaq target_func(%rip), %rax
119 /// callq *%rax
120 /// \endcode
121 ///
122 /// is transformed to:
123 /// \code
124 /// leaq target_func(%rip), %rax
125 /// callq *__guard_dispatch_icall_fptr(%rip)
126 /// \endcode
127 ///
128 /// \param CB indirect call to instrument.
129 void insertCFGuardDispatch(CallBase *CB);
130
131 bool doInitialization(Module &M);
132 bool runOnFunction(Function &F);
133
134private:
135 // Only add checks if the module has them enabled.
137 Mechanism GuardMechanism = Mechanism::Check;
138 FunctionType *GuardFnType = nullptr;
139 PointerType *GuardFnPtrType = nullptr;
140 Constant *GuardFnGlobal = nullptr;
141};
142
143class CFGuard : public FunctionPass {
144 CFGuardImpl Impl;
145
146public:
147 static char ID;
148
149 // Default constructor required for the INITIALIZE_PASS macro.
150 CFGuard() : FunctionPass(ID) {}
151
152 bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
153 bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
154};
155
156} // end anonymous namespace
157
158void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {
160 "Only applicable for Windows targets");
161 assert(CB->isIndirectCall() &&
162 "Control Flow Guard checks can only be added to indirect calls");
163
164 IRBuilder<> B(CB);
165 Value *CalledOperand = CB->getCalledOperand();
166
167 // If the indirect call is called within catchpad or cleanuppad,
168 // we need to copy "funclet" bundle of the call.
170 if (auto Bundle = CB->getOperandBundle(LLVMContext::OB_funclet))
171 Bundles.push_back(OperandBundleDef(*Bundle));
172
173 // Load the global symbol as a pointer to the check function.
174 LoadInst *GuardCheckLoad = B.CreateLoad(GuardFnPtrType, GuardFnGlobal);
175
176 // Create new call instruction. The CFGuard check should always be a call,
177 // even if the original CallBase is an Invoke or CallBr instruction.
178 CallInst *GuardCheck =
179 B.CreateCall(GuardFnType, GuardCheckLoad, {CalledOperand}, Bundles);
180
181 // Ensure that the first argument is passed in the correct register
182 // (e.g. ECX on 32-bit X86 targets).
183 GuardCheck->setCallingConv(CallingConv::CFGuard_Check);
184}
185
186void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {
188 "Only applicable for Windows targets");
189 assert(CB->isIndirectCall() &&
190 "Control Flow Guard checks can only be added to indirect calls");
191
192 IRBuilder<> B(CB);
193 Value *CalledOperand = CB->getCalledOperand();
194 Type *CalledOperandType = CalledOperand->getType();
195
196 // Load the global as a pointer to a function of the same type.
197 LoadInst *GuardDispatchLoad = B.CreateLoad(CalledOperandType, GuardFnGlobal);
198
199 // Add the original call target as a cfguardtarget operand bundle.
201 CB->getOperandBundlesAsDefs(Bundles);
202 Bundles.emplace_back("cfguardtarget", CalledOperand);
203
204 // Create a copy of the call/invoke instruction and add the new bundle.
205 assert((isa<CallInst>(CB) || isa<InvokeInst>(CB)) &&
206 "Unknown indirect call type");
207 CallBase *NewCB = CallBase::Create(CB, Bundles, CB->getIterator());
208
209 // Change the target of the call to be the guard dispatch function.
210 NewCB->setCalledOperand(GuardDispatchLoad);
211
212 // Replace the original call/invoke with the new instruction.
213 CB->replaceAllUsesWith(NewCB);
214
215 // Delete the original call/invoke.
216 CB->eraseFromParent();
217}
218
219bool CFGuardImpl::doInitialization(Module &M) {
220 // Check if this module has the cfguard flag and read its value.
221 CFGuardModuleFlag = M.getControlFlowGuardMode();
222
223 // Skip modules for which CFGuard checks have been disabled.
224 if (CFGuardModuleFlag != ControlFlowGuardMode::Enabled)
225 return false;
226
227 // Determine the guard mechanism to use.
228 ControlFlowGuardMechanism MechanismOverride =
229 ControlFlowGuardMechanism::Automatic;
231 M.getModuleFlag("cfguard-mechanism")))
232 MechanismOverride =
233 static_cast<ControlFlowGuardMechanism>(CI->getZExtValue());
234 switch (MechanismOverride) {
235 case ControlFlowGuardMechanism::Check:
236 GuardMechanism = Mechanism::Check;
237 break;
238 case ControlFlowGuardMechanism::Dispatch:
239 GuardMechanism = Mechanism::Dispatch;
240 break;
241 default:
242 // X86_64 uses dispatch; all other architectures use check.
243 GuardMechanism =
244 M.getTargetTriple().isX86_64() ? Mechanism::Dispatch : Mechanism::Check;
245 break;
246 }
247
248 // Set up prototypes for the guard check and dispatch functions.
249 GuardFnType =
250 FunctionType::get(Type::getVoidTy(M.getContext()),
251 {PointerType::getUnqual(M.getContext())}, false);
252 GuardFnPtrType = PointerType::get(M.getContext(), 0);
253
254 StringRef GuardFnName = GuardMechanism == Mechanism::Check
257 GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {
258 auto *Var = new GlobalVariable(M, GuardFnPtrType, false,
259 GlobalVariable::ExternalLinkage, nullptr,
260 GuardFnName);
261 Var->setDSOLocal(true);
262 return Var;
263 });
264
265 return true;
266}
267
268bool CFGuardImpl::runOnFunction(Function &F) {
269 // Skip modules for which CFGuard checks have been disabled.
270 if (CFGuardModuleFlag != ControlFlowGuardMode::Enabled)
271 return false;
272
273 SmallVector<CallBase *, 8> IndirectCalls;
274
275 // Iterate over the instructions to find all indirect call/invoke/callbr
276 // instructions. Make a separate list of pointers to indirect
277 // call/invoke/callbr instructions because the original instructions will be
278 // deleted as the checks are added.
279 for (BasicBlock &BB : F) {
280 for (Instruction &I : BB) {
281 auto *CB = dyn_cast<CallBase>(&I);
282 if (CB && CB->isIndirectCall() && !CB->hasFnAttr("guard_nocf")) {
283 IndirectCalls.push_back(CB);
284 CFGuardCounter++;
285 }
286 }
287 }
288
289 // If no checks are needed, return early.
290 if (IndirectCalls.empty())
291 return false;
292
293 // For each indirect call/invoke, add the appropriate dispatch or check.
294 if (GuardMechanism == Mechanism::Dispatch) {
295 for (CallBase *CB : IndirectCalls)
296 insertCFGuardDispatch(CB);
297 } else {
298 for (CallBase *CB : IndirectCalls)
299 insertCFGuardCheck(CB);
300 }
301
302 return true;
303}
304
306 CFGuardImpl Impl;
307 bool Changed = Impl.doInitialization(*F.getParent());
308 Changed |= Impl.runOnFunction(F);
310}
311
312char CFGuard::ID = 0;
313
314FunctionPass *llvm::createCFGuardPass() { return new CFGuard(); }
315
320
323 return false;
324
325 StringRef Name = GV->getName();
326 return Name == GuardCheckFunctionName || Name == GuardDispatchFunctionName;
327}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
constexpr StringRef GuardCheckFunctionName
Definition CFGuard.cpp:33
constexpr StringRef GuardDispatchFunctionName
Definition CFGuard.cpp:34
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
FunctionAnalysisManager FAM
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
Definition CFGuard.cpp:305
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
LLVM_ABI void getOperandBundlesAsDefs(SmallVectorImpl< OperandBundleDef > &Defs) const
Return the list of operand bundles attached to this instruction as a vector of OperandBundleDefs.
std::optional< OperandBundleUse > getOperandBundle(StringRef Name) const
Return an operand bundle by name, if present.
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
CallingConv::ID getCallingConv() const
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
unsigned countOperandBundlesOfType(StringRef Name) const
Return the number of operand bundles with the tag Name attached to this instruction.
Value * getCalledOperand() const
static LLVM_ABI CallBase * Create(CallBase *CB, ArrayRef< OperandBundleDef > Bundles, InsertPosition InsertPt=nullptr)
Create a clone of CB with a different set of operand bundles and insert it before InsertPt.
void setCalledOperand(Value *V)
This is an important base class in LLVM.
Definition Constant.h:44
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
LinkageTypes getLinkage() const
@ ExternalLinkage
Externally visible function.
Definition GlobalValue.h:53
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition Module.h:328
A container for an operand bundle being viewed as a set of values rather than a set of uses.
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
Definition Pass.h:126
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool isOSWindows() const
Tests whether the OS is Windows.
Definition Triple.h:778
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:548
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:314
self_iterator getIterator()
Definition ilist_node.h:123
@ CFGuard_Check
Special calling convention on Windows for calling the Control Guard Check ICall funtion.
Definition CallingConv.h:82
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
Definition Metadata.h:720
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool isCFGuardCall(const CallBase *CB)
Definition CFGuard.cpp:316
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI bool isCFGuardFunction(const GlobalValue *GV)
Definition CFGuard.cpp:321
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
ControlFlowGuardMode
Definition CodeGen.h:385
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ABI FunctionPass * createCFGuardPass()
Insert Control Flow Guard checks on indirect function calls.
Definition CFGuard.cpp:314
OperandBundleDefT< Value * > OperandBundleDef
Definition AutoUpgrade.h:34
ControlFlowGuardMechanism
Definition CodeGen.h:395
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.