Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/CFGuard/CFGuard.cpp
35266 views
//===-- CFGuard.cpp - Control Flow Guard checks -----------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file contains the IR transform to add Microsoft's Control Flow Guard10/// checks on Windows targets.11///12//===----------------------------------------------------------------------===//1314#include "llvm/Transforms/CFGuard.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/Statistic.h"17#include "llvm/IR/CallingConv.h"18#include "llvm/IR/IRBuilder.h"19#include "llvm/IR/Instruction.h"20#include "llvm/IR/Module.h"21#include "llvm/InitializePasses.h"22#include "llvm/Pass.h"23#include "llvm/TargetParser/Triple.h"2425using namespace llvm;2627using OperandBundleDef = OperandBundleDefT<Value *>;2829#define DEBUG_TYPE "cfguard"3031STATISTIC(CFGuardCounter, "Number of Control Flow Guard checks added");3233namespace {3435/// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes.36/// These checks ensure that the target address corresponds to the start of an37/// address-taken function. X86_64 targets use the Mechanism::Dispatch38/// mechanism. X86, ARM, and AArch64 targets use the Mechanism::Check machanism.39class CFGuardImpl {40public:41using Mechanism = CFGuardPass::Mechanism;4243CFGuardImpl(Mechanism M) : GuardMechanism(M) {44// Get or insert the guard check or dispatch global symbols.45switch (GuardMechanism) {46case Mechanism::Check:47GuardFnName = "__guard_check_icall_fptr";48break;49case Mechanism::Dispatch:50GuardFnName = "__guard_dispatch_icall_fptr";51break;52}53}5455/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG56/// check mechanism. When the image is loaded, the loader puts the appropriate57/// guard check function pointer in the __guard_check_icall_fptr global58/// symbol. This checks that the target address is a valid address-taken59/// function. The address of the target function is passed to the guard check60/// function in an architecture-specific register (e.g. ECX on 32-bit X86,61/// X15 on Aarch64, and R0 on ARM). The guard check function has no return62/// value (if the target is invalid, the guard check funtion will raise an63/// error).64///65/// For example, the following LLVM IR:66/// \code67/// %func_ptr = alloca i32 ()*, align 868/// store i32 ()* @target_func, i32 ()** %func_ptr, align 869/// %0 = load i32 ()*, i32 ()** %func_ptr, align 870/// %1 = call i32 %0()71/// \endcode72///73/// is transformed to:74/// \code75/// %func_ptr = alloca i32 ()*, align 876/// store i32 ()* @target_func, i32 ()** %func_ptr, align 877/// %0 = load i32 ()*, i32 ()** %func_ptr, align 878/// %1 = load void (i8*)*, void (i8*)** @__guard_check_icall_fptr79/// %2 = bitcast i32 ()* %0 to i8*80/// call cfguard_checkcc void %1(i8* %2)81/// %3 = call i32 %0()82/// \endcode83///84/// For example, the following X86 assembly code:85/// \code86/// movl $_target_func, %eax87/// calll *%eax88/// \endcode89///90/// is transformed to:91/// \code92/// movl $_target_func, %ecx93/// calll *___guard_check_icall_fptr94/// calll *%ecx95/// \endcode96///97/// \param CB indirect call to instrument.98void insertCFGuardCheck(CallBase *CB);99100/// Inserts a Control Flow Guard (CFG) check on an indirect call using the CFG101/// dispatch mechanism. When the image is loaded, the loader puts the102/// appropriate guard check function pointer in the103/// __guard_dispatch_icall_fptr global symbol. This checks that the target104/// address is a valid address-taken function and, if so, tail calls the105/// target. The target address is passed in an architecture-specific register106/// (e.g. RAX on X86_64), with all other arguments for the target function107/// passed as usual.108///109/// For example, the following LLVM IR:110/// \code111/// %func_ptr = alloca i32 ()*, align 8112/// store i32 ()* @target_func, i32 ()** %func_ptr, align 8113/// %0 = load i32 ()*, i32 ()** %func_ptr, align 8114/// %1 = call i32 %0()115/// \endcode116///117/// is transformed to:118/// \code119/// %func_ptr = alloca i32 ()*, align 8120/// store i32 ()* @target_func, i32 ()** %func_ptr, align 8121/// %0 = load i32 ()*, i32 ()** %func_ptr, align 8122/// %1 = load i32 ()*, i32 ()** @__guard_dispatch_icall_fptr123/// %2 = call i32 %1() [ "cfguardtarget"(i32 ()* %0) ]124/// \endcode125///126/// For example, the following X86_64 assembly code:127/// \code128/// leaq target_func(%rip), %rax129/// callq *%rax130/// \endcode131///132/// is transformed to:133/// \code134/// leaq target_func(%rip), %rax135/// callq *__guard_dispatch_icall_fptr(%rip)136/// \endcode137///138/// \param CB indirect call to instrument.139void insertCFGuardDispatch(CallBase *CB);140141bool doInitialization(Module &M);142bool runOnFunction(Function &F);143144private:145// Only add checks if the module has the cfguard=2 flag.146int cfguard_module_flag = 0;147StringRef GuardFnName;148Mechanism GuardMechanism = Mechanism::Check;149FunctionType *GuardFnType = nullptr;150PointerType *GuardFnPtrType = nullptr;151Constant *GuardFnGlobal = nullptr;152};153154class CFGuard : public FunctionPass {155CFGuardImpl Impl;156157public:158static char ID;159160// Default constructor required for the INITIALIZE_PASS macro.161CFGuard(CFGuardImpl::Mechanism M) : FunctionPass(ID), Impl(M) {162initializeCFGuardPass(*PassRegistry::getPassRegistry());163}164165bool doInitialization(Module &M) override { return Impl.doInitialization(M); }166bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }167};168169} // end anonymous namespace170171void CFGuardImpl::insertCFGuardCheck(CallBase *CB) {172173assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&174"Only applicable for Windows targets");175assert(CB->isIndirectCall() &&176"Control Flow Guard checks can only be added to indirect calls");177178IRBuilder<> B(CB);179Value *CalledOperand = CB->getCalledOperand();180181// If the indirect call is called within catchpad or cleanuppad,182// we need to copy "funclet" bundle of the call.183SmallVector<llvm::OperandBundleDef, 1> Bundles;184if (auto Bundle = CB->getOperandBundle(LLVMContext::OB_funclet))185Bundles.push_back(OperandBundleDef(*Bundle));186187// Load the global symbol as a pointer to the check function.188LoadInst *GuardCheckLoad = B.CreateLoad(GuardFnPtrType, GuardFnGlobal);189190// Create new call instruction. The CFGuard check should always be a call,191// even if the original CallBase is an Invoke or CallBr instruction.192CallInst *GuardCheck =193B.CreateCall(GuardFnType, GuardCheckLoad, {CalledOperand}, Bundles);194195// Ensure that the first argument is passed in the correct register196// (e.g. ECX on 32-bit X86 targets).197GuardCheck->setCallingConv(CallingConv::CFGuard_Check);198}199200void CFGuardImpl::insertCFGuardDispatch(CallBase *CB) {201202assert(Triple(CB->getModule()->getTargetTriple()).isOSWindows() &&203"Only applicable for Windows targets");204assert(CB->isIndirectCall() &&205"Control Flow Guard checks can only be added to indirect calls");206207IRBuilder<> B(CB);208Value *CalledOperand = CB->getCalledOperand();209Type *CalledOperandType = CalledOperand->getType();210211// Load the global as a pointer to a function of the same type.212LoadInst *GuardDispatchLoad = B.CreateLoad(CalledOperandType, GuardFnGlobal);213214// Add the original call target as a cfguardtarget operand bundle.215SmallVector<llvm::OperandBundleDef, 1> Bundles;216CB->getOperandBundlesAsDefs(Bundles);217Bundles.emplace_back("cfguardtarget", CalledOperand);218219// Create a copy of the call/invoke instruction and add the new bundle.220assert((isa<CallInst>(CB) || isa<InvokeInst>(CB)) &&221"Unknown indirect call type");222CallBase *NewCB = CallBase::Create(CB, Bundles, CB->getIterator());223224// Change the target of the call to be the guard dispatch function.225NewCB->setCalledOperand(GuardDispatchLoad);226227// Replace the original call/invoke with the new instruction.228CB->replaceAllUsesWith(NewCB);229230// Delete the original call/invoke.231CB->eraseFromParent();232}233234bool CFGuardImpl::doInitialization(Module &M) {235236// Check if this module has the cfguard flag and read its value.237if (auto *MD =238mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("cfguard")))239cfguard_module_flag = MD->getZExtValue();240241// Skip modules for which CFGuard checks have been disabled.242if (cfguard_module_flag != 2)243return false;244245// Set up prototypes for the guard check and dispatch functions.246GuardFnType =247FunctionType::get(Type::getVoidTy(M.getContext()),248{PointerType::getUnqual(M.getContext())}, false);249GuardFnPtrType = PointerType::get(GuardFnType, 0);250251GuardFnGlobal = M.getOrInsertGlobal(GuardFnName, GuardFnPtrType, [&] {252auto *Var = new GlobalVariable(M, GuardFnPtrType, false,253GlobalVariable::ExternalLinkage, nullptr,254GuardFnName);255Var->setDSOLocal(true);256return Var;257});258259return true;260}261262bool CFGuardImpl::runOnFunction(Function &F) {263264// Skip modules for which CFGuard checks have been disabled.265if (cfguard_module_flag != 2)266return false;267268SmallVector<CallBase *, 8> IndirectCalls;269270// Iterate over the instructions to find all indirect call/invoke/callbr271// instructions. Make a separate list of pointers to indirect272// call/invoke/callbr instructions because the original instructions will be273// deleted as the checks are added.274for (BasicBlock &BB : F) {275for (Instruction &I : BB) {276auto *CB = dyn_cast<CallBase>(&I);277if (CB && CB->isIndirectCall() && !CB->hasFnAttr("guard_nocf")) {278IndirectCalls.push_back(CB);279CFGuardCounter++;280}281}282}283284// If no checks are needed, return early.285if (IndirectCalls.empty()) {286return false;287}288289// For each indirect call/invoke, add the appropriate dispatch or check.290if (GuardMechanism == Mechanism::Dispatch) {291for (CallBase *CB : IndirectCalls) {292insertCFGuardDispatch(CB);293}294} else {295for (CallBase *CB : IndirectCalls) {296insertCFGuardCheck(CB);297}298}299300return true;301}302303PreservedAnalyses CFGuardPass::run(Function &F, FunctionAnalysisManager &FAM) {304CFGuardImpl Impl(GuardMechanism);305bool Changed = Impl.doInitialization(*F.getParent());306Changed |= Impl.runOnFunction(F);307return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();308}309310char CFGuard::ID = 0;311INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false)312313FunctionPass *llvm::createCFGuardCheckPass() {314return new CFGuard(CFGuardPass::Mechanism::Check);315}316317FunctionPass *llvm::createCFGuardDispatchPass() {318return new CFGuard(CFGuardPass::Mechanism::Dispatch);319}320321322