LLVM 23.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"
23#include "llvm/Pass.h"
25
26using namespace llvm;
27
29
30#define DEBUG_TYPE "cfguard"
31
32STATISTIC(CFGuardCounter, "Number of Control Flow Guard checks added");
33
34constexpr StringRef GuardCheckFunctionName = "__guard_check_icall_fptr";
35constexpr StringRef GuardDispatchFunctionName = "__guard_dispatch_icall_fptr";
36
37namespace {
38
39/// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes.
40/// These checks ensure that the target address corresponds to the start of an
41/// address-taken function. X86_64 targets use the Mechanism::Dispatch
42/// mechanism. X86, ARM, and AArch64 targets use the Mechanism::Check machanism.
43class CFGuardImpl {
44public:
45 using Mechanism = CFGuardPass::Mechanism;
46
47 CFGuardImpl(Mechanism M) : GuardMechanism(M) {
48 // Get or insert the guard check or dispatch global symbols.
49 switch (GuardMechanism) {
50 case Mechanism::Check:
51 GuardFnName = GuardCheckFunctionName;
52 break;
53 case Mechanism::Dispatch:
54 GuardFnName = GuardDispatchFunctionName;
55 break;
56 }
57 }
58
59 /// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
60 /// check mechanism. When the image is loaded, the loader puts the appropriate
61 /// guard check function pointer in the __guard_check_icall_fptr global
62 /// symbol. This checks that the target address is a valid address-taken
63 /// function. The address of the target function is passed to the guard check
64 /// function in an architecture-specific register (e.g. ECX on 32-bit X86,
65 /// X15 on Aarch64, and R0 on ARM). The guard check function has no return
66 /// value (if the target is invalid, the guard check funtion will raise an
67 /// error).
68 ///
69 /// For example, the following LLVM IR:
70 /// \code
71 /// %func_ptr = alloca i32 ()*, align 8
72 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
73 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
74 /// %1 = call i32 %0()
75 /// \endcode
76 ///
77 /// is transformed to:
78 /// \code
79 /// %func_ptr = alloca i32 ()*, align 8
80 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
81 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
82 /// %1 = load void (i8*)*, void (i8*)** @__guard_check_icall_fptr
83 /// %2 = bitcast i32 ()* %0 to i8*
84 /// call cfguard_checkcc void %1(i8* %2)
85 /// %3 = call i32 %0()
86 /// \endcode
87 ///
88 /// For example, the following X86 assembly code:
89 /// \code
90 /// movl $_target_func, %eax
91 /// calll *%eax
92 /// \endcode
93 ///
94 /// is transformed to:
95 /// \code
96 /// movl $_target_func, %ecx
97 /// calll *___guard_check_icall_fptr
98 /// calll *%ecx
99 /// \endcode
100 ///
101 /// \param CB indirect call to instrument.
102 void insertCFGuardCheck(CallBase *CB);
103
104 /// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG
105 /// dispatch mechanism. When the image is loaded, the loader puts the
106 /// appropriate guard check function pointer in the
107 /// __guard_dispatch_icall_fptr global symbol. This checks that the target
108 /// address is a valid address-taken function and, if so, tail calls the
109 /// target. The target address is passed in an architecture-specific register
110 /// (e.g. RAX on X86_64), with all other arguments for the target function
111 /// passed as usual.
112 ///
113 /// For example, the following LLVM IR:
114 /// \code
115 /// %func_ptr = alloca i32 ()*, align 8
116 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
117 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
118 /// %1 = call i32 %0()
119 /// \endcode
120 ///
121 /// is transformed to:
122 /// \code
123 /// %func_ptr = alloca i32 ()*, align 8
124 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8
125 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8
126 /// %1 = load i32 ()*, i32 ()** @__guard_dispatch_icall_fptr
127 /// %2 = call i32 %1() [ "cfguardtarget"(i32 ()* %0) ]
128 /// \endcode
129 ///
130 /// For example, the following X86_64 assembly code:
131 /// \code
132 /// leaq target_func(%rip), %rax
133 /// callq *%rax
134 /// \endcode
135 ///
136 /// is transformed to:
137 /// \code
138 /// leaq target_func(%rip), %rax
139 /// callq *__guard_dispatch_icall_fptr(%rip)
140 /// \endcode
141 ///
142 /// \param CB indirect call to instrument.
143 void insertCFGuardDispatch(CallBase *CB);
144
145 bool doInitialization(Module &M);
146 bool runOnFunction(Function &F);
147
148private:
149 // Only add checks if the module has them enabled.
151 StringRef GuardFnName;
152 Mechanism GuardMechanism = Mechanism::Check;
153 FunctionType *GuardFnType = nullptr;
154 PointerType *GuardFnPtrType = nullptr;
155 Constant *GuardFnGlobal = nullptr;
156};
157
158class CFGuard : public FunctionPass {
159 CFGuardImpl Impl;
160
161public:
162 static char ID;
163
164 // Default constructor required for the INITIALIZE_PASS macro.
165 CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {}
166
167 bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
168 bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
169};
170
171} // end anonymous namespace
172
173void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {
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.
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
201void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {
203 "Only applicable for Windows targets");
204 assert(CB->isIndirectCall() &&
205 "Control Flow Guard checks can only be added to indirect calls");
206
207 IRBuilder<> B(CB);
208 Value *CalledOperand = CB->getCalledOperand();
209 Type *CalledOperandType = CalledOperand->getType();
210
211 // Load the global as a pointer to a function of the same type.
212 LoadInst *GuardDispatchLoad = B.CreateLoad(CalledOperandType, GuardFnGlobal);
213
214 // Add the original call target as a cfguardtarget operand bundle.
216 CB->getOperandBundlesAsDefs(Bundles);
217 Bundles.emplace_back("cfguardtarget", CalledOperand);
218
219 // Create a copy of the call/invoke instruction and add the new bundle.
220 assert((isa<CallInst>(CB) || isa<InvokeInst>(CB)) &&
221 "Unknown indirect call type");
222 CallBase *NewCB = CallBase::Create(CB, Bundles, CB->getIterator());
223
224 // Change the target of the call to be the guard dispatch function.
225 NewCB->setCalledOperand(GuardDispatchLoad);
226
227 // Replace the original call/invoke with the new instruction.
228 CB->replaceAllUsesWith(NewCB);
229
230 // Delete the original call/invoke.
231 CB->eraseFromParent();
232}
233
234bool CFGuardImpl::doInitialization(Module &M) {
235 // Check if this module has the cfguard flag and read its value.
236 CFGuardModuleFlag = M.getControlFlowGuardMode();
237
238 // Skip modules for which CFGuard checks have been disabled.
239 if (CFGuardModuleFlag != ControlFlowGuardMode::Enabled)
240 return false;
241
242 // Set up prototypes for the guard check and dispatch functions.
243 GuardFnType =
244 FunctionType::get(Type::getVoidTy(M.getContext()),
245 {PointerType::getUnqual(M.getContext())}, false);
246 GuardFnPtrType = PointerType::get(M.getContext(), 0);
247
248 GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {
249 auto *Var = new GlobalVariable(M, GuardFnPtrType, false,
250 GlobalVariable::ExternalLinkage, nullptr,
251 GuardFnName);
252 Var->setDSOLocal(true);
253 return Var;
254 });
255
256 return true;
257}
258
259bool CFGuardImpl::runOnFunction(Function &F) {
260 // Skip modules for which CFGuard checks have been disabled.
261 if (CFGuardModuleFlag != ControlFlowGuardMode::Enabled)
262 return false;
263
264 SmallVector<CallBase *, 8> IndirectCalls;
265
266 // Iterate over the instructions to find all indirect call/invoke/callbr
267 // instructions. Make a separate list of pointers to indirect
268 // call/invoke/callbr instructions because the original instructions will be
269 // deleted as the checks are added.
270 for (BasicBlock &BB : F) {
271 for (Instruction &I : BB) {
272 auto *CB = dyn_cast<CallBase>(&I);
273 if (CB && CB->isIndirectCall() && !CB->hasFnAttr("guard_nocf")) {
274 IndirectCalls.push_back(CB);
275 CFGuardCounter++;
276 }
277 }
278 }
279
280 // If no checks are needed, return early.
281 if (IndirectCalls.empty())
282 return false;
283
284 // For each indirect call/invoke, add the appropriate dispatch or check.
285 if (GuardMechanism == Mechanism::Dispatch) {
286 for (CallBase *CB : IndirectCalls)
287 insertCFGuardDispatch(CB);
288 } else {
289 for (CallBase *CB : IndirectCalls)
290 insertCFGuardCheck(CB);
291 }
292
293 return true;
294}
295
297 CFGuardImpl Impl(GuardMechanism);
298 bool Changed = Impl.doInitialization(*F.getParent());
299 Changed |= Impl.runOnFunction(F);
301}
302
303char CFGuard::ID = 0;
304INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false)
305
309
313
318
321 return false;
322
323 StringRef Name = GV->getName();
324 return Name == GuardCheckFunctionName || Name == GuardDispatchFunctionName;
325}
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:34
constexpr StringRef GuardDispatchFunctionName
Definition CFGuard.cpp:35
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
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
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:296
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:43
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
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:67
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition Module.h:281
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:128
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)
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
bool isOSWindows() const
Tests whether the OS is Windows.
Definition Triple.h:700
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
self_iterator getIterator()
Definition ilist_node.h:123
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ CFGuard_Check
Special calling convention on Windows for calling the Control Guard Check ICall funtion.
Definition CallingConv.h:82
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
LLVM_ABI bool isCFGuardCall(const CallBase *CB)
Definition CFGuard.cpp:314
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:319
LLVM_ABI FunctionPass * createCFGuardDispatchPass()
Insert Control FLow Guard dispatches on indirect function calls.
Definition CFGuard.cpp:310
ControlFlowGuardMode
Definition CodeGen.h:176
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
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
OperandBundleDefT< Value * > OperandBundleDef
Definition AutoUpgrade.h:34
LLVM_ABI FunctionPass * createCFGuardCheckPass()
Insert Control FLow Guard checks on indirect function calls.
Definition CFGuard.cpp:306
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.