10b57cec5SDimitry Andric //===---- X86IndirectBranchTracking.cpp - Enables CET IBT mechanism -------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines a pass that enables Indirect Branch Tracking (IBT) as part 100b57cec5SDimitry Andric // of Control-Flow Enforcement Technology (CET). 110b57cec5SDimitry Andric // The pass adds ENDBR (End Branch) machine instructions at the beginning of 120b57cec5SDimitry Andric // each basic block or function that is referenced by an indrect jump/call 130b57cec5SDimitry Andric // instruction. 140b57cec5SDimitry Andric // The ENDBR instructions have a NOP encoding and as such are ignored in 150b57cec5SDimitry Andric // targets that do not support CET IBT mechanism. 160b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "X86.h" 190b57cec5SDimitry Andric #include "X86InstrInfo.h" 200b57cec5SDimitry Andric #include "X86Subtarget.h" 210b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #define DEBUG_TYPE "x86-indirect-branch-tracking" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric static cl::opt<bool> IndirectBranchTracking( 310b57cec5SDimitry Andric "x86-indirect-branch-tracking", cl::init(false), cl::Hidden, 320b57cec5SDimitry Andric cl::desc("Enable X86 indirect branch tracking pass.")); 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric STATISTIC(NumEndBranchAdded, "Number of ENDBR instructions added"); 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric namespace { 370b57cec5SDimitry Andric class X86IndirectBranchTrackingPass : public MachineFunctionPass { 380b57cec5SDimitry Andric public: 390b57cec5SDimitry Andric X86IndirectBranchTrackingPass() : MachineFunctionPass(ID) {} 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric StringRef getPassName() const override { 420b57cec5SDimitry Andric return "X86 Indirect Branch Tracking"; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric private: 480b57cec5SDimitry Andric static char ID; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric /// Machine instruction info used throughout the class. 510b57cec5SDimitry Andric const X86InstrInfo *TII; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric /// Endbr opcode for the current machine function. 540b57cec5SDimitry Andric unsigned int EndbrOpcode; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric /// Adds a new ENDBR instruction to the begining of the MBB. 570b57cec5SDimitry Andric /// The function will not add it if already exists. 580b57cec5SDimitry Andric /// It will add ENDBR32 or ENDBR64 opcode, depending on the target. 590b57cec5SDimitry Andric /// \returns true if the ENDBR was added and false otherwise. 600b57cec5SDimitry Andric bool addENDBR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; 610b57cec5SDimitry Andric }; 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric } // end anonymous namespace 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric char X86IndirectBranchTrackingPass::ID = 0; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric FunctionPass *llvm::createX86IndirectBranchTrackingPass() { 680b57cec5SDimitry Andric return new X86IndirectBranchTrackingPass(); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric bool X86IndirectBranchTrackingPass::addENDBR( 720b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { 730b57cec5SDimitry Andric assert(TII && "Target instruction info was not initialized"); 740b57cec5SDimitry Andric assert((X86::ENDBR64 == EndbrOpcode || X86::ENDBR32 == EndbrOpcode) && 750b57cec5SDimitry Andric "Unexpected Endbr opcode"); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // If the MBB/I is empty or the current instruction is not ENDBR, 780b57cec5SDimitry Andric // insert ENDBR instruction to the location of I. 790b57cec5SDimitry Andric if (I == MBB.end() || I->getOpcode() != EndbrOpcode) { 800b57cec5SDimitry Andric BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(EndbrOpcode)); 810b57cec5SDimitry Andric ++NumEndBranchAdded; 820b57cec5SDimitry Andric return true; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric return false; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 87*8bcb0991SDimitry Andric static bool IsCallReturnTwice(llvm::MachineOperand &MOp) { 880b57cec5SDimitry Andric if (!MOp.isGlobal()) 890b57cec5SDimitry Andric return false; 900b57cec5SDimitry Andric auto *CalleeFn = dyn_cast<Function>(MOp.getGlobal()); 910b57cec5SDimitry Andric if (!CalleeFn) 920b57cec5SDimitry Andric return false; 930b57cec5SDimitry Andric AttributeList Attrs = CalleeFn->getAttributes(); 940b57cec5SDimitry Andric if (Attrs.hasAttribute(AttributeList::FunctionIndex, Attribute::ReturnsTwice)) 950b57cec5SDimitry Andric return true; 960b57cec5SDimitry Andric return false; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric bool X86IndirectBranchTrackingPass::runOnMachineFunction(MachineFunction &MF) { 1000b57cec5SDimitry Andric const X86Subtarget &SubTarget = MF.getSubtarget<X86Subtarget>(); 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // Check that the cf-protection-branch is enabled. 1030b57cec5SDimitry Andric Metadata *isCFProtectionSupported = 1040b57cec5SDimitry Andric MF.getMMI().getModule()->getModuleFlag("cf-protection-branch"); 1050b57cec5SDimitry Andric if (!isCFProtectionSupported && !IndirectBranchTracking) 1060b57cec5SDimitry Andric return false; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // True if the current MF was changed and false otherwise. 1090b57cec5SDimitry Andric bool Changed = false; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric TII = SubTarget.getInstrInfo(); 1120b57cec5SDimitry Andric EndbrOpcode = SubTarget.is64Bit() ? X86::ENDBR64 : X86::ENDBR32; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric // Non-internal function or function whose address was taken, can be 1150b57cec5SDimitry Andric // accessed through indirect calls. Mark the first BB with ENDBR instruction 1160b57cec5SDimitry Andric // unless nocf_check attribute is used. 1170b57cec5SDimitry Andric if ((MF.getFunction().hasAddressTaken() || 1180b57cec5SDimitry Andric !MF.getFunction().hasLocalLinkage()) && 1190b57cec5SDimitry Andric !MF.getFunction().doesNoCfCheck()) { 1200b57cec5SDimitry Andric auto MBB = MF.begin(); 1210b57cec5SDimitry Andric Changed |= addENDBR(*MBB, MBB->begin()); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric for (auto &MBB : MF) { 1250b57cec5SDimitry Andric // Find all basic blocks that their address was taken (for example 1260b57cec5SDimitry Andric // in the case of indirect jump) and add ENDBR instruction. 1270b57cec5SDimitry Andric if (MBB.hasAddressTaken()) 1280b57cec5SDimitry Andric Changed |= addENDBR(MBB, MBB.begin()); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { 1310b57cec5SDimitry Andric if (!I->isCall()) 1320b57cec5SDimitry Andric continue; 1330b57cec5SDimitry Andric if (IsCallReturnTwice(I->getOperand(0))) 1340b57cec5SDimitry Andric Changed |= addENDBR(MBB, std::next(I)); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric return Changed; 1380b57cec5SDimitry Andric } 139