xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/CFGuard/CFGuard.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
CFGuardImpl(Mechanism M)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.
CFGuard(CFGuardImpl::Mechanism M)162   CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {
163     initializeCFGuardPass(*PassRegistry::getPassRegistry());
164   }
165 
doInitialization(Module & M)166   bool doInitialization(Module &M) override { return Impl.doInitialization(M); }
runOnFunction(Function & F)167   bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }
168 };
169 
170 } // end anonymous namespace
171 
insertCFGuardCheck(CallBase * CB)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 
insertCFGuardDispatch(CallBase * CB)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 
doInitialization(Module & M)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 
runOnFunction(Function & F)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 
run(Function & F,FunctionAnalysisManager & FAM)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 
createCFGuardCheckPass()314 FunctionPass *llvm::createCFGuardCheckPass() {
315   return new CFGuard(CFGuardPass::Mechanism::Check);
316 }
317 
createCFGuardDispatchPass()318 FunctionPass *llvm::createCFGuardDispatchPass() {
319   return new CFGuard(CFGuardPass::Mechanism::Dispatch);
320 }
321