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;
ARMBranchTargets()354824e7fdSDimitry Andric ARMBranchTargets() : MachineFunctionPass(ID) {}
364824e7fdSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override;
374824e7fdSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
getPassName() const384824e7fdSDimitry 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
getAnalysisUsage(AnalysisUsage & AU) const504824e7fdSDimitry Andric void ARMBranchTargets::getAnalysisUsage(AnalysisUsage &AU) const {
514824e7fdSDimitry Andric AU.setPreservesCFG();
524824e7fdSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
534824e7fdSDimitry Andric }
544824e7fdSDimitry Andric
createARMBranchTargetsPass()554824e7fdSDimitry Andric FunctionPass *llvm::createARMBranchTargetsPass() {
564824e7fdSDimitry Andric return new ARMBranchTargets();
574824e7fdSDimitry Andric }
584824e7fdSDimitry Andric
runOnMachineFunction(MachineFunction & MF)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 bool MadeChange = false;
694824e7fdSDimitry Andric for (MachineBasicBlock &MBB : MF) {
704824e7fdSDimitry Andric bool IsFirstBB = &MBB == &MF.front();
714824e7fdSDimitry Andric
724824e7fdSDimitry Andric // Every function can potentially be called indirectly (even if it has
734824e7fdSDimitry Andric // static linkage, due to linker-generated veneers).
744824e7fdSDimitry Andric // If the block itself is address-taken, or is an exception landing pad, it
754824e7fdSDimitry Andric // could be indirectly branched to.
76*06c3fb27SDimitry Andric // Jump tables only emit indirect jumps (JUMPTABLE_ADDRS) in ARM or Thumb1
77*06c3fb27SDimitry Andric // modes. These modes do not support PACBTI. As a result, BTI instructions
78*06c3fb27SDimitry Andric // are not added in the destination blocks.
794824e7fdSDimitry Andric
80*06c3fb27SDimitry Andric if (IsFirstBB || MBB.hasAddressTaken() || MBB.isEHPad()) {
814824e7fdSDimitry Andric addBTI(TII, MBB, IsFirstBB);
824824e7fdSDimitry Andric MadeChange = true;
834824e7fdSDimitry Andric }
844824e7fdSDimitry Andric }
854824e7fdSDimitry Andric
864824e7fdSDimitry Andric return MadeChange;
874824e7fdSDimitry Andric }
884824e7fdSDimitry Andric
894824e7fdSDimitry Andric /// Insert a BTI/PACBTI instruction into a given basic block \c MBB. If
904824e7fdSDimitry Andric /// \c IsFirstBB is true (meaning that this is the first BB in a function) try
914824e7fdSDimitry Andric /// to find a PAC instruction and replace it with PACBTI. Otherwise just insert
924824e7fdSDimitry Andric /// a BTI instruction.
934824e7fdSDimitry Andric /// The point of insertion is in the beginning of the BB, immediately after meta
944824e7fdSDimitry Andric /// instructions (such labels in exception handling landing pads).
addBTI(const ARMInstrInfo & TII,MachineBasicBlock & MBB,bool IsFirstBB)954824e7fdSDimitry Andric void ARMBranchTargets::addBTI(const ARMInstrInfo &TII, MachineBasicBlock &MBB,
964824e7fdSDimitry Andric bool IsFirstBB) {
974824e7fdSDimitry Andric // Which instruction to insert: BTI or PACBTI
984824e7fdSDimitry Andric unsigned OpCode = ARM::t2BTI;
990eae32dcSDimitry Andric unsigned MIFlags = 0;
1004824e7fdSDimitry Andric
1014824e7fdSDimitry Andric // Skip meta instructions, including EH labels
1024824e7fdSDimitry Andric auto MBBI = llvm::find_if_not(MBB.instrs(), [](const MachineInstr &MI) {
1034824e7fdSDimitry Andric return MI.isMetaInstruction();
1044824e7fdSDimitry Andric });
1054824e7fdSDimitry Andric
1064824e7fdSDimitry Andric // If this is the first BB in a function, check if it starts with a PAC
1074824e7fdSDimitry Andric // instruction and in that case remove the PAC instruction.
1084824e7fdSDimitry Andric if (IsFirstBB) {
1094824e7fdSDimitry Andric if (MBBI != MBB.instr_end() && MBBI->getOpcode() == ARM::t2PAC) {
1104824e7fdSDimitry Andric LLVM_DEBUG(dbgs() << "Removing a 'PAC' instr from BB '" << MBB.getName()
1114824e7fdSDimitry Andric << "' to replace with PACBTI\n");
1124824e7fdSDimitry Andric OpCode = ARM::t2PACBTI;
1130eae32dcSDimitry Andric MIFlags = MachineInstr::FrameSetup;
1144824e7fdSDimitry Andric auto NextMBBI = std::next(MBBI);
1154824e7fdSDimitry Andric MBBI->eraseFromParent();
1164824e7fdSDimitry Andric MBBI = NextMBBI;
1174824e7fdSDimitry Andric }
1184824e7fdSDimitry Andric }
1194824e7fdSDimitry Andric
1204824e7fdSDimitry Andric LLVM_DEBUG(dbgs() << "Inserting a '"
1214824e7fdSDimitry Andric << (OpCode == ARM::t2BTI ? "BTI" : "PACBTI")
1224824e7fdSDimitry Andric << "' instr into BB '" << MBB.getName() << "'\n");
1234824e7fdSDimitry Andric // Finally, insert a new instruction (either PAC or PACBTI)
1240eae32dcSDimitry Andric BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII.get(OpCode))
1250eae32dcSDimitry Andric .setMIFlags(MIFlags);
1264824e7fdSDimitry Andric }
127