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