X86IndirectBranchTracking.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. //===---- X86IndirectBranchTracking.cpp - Enables CET IBT mechanism -------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines a pass that enables Indirect Branch Tracking (IBT) as part
  10. // of Control-Flow Enforcement Technology (CET).
  11. // The pass adds ENDBR (End Branch) machine instructions at the beginning of
  12. // each basic block or function that is referenced by an indrect jump/call
  13. // instruction.
  14. // The ENDBR instructions have a NOP encoding and as such are ignored in
  15. // targets that do not support CET IBT mechanism.
  16. //===----------------------------------------------------------------------===//
  17. #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. using namespace llvm;
  26. #define DEBUG_TYPE "x86-indirect-branch-tracking"
  27. cl::opt<bool> IndirectBranchTracking(
  28. "x86-indirect-branch-tracking", cl::init(false), cl::Hidden,
  29. cl::desc("Enable X86 indirect branch tracking pass."));
  30. STATISTIC(NumEndBranchAdded, "Number of ENDBR instructions added");
  31. namespace {
  32. class X86IndirectBranchTrackingPass : public MachineFunctionPass {
  33. public:
  34. X86IndirectBranchTrackingPass() : MachineFunctionPass(ID) {}
  35. StringRef getPassName() const override {
  36. return "X86 Indirect Branch Tracking";
  37. }
  38. bool runOnMachineFunction(MachineFunction &MF) override;
  39. private:
  40. static char ID;
  41. /// Machine instruction info used throughout the class.
  42. const X86InstrInfo *TII = nullptr;
  43. /// Endbr opcode for the current machine function.
  44. unsigned int EndbrOpcode = 0;
  45. /// Adds a new ENDBR instruction to the beginning of the MBB.
  46. /// The function will not add it if already exists.
  47. /// It will add ENDBR32 or ENDBR64 opcode, depending on the target.
  48. /// \returns true if the ENDBR was added and false otherwise.
  49. bool addENDBR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const;
  50. };
  51. } // end anonymous namespace
  52. char X86IndirectBranchTrackingPass::ID = 0;
  53. FunctionPass *llvm::createX86IndirectBranchTrackingPass() {
  54. return new X86IndirectBranchTrackingPass();
  55. }
  56. bool X86IndirectBranchTrackingPass::addENDBR(
  57. MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const {
  58. assert(TII && "Target instruction info was not initialized");
  59. assert((X86::ENDBR64 == EndbrOpcode || X86::ENDBR32 == EndbrOpcode) &&
  60. "Unexpected Endbr opcode");
  61. // If the MBB/I is empty or the current instruction is not ENDBR,
  62. // insert ENDBR instruction to the location of I.
  63. if (I == MBB.end() || I->getOpcode() != EndbrOpcode) {
  64. BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(EndbrOpcode));
  65. ++NumEndBranchAdded;
  66. return true;
  67. }
  68. return false;
  69. }
  70. static bool IsCallReturnTwice(llvm::MachineOperand &MOp) {
  71. if (!MOp.isGlobal())
  72. return false;
  73. auto *CalleeFn = dyn_cast<Function>(MOp.getGlobal());
  74. if (!CalleeFn)
  75. return false;
  76. AttributeList Attrs = CalleeFn->getAttributes();
  77. return Attrs.hasFnAttr(Attribute::ReturnsTwice);
  78. }
  79. // Checks if function should have an ENDBR in its prologue
  80. static bool needsPrologueENDBR(MachineFunction &MF, const Module *M) {
  81. Function &F = MF.getFunction();
  82. if (F.doesNoCfCheck())
  83. return false;
  84. switch (MF.getTarget().getCodeModel()) {
  85. // Large code model functions always reachable through indirect calls.
  86. case CodeModel::Large:
  87. return true;
  88. // Address taken or externally linked functions may be reachable.
  89. default:
  90. return (F.hasAddressTaken() || !F.hasLocalLinkage());
  91. }
  92. }
  93. bool X86IndirectBranchTrackingPass::runOnMachineFunction(MachineFunction &MF) {
  94. const X86Subtarget &SubTarget = MF.getSubtarget<X86Subtarget>();
  95. const Module *M = MF.getMMI().getModule();
  96. // Check that the cf-protection-branch is enabled.
  97. Metadata *isCFProtectionSupported = M->getModuleFlag("cf-protection-branch");
  98. // NB: We need to enable IBT in jitted code if JIT compiler is CET
  99. // enabled.
  100. const X86TargetMachine *TM =
  101. static_cast<const X86TargetMachine *>(&MF.getTarget());
  102. #ifdef __CET__
  103. bool isJITwithCET = TM->isJIT();
  104. #else
  105. bool isJITwithCET = false;
  106. #endif
  107. if (!isCFProtectionSupported && !IndirectBranchTracking && !isJITwithCET)
  108. return false;
  109. // True if the current MF was changed and false otherwise.
  110. bool Changed = false;
  111. TII = SubTarget.getInstrInfo();
  112. EndbrOpcode = SubTarget.is64Bit() ? X86::ENDBR64 : X86::ENDBR32;
  113. // If function is reachable indirectly, mark the first BB with ENDBR.
  114. if (needsPrologueENDBR(MF, M)) {
  115. auto MBB = MF.begin();
  116. Changed |= addENDBR(*MBB, MBB->begin());
  117. }
  118. for (auto &MBB : MF) {
  119. // Find all basic blocks that their address was taken (for example
  120. // in the case of indirect jump) and add ENDBR instruction.
  121. if (MBB.hasAddressTaken())
  122. Changed |= addENDBR(MBB, MBB.begin());
  123. for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
  124. if (I->isCall() && I->getNumOperands() > 0 &&
  125. IsCallReturnTwice(I->getOperand(0))) {
  126. Changed |= addENDBR(MBB, std::next(I));
  127. }
  128. }
  129. // Exception handle may indirectly jump to catch pad, So we should add
  130. // ENDBR before catch pad instructions. For SjLj exception model, it will
  131. // create a new BB(new landingpad) indirectly jump to the old landingpad.
  132. if (TM->Options.ExceptionModel == ExceptionHandling::SjLj) {
  133. for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
  134. // New Landingpad BB without EHLabel.
  135. if (MBB.isEHPad()) {
  136. if (I->isDebugInstr())
  137. continue;
  138. Changed |= addENDBR(MBB, I);
  139. break;
  140. } else if (I->isEHLabel()) {
  141. // Old Landingpad BB (is not Landingpad now) with
  142. // the the old "callee" EHLabel.
  143. MCSymbol *Sym = I->getOperand(0).getMCSymbol();
  144. if (!MF.hasCallSiteLandingPad(Sym))
  145. continue;
  146. Changed |= addENDBR(MBB, std::next(I));
  147. break;
  148. }
  149. }
  150. } else if (MBB.isEHPad()){
  151. for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
  152. if (!I->isEHLabel())
  153. continue;
  154. Changed |= addENDBR(MBB, std::next(I));
  155. break;
  156. }
  157. }
  158. }
  159. return Changed;
  160. }