14824e7fdSDimitry Andric //===-- ARMBranchTargets.cpp -- Harden code using v8.1-M BTI extension -----==// 24824e7fdSDimitry Andric // 34824e7fdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44824e7fdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 54824e7fdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64824e7fdSDimitry Andric // 74824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 84824e7fdSDimitry Andric // 94824e7fdSDimitry Andric // This pass inserts BTI instructions at the start of every function and basic 104824e7fdSDimitry Andric // block which could be indirectly called. The hardware will (when enabled) 114824e7fdSDimitry Andric // trap when an indirect branch or call instruction targets an instruction 124824e7fdSDimitry Andric // which is not a valid BTI instruction. This is intended to guard against 134824e7fdSDimitry Andric // control-flow hijacking attacks. 144824e7fdSDimitry Andric // 154824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 164824e7fdSDimitry Andric 174824e7fdSDimitry Andric #include "ARM.h" 184824e7fdSDimitry Andric #include "ARMInstrInfo.h" 194824e7fdSDimitry Andric #include "ARMMachineFunctionInfo.h" 204824e7fdSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 214824e7fdSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 224824e7fdSDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h" 234824e7fdSDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 244824e7fdSDimitry Andric #include "llvm/Support/Debug.h" 254824e7fdSDimitry Andric 264824e7fdSDimitry Andric using namespace llvm; 274824e7fdSDimitry Andric 284824e7fdSDimitry Andric #define DEBUG_TYPE "arm-branch-targets" 294824e7fdSDimitry Andric #define ARM_BRANCH_TARGETS_NAME "ARM Branch Targets" 304824e7fdSDimitry Andric 314824e7fdSDimitry Andric namespace { 324824e7fdSDimitry Andric class ARMBranchTargets : public MachineFunctionPass { 334824e7fdSDimitry Andric public: 344824e7fdSDimitry Andric static char ID; 354824e7fdSDimitry Andric ARMBranchTargets() : MachineFunctionPass(ID) {} 364824e7fdSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 374824e7fdSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 384824e7fdSDimitry Andric StringRef getPassName() const override { return ARM_BRANCH_TARGETS_NAME; } 394824e7fdSDimitry Andric 404824e7fdSDimitry Andric private: 414824e7fdSDimitry Andric void addBTI(const ARMInstrInfo &TII, MachineBasicBlock &MBB, bool IsFirstBB); 424824e7fdSDimitry Andric }; 434824e7fdSDimitry Andric } // end anonymous namespace 444824e7fdSDimitry Andric 454824e7fdSDimitry Andric char ARMBranchTargets::ID = 0; 464824e7fdSDimitry Andric 474824e7fdSDimitry Andric INITIALIZE_PASS(ARMBranchTargets, "arm-branch-targets", ARM_BRANCH_TARGETS_NAME, 484824e7fdSDimitry Andric false, false) 494824e7fdSDimitry Andric 504824e7fdSDimitry Andric void ARMBranchTargets::getAnalysisUsage(AnalysisUsage &AU) const { 514824e7fdSDimitry Andric AU.setPreservesCFG(); 524824e7fdSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 534824e7fdSDimitry Andric } 544824e7fdSDimitry Andric 554824e7fdSDimitry Andric FunctionPass *llvm::createARMBranchTargetsPass() { 564824e7fdSDimitry Andric return new ARMBranchTargets(); 574824e7fdSDimitry Andric } 584824e7fdSDimitry Andric 594824e7fdSDimitry Andric bool ARMBranchTargets::runOnMachineFunction(MachineFunction &MF) { 604824e7fdSDimitry Andric if (!MF.getInfo<ARMFunctionInfo>()->branchTargetEnforcement()) 614824e7fdSDimitry Andric return false; 624824e7fdSDimitry Andric 634824e7fdSDimitry Andric LLVM_DEBUG(dbgs() << "********** ARM Branch Targets **********\n" 644824e7fdSDimitry Andric << "********** Function: " << MF.getName() << '\n'); 654824e7fdSDimitry Andric const ARMInstrInfo &TII = 664824e7fdSDimitry Andric *static_cast<const ARMInstrInfo *>(MF.getSubtarget().getInstrInfo()); 674824e7fdSDimitry Andric 684824e7fdSDimitry Andric // LLVM does not consider basic blocks which are the targets of jump tables 694824e7fdSDimitry Andric // to be address-taken (the address can't escape anywhere else), but they are 704824e7fdSDimitry Andric // used for indirect branches, so need BTI instructions. 714824e7fdSDimitry Andric SmallPtrSet<const MachineBasicBlock *, 8> JumpTableTargets; 724824e7fdSDimitry Andric if (const MachineJumpTableInfo *JTI = MF.getJumpTableInfo()) 734824e7fdSDimitry Andric for (const MachineJumpTableEntry &JTE : JTI->getJumpTables()) 744824e7fdSDimitry Andric for (const MachineBasicBlock *MBB : JTE.MBBs) 754824e7fdSDimitry Andric JumpTableTargets.insert(MBB); 764824e7fdSDimitry Andric 774824e7fdSDimitry Andric bool MadeChange = false; 784824e7fdSDimitry Andric for (MachineBasicBlock &MBB : MF) { 794824e7fdSDimitry Andric bool NeedBTI = false; 804824e7fdSDimitry Andric bool IsFirstBB = &MBB == &MF.front(); 814824e7fdSDimitry Andric 824824e7fdSDimitry Andric // Every function can potentially be called indirectly (even if it has 834824e7fdSDimitry Andric // static linkage, due to linker-generated veneers). 844824e7fdSDimitry Andric if (IsFirstBB) 854824e7fdSDimitry Andric NeedBTI = true; 864824e7fdSDimitry Andric 874824e7fdSDimitry Andric // If the block itself is address-taken, or is an exception landing pad, it 884824e7fdSDimitry Andric // could be indirectly branched to. 894824e7fdSDimitry Andric if (MBB.hasAddressTaken() || MBB.isEHPad() || JumpTableTargets.count(&MBB)) 904824e7fdSDimitry Andric NeedBTI = true; 914824e7fdSDimitry Andric 924824e7fdSDimitry Andric if (NeedBTI) { 934824e7fdSDimitry Andric addBTI(TII, MBB, IsFirstBB); 944824e7fdSDimitry Andric MadeChange = true; 954824e7fdSDimitry Andric } 964824e7fdSDimitry Andric } 974824e7fdSDimitry Andric 984824e7fdSDimitry Andric return MadeChange; 994824e7fdSDimitry Andric } 1004824e7fdSDimitry Andric 1014824e7fdSDimitry Andric /// Insert a BTI/PACBTI instruction into a given basic block \c MBB. If 1024824e7fdSDimitry Andric /// \c IsFirstBB is true (meaning that this is the first BB in a function) try 1034824e7fdSDimitry Andric /// to find a PAC instruction and replace it with PACBTI. Otherwise just insert 1044824e7fdSDimitry Andric /// a BTI instruction. 1054824e7fdSDimitry Andric /// The point of insertion is in the beginning of the BB, immediately after meta 1064824e7fdSDimitry Andric /// instructions (such labels in exception handling landing pads). 1074824e7fdSDimitry Andric void ARMBranchTargets::addBTI(const ARMInstrInfo &TII, MachineBasicBlock &MBB, 1084824e7fdSDimitry Andric bool IsFirstBB) { 1094824e7fdSDimitry Andric // Which instruction to insert: BTI or PACBTI 1104824e7fdSDimitry Andric unsigned OpCode = ARM::t2BTI; 111*0eae32dcSDimitry Andric unsigned MIFlags = 0; 1124824e7fdSDimitry Andric 1134824e7fdSDimitry Andric // Skip meta instructions, including EH labels 1144824e7fdSDimitry Andric auto MBBI = llvm::find_if_not(MBB.instrs(), [](const MachineInstr &MI) { 1154824e7fdSDimitry Andric return MI.isMetaInstruction(); 1164824e7fdSDimitry Andric }); 1174824e7fdSDimitry Andric 1184824e7fdSDimitry Andric // If this is the first BB in a function, check if it starts with a PAC 1194824e7fdSDimitry Andric // instruction and in that case remove the PAC instruction. 1204824e7fdSDimitry Andric if (IsFirstBB) { 1214824e7fdSDimitry Andric if (MBBI != MBB.instr_end() && MBBI->getOpcode() == ARM::t2PAC) { 1224824e7fdSDimitry Andric LLVM_DEBUG(dbgs() << "Removing a 'PAC' instr from BB '" << MBB.getName() 1234824e7fdSDimitry Andric << "' to replace with PACBTI\n"); 1244824e7fdSDimitry Andric OpCode = ARM::t2PACBTI; 125*0eae32dcSDimitry Andric MIFlags = MachineInstr::FrameSetup; 1264824e7fdSDimitry Andric auto NextMBBI = std::next(MBBI); 1274824e7fdSDimitry Andric MBBI->eraseFromParent(); 1284824e7fdSDimitry Andric MBBI = NextMBBI; 1294824e7fdSDimitry Andric } 1304824e7fdSDimitry Andric } 1314824e7fdSDimitry Andric 1324824e7fdSDimitry Andric LLVM_DEBUG(dbgs() << "Inserting a '" 1334824e7fdSDimitry Andric << (OpCode == ARM::t2BTI ? "BTI" : "PACBTI") 1344824e7fdSDimitry Andric << "' instr into BB '" << MBB.getName() << "'\n"); 1354824e7fdSDimitry Andric // Finally, insert a new instruction (either PAC or PACBTI) 136*0eae32dcSDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII.get(OpCode)) 137*0eae32dcSDimitry Andric .setMIFlags(MIFlags); 1384824e7fdSDimitry Andric } 139