Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/X86IndirectBranchTracking.cpp
35269 views
//===---- X86IndirectBranchTracking.cpp - Enables CET IBT mechanism -------===//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// This file defines a pass that enables Indirect Branch Tracking (IBT) as part9// of Control-Flow Enforcement Technology (CET).10// The pass adds ENDBR (End Branch) machine instructions at the beginning of11// each basic block or function that is referenced by an indrect jump/call12// instruction.13// The ENDBR instructions have a NOP encoding and as such are ignored in14// targets that do not support CET IBT mechanism.15//===----------------------------------------------------------------------===//1617#include "X86.h"18#include "X86InstrInfo.h"19#include "X86Subtarget.h"20#include "X86TargetMachine.h"21#include "llvm/ADT/Statistic.h"22#include "llvm/CodeGen/MachineFunctionPass.h"23#include "llvm/CodeGen/MachineInstrBuilder.h"24#include "llvm/CodeGen/MachineModuleInfo.h"25#include "llvm/IR/Module.h"2627using namespace llvm;2829#define DEBUG_TYPE "x86-indirect-branch-tracking"3031cl::opt<bool> IndirectBranchTracking(32"x86-indirect-branch-tracking", cl::init(false), cl::Hidden,33cl::desc("Enable X86 indirect branch tracking pass."));3435STATISTIC(NumEndBranchAdded, "Number of ENDBR instructions added");3637namespace {38class X86IndirectBranchTrackingPass : public MachineFunctionPass {39public:40X86IndirectBranchTrackingPass() : MachineFunctionPass(ID) {}4142StringRef getPassName() const override {43return "X86 Indirect Branch Tracking";44}4546bool runOnMachineFunction(MachineFunction &MF) override;4748private:49static char ID;5051/// Machine instruction info used throughout the class.52const X86InstrInfo *TII = nullptr;5354/// Endbr opcode for the current machine function.55unsigned int EndbrOpcode = 0;5657/// Adds a new ENDBR instruction to the beginning of the MBB.58/// The function will not add it if already exists.59/// It will add ENDBR32 or ENDBR64 opcode, depending on the target.60/// \returns true if the ENDBR was added and false otherwise.61bool addENDBR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const;62};6364} // end anonymous namespace6566char X86IndirectBranchTrackingPass::ID = 0;6768FunctionPass *llvm::createX86IndirectBranchTrackingPass() {69return new X86IndirectBranchTrackingPass();70}7172bool X86IndirectBranchTrackingPass::addENDBR(73MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const {74assert(TII && "Target instruction info was not initialized");75assert((X86::ENDBR64 == EndbrOpcode || X86::ENDBR32 == EndbrOpcode) &&76"Unexpected Endbr opcode");7778// If the MBB/I is empty or the current instruction is not ENDBR,79// insert ENDBR instruction to the location of I.80if (I == MBB.end() || I->getOpcode() != EndbrOpcode) {81BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(EndbrOpcode));82++NumEndBranchAdded;83return true;84}85return false;86}8788static bool IsCallReturnTwice(llvm::MachineOperand &MOp) {89if (!MOp.isGlobal())90return false;91auto *CalleeFn = dyn_cast<Function>(MOp.getGlobal());92if (!CalleeFn)93return false;94AttributeList Attrs = CalleeFn->getAttributes();95return Attrs.hasFnAttr(Attribute::ReturnsTwice);96}9798// Checks if function should have an ENDBR in its prologue99static bool needsPrologueENDBR(MachineFunction &MF, const Module *M) {100Function &F = MF.getFunction();101102if (F.doesNoCfCheck())103return false;104105switch (MF.getTarget().getCodeModel()) {106// Large code model functions always reachable through indirect calls.107case CodeModel::Large:108return true;109// Address taken or externally linked functions may be reachable.110default:111return (F.hasAddressTaken() || !F.hasLocalLinkage());112}113}114115bool X86IndirectBranchTrackingPass::runOnMachineFunction(MachineFunction &MF) {116const X86Subtarget &SubTarget = MF.getSubtarget<X86Subtarget>();117118const Module *M = MF.getFunction().getParent();119// Check that the cf-protection-branch is enabled.120Metadata *isCFProtectionSupported = M->getModuleFlag("cf-protection-branch");121122// NB: We need to enable IBT in jitted code if JIT compiler is CET123// enabled.124const X86TargetMachine *TM =125static_cast<const X86TargetMachine *>(&MF.getTarget());126#ifdef __CET__127bool isJITwithCET = TM->isJIT();128#else129bool isJITwithCET = false;130#endif131if (!isCFProtectionSupported && !IndirectBranchTracking && !isJITwithCET)132return false;133134// True if the current MF was changed and false otherwise.135bool Changed = false;136137TII = SubTarget.getInstrInfo();138EndbrOpcode = SubTarget.is64Bit() ? X86::ENDBR64 : X86::ENDBR32;139140// If function is reachable indirectly, mark the first BB with ENDBR.141if (needsPrologueENDBR(MF, M)) {142auto MBB = MF.begin();143Changed |= addENDBR(*MBB, MBB->begin());144}145146for (auto &MBB : MF) {147// Find all basic blocks that their address was taken (for example148// in the case of indirect jump) and add ENDBR instruction.149if (MBB.hasAddressTaken())150Changed |= addENDBR(MBB, MBB.begin());151152for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {153if (I->isCall() && I->getNumOperands() > 0 &&154IsCallReturnTwice(I->getOperand(0))) {155Changed |= addENDBR(MBB, std::next(I));156}157}158159// Exception handle may indirectly jump to catch pad, So we should add160// ENDBR before catch pad instructions. For SjLj exception model, it will161// create a new BB(new landingpad) indirectly jump to the old landingpad.162if (TM->Options.ExceptionModel == ExceptionHandling::SjLj) {163for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {164// New Landingpad BB without EHLabel.165if (MBB.isEHPad()) {166if (I->isDebugInstr())167continue;168Changed |= addENDBR(MBB, I);169break;170} else if (I->isEHLabel()) {171// Old Landingpad BB (is not Landingpad now) with172// the old "callee" EHLabel.173MCSymbol *Sym = I->getOperand(0).getMCSymbol();174if (!MF.hasCallSiteLandingPad(Sym))175continue;176Changed |= addENDBR(MBB, std::next(I));177break;178}179}180} else if (MBB.isEHPad()){181for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {182if (!I->isEHLabel())183continue;184Changed |= addENDBR(MBB, std::next(I));185break;186}187}188}189return Changed;190}191192193