LCOV - code coverage report
Current view: top level - lib/Target/AArch64 - AArch64BranchTargets.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 30 30 100.0 %
Date: 2018-10-20 13:21:21 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- AArch64BranchTargets.cpp -- Harden code using v8.5-A BTI extension -==//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This pass inserts BTI instructions at the start of every function and basic
      11             : // block which could be indirectly called. The hardware will (when enabled)
      12             : // trap when an indirect branch or call instruction targets an instruction
      13             : // which is not a valid BTI instruction. This is intended to guard against
      14             : // control-flow hijacking attacks. Note that this does not do anything for RET
      15             : // instructions, as they can be more precisely protected by return address
      16             : // signing.
      17             : //
      18             : //===----------------------------------------------------------------------===//
      19             : 
      20             : #include "AArch64Subtarget.h"
      21             : #include "llvm/CodeGen/MachineFunctionPass.h"
      22             : #include "llvm/CodeGen/MachineInstrBuilder.h"
      23             : #include "llvm/CodeGen/MachineJumpTableInfo.h"
      24             : #include "llvm/CodeGen/MachineModuleInfo.h"
      25             : #include "llvm/Support/Debug.h"
      26             : 
      27             : using namespace llvm;
      28             : 
      29             : #define DEBUG_TYPE "aarch64-branch-targets"
      30             : #define AARCH64_BRANCH_TARGETS_NAME "AArch64 Branch Targets"
      31             : 
      32             : namespace {
      33             : class AArch64BranchTargets : public MachineFunctionPass {
      34             : public:
      35             :   static char ID;
      36        1224 :   AArch64BranchTargets() : MachineFunctionPass(ID) {}
      37             :   void getAnalysisUsage(AnalysisUsage &AU) const override;
      38             :   bool runOnMachineFunction(MachineFunction &MF) override;
      39        1206 :   StringRef getPassName() const override { return AARCH64_BRANCH_TARGETS_NAME; }
      40             : 
      41             : private:
      42             :   void addBTI(MachineBasicBlock &MBB, bool CouldCall, bool CouldJump);
      43             : };
      44             : } // end anonymous namespace
      45             : 
      46             : char AArch64BranchTargets::ID = 0;
      47             : 
      48      199032 : INITIALIZE_PASS(AArch64BranchTargets, "aarch64-branch-targets",
      49             :                 AARCH64_BRANCH_TARGETS_NAME, false, false)
      50             : 
      51        1195 : void AArch64BranchTargets::getAnalysisUsage(AnalysisUsage &AU) const {
      52        1195 :   AU.setPreservesCFG();
      53        1195 :   MachineFunctionPass::getAnalysisUsage(AU);
      54        1195 : }
      55             : 
      56        1223 : FunctionPass *llvm::createAArch64BranchTargetsPass() {
      57        1223 :   return new AArch64BranchTargets();
      58             : }
      59             : 
      60       14774 : bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) {
      61       14774 :   const Function &F = MF.getFunction();
      62       14774 :   if (!F.hasFnAttribute("branch-target-enforcement"))
      63             :     return false;
      64             : 
      65             :   LLVM_DEBUG(
      66             :       dbgs() << "********** AArch64 Branch Targets  **********\n"
      67             :              << "********** Function: " << MF.getName() << '\n');
      68             : 
      69             :   // LLVM does not consider basic blocks which are the targets of jump tables
      70             :   // to be address-taken (the address can't escape anywhere else), but they are
      71             :   // used for indirect branches, so need BTI instructions.
      72             :   SmallPtrSet<MachineBasicBlock *, 8> JumpTableTargets;
      73           8 :   if (auto *JTI = MF.getJumpTableInfo())
      74           2 :     for (auto &JTE : JTI->getJumpTables())
      75           6 :       for (auto *MBB : JTE.MBBs)
      76           5 :         JumpTableTargets.insert(MBB);
      77             : 
      78             :   bool MadeChange = false;
      79          27 :   for (MachineBasicBlock &MBB : MF) {
      80             :     bool CouldCall = false, CouldJump = false;
      81             :     // If the function is address-taken or externally-visible, it could be
      82             :     // indirectly called. PLT entries and tail-calls use BR, but when they are
      83             :     // are in guarded pages should all use x16 or x17 to hold the called
      84             :     // address, so we don't need to set CouldJump here. BR instructions in
      85             :     // non-guarded pages (which might be non-BTI-aware code) are allowed to
      86             :     // branch to a "BTI c" using any register.
      87          19 :     if (&MBB == &*MF.begin() && (F.hasAddressTaken() || !F.hasLocalLinkage()))
      88             :       CouldCall = true;
      89             : 
      90             :     // If the block itself is address-taken, it could be indirectly branched
      91             :     // to, but not called.
      92          19 :     if (MBB.hasAddressTaken() || JumpTableTargets.count(&MBB))
      93             :       CouldJump = true;
      94             : 
      95          19 :     if (CouldCall || CouldJump) {
      96          15 :       addBTI(MBB, CouldCall, CouldJump);
      97             :       MadeChange = true;
      98             :     }
      99             :   }
     100             : 
     101             :   return MadeChange;
     102             : }
     103             : 
     104          15 : void AArch64BranchTargets::addBTI(MachineBasicBlock &MBB, bool CouldCall,
     105             :                                   bool CouldJump) {
     106             :   LLVM_DEBUG(dbgs() << "Adding BTI " << (CouldJump ? "j" : "")
     107             :                     << (CouldCall ? "c" : "") << " to " << MBB.getName()
     108             :                     << "\n");
     109             : 
     110             :   const AArch64InstrInfo *TII = static_cast<const AArch64InstrInfo *>(
     111          15 :       MBB.getParent()->getSubtarget().getInstrInfo());
     112             : 
     113             :   unsigned HintNum = 32;
     114          15 :   if (CouldCall)
     115             :     HintNum |= 2;
     116          15 :   if (CouldJump)
     117           9 :     HintNum |= 4;
     118             :   assert(HintNum != 32 && "No target kinds!");
     119             : 
     120             :   auto MBBI = MBB.begin();
     121             : 
     122             :   // PACI[AB]SP are implicitly BTI JC, so no BTI instruction needed there.
     123          15 :   if (MBBI != MBB.end() && (MBBI->getOpcode() == AArch64::PACIASP ||
     124             :                             MBBI->getOpcode() == AArch64::PACIBSP))
     125             :     return;
     126             : 
     127          13 :   BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
     128          13 :           TII->get(AArch64::HINT))
     129          13 :       .addImm(HintNum);
     130             : }

Generated by: LCOV version 1.13