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