323 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains the IR transform to add Microsoft's Control Flow Guard11/// 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 an41/// address-taken function. X86_64 targets use the Mechanism::Dispatch42/// 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 CFG60 /// check mechanism. When the image is loaded, the loader puts the appropriate61 /// guard check function pointer in the __guard_check_icall_fptr global62 /// symbol. This checks that the target address is a valid address-taken63 /// function. The address of the target function is passed to the guard check64 /// 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 return66 /// value (if the target is invalid, the guard check funtion will raise an67 /// error).68 ///69 /// For example, the following LLVM IR:70 /// \code71 /// %func_ptr = alloca i32 ()*, align 872 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 873 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 874 /// %1 = call i32 %0()75 /// \endcode76 ///77 /// is transformed to:78 /// \code79 /// %func_ptr = alloca i32 ()*, align 880 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 881 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 882 /// %1 = load void (i8*)*, void (i8*)** @__guard_check_icall_fptr83 /// %2 = bitcast i32 ()* %0 to i8*84 /// call cfguard_checkcc void %1(i8* %2)85 /// %3 = call i32 %0()86 /// \endcode87 ///88 /// For example, the following X86 assembly code:89 /// \code90 /// movl $_target_func, %eax91 /// calll *%eax92 /// \endcode93 ///94 /// is transformed to:95 /// \code96 /// movl $_target_func, %ecx97 /// calll *___guard_check_icall_fptr98 /// calll *%ecx99 /// \endcode100 ///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 CFG105 /// dispatch mechanism. When the image is loaded, the loader puts the106 /// appropriate guard check function pointer in the107 /// __guard_dispatch_icall_fptr global symbol. This checks that the target108 /// address is a valid address-taken function and, if so, tail calls the109 /// target. The target address is passed in an architecture-specific register110 /// (e.g. RAX on X86_64), with all other arguments for the target function111 /// passed as usual.112 ///113 /// For example, the following LLVM IR:114 /// \code115 /// %func_ptr = alloca i32 ()*, align 8116 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8117 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8118 /// %1 = call i32 %0()119 /// \endcode120 ///121 /// is transformed to:122 /// \code123 /// %func_ptr = alloca i32 ()*, align 8124 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8125 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8126 /// %1 = load i32 ()*, i32 ()** @__guard_dispatch_icall_fptr127 /// %2 = call i32 %1() [ "cfguardtarget"(i32 ()* %0) ]128 /// \endcode129 ///130 /// For example, the following X86_64 assembly code:131 /// \code132 /// leaq target_func(%rip), %rax133 /// callq *%rax134 /// \endcode135 ///136 /// is transformed to:137 /// \code138 /// leaq target_func(%rip), %rax139 /// callq *__guard_dispatch_icall_fptr(%rip)140 /// \endcode141 ///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 the cfguard=2 flag.150 int CFGuardModuleFlag = 0;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 namespace172 173void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {174 assert(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 register197 // (e.g. ECX on 32-bit X86 targets).198 GuardCheck->setCallingConv(CallingConv::CFGuard_Check);199}200 201void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {202 assert(CB->getModule()->getTargetTriple().isOSWindows() &&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.215 SmallVector<llvm::OperandBundleDef, 1> Bundles;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 if (auto *MD =237 mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("cfguard")))238 CFGuardModuleFlag = MD->getZExtValue();239 240 // Skip modules for which CFGuard checks have been disabled.241 if (CFGuardModuleFlag != 2)242 return false;243 244 // Set up prototypes for the guard check and dispatch functions.245 GuardFnType =246 FunctionType::get(Type::getVoidTy(M.getContext()),247 {PointerType::getUnqual(M.getContext())}, false);248 GuardFnPtrType = PointerType::get(M.getContext(), 0);249 250 GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {251 auto *Var = new GlobalVariable(M, GuardFnPtrType, false,252 GlobalVariable::ExternalLinkage, nullptr,253 GuardFnName);254 Var->setDSOLocal(true);255 return Var;256 });257 258 return true;259}260 261bool CFGuardImpl::runOnFunction(Function &F) {262 // Skip modules for which CFGuard checks have been disabled.263 if (CFGuardModuleFlag != 2)264 return false;265 266 SmallVector<CallBase *, 8> IndirectCalls;267 268 // Iterate over the instructions to find all indirect call/invoke/callbr269 // instructions. Make a separate list of pointers to indirect270 // call/invoke/callbr instructions because the original instructions will be271 // deleted as the checks are added.272 for (BasicBlock &BB : F) {273 for (Instruction &I : BB) {274 auto *CB = dyn_cast<CallBase>(&I);275 if (CB && CB->isIndirectCall() && !CB->hasFnAttr("guard_nocf")) {276 IndirectCalls.push_back(CB);277 CFGuardCounter++;278 }279 }280 }281 282 // If no checks are needed, return early.283 if (IndirectCalls.empty())284 return false;285 286 // For each indirect call/invoke, add the appropriate dispatch or check.287 if (GuardMechanism == Mechanism::Dispatch) {288 for (CallBase *CB : IndirectCalls)289 insertCFGuardDispatch(CB);290 } else {291 for (CallBase *CB : IndirectCalls)292 insertCFGuardCheck(CB);293 }294 295 return true;296}297 298PreservedAnalyses CFGuardPass::run(Function &F, FunctionAnalysisManager &FAM) {299 CFGuardImpl Impl(GuardMechanism);300 bool Changed = Impl.doInitialization(*F.getParent());301 Changed |= Impl.runOnFunction(F);302 return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();303}304 305char CFGuard::ID = 0;306INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false)307 308FunctionPass *llvm::createCFGuardCheckPass() {309 return new CFGuard(CFGuardPass::Mechanism::Check);310}311 312FunctionPass *llvm::createCFGuardDispatchPass() {313 return new CFGuard(CFGuardPass::Mechanism::Dispatch);314}315 316bool llvm::isCFGuardFunction(const GlobalValue *GV) {317 if (GV->getLinkage() != GlobalValue::ExternalLinkage)318 return false;319 320 StringRef Name = GV->getName();321 return Name == GuardCheckFunctionName || Name == GuardDispatchFunctionName;322}323