X86IndirectBranchTracking.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. const X86TargetMachine *TM =
  85. static_cast<const X86TargetMachine *>(&MF.getTarget());
  86. Metadata *IBTSeal = M->getModuleFlag("ibt-seal");
  87. switch (TM->getCodeModel()) {
  88. // Large code model functions always reachable through indirect calls.
  89. case CodeModel::Large:
  90. return true;
  91. // Only address taken functions in LTO'ed kernel are reachable indirectly.
  92. // IBTSeal implies LTO, thus only check if function is address taken.
  93. case CodeModel::Kernel:
  94. // Check if ibt-seal was enabled (implies LTO is being used).
  95. if (IBTSeal) {
  96. return F.hasAddressTaken();
  97. }
  98. // if !IBTSeal, fall into default case.
  99. LLVM_FALLTHROUGH;
  100. // Address taken or externally linked functions may be reachable.
  101. default:
  102. return (F.hasAddressTaken() || !F.hasLocalLinkage());
  103. }
  104. }
  105. bool X86IndirectBranchTrackingPass::runOnMachineFunction(MachineFunction &MF) {
  106. const X86Subtarget &SubTarget = MF.getSubtarget<X86Subtarget>();
  107. const Module *M = MF.getMMI().getModule();
  108. // Check that the cf-protection-branch is enabled.
  109. Metadata *isCFProtectionSupported = M->getModuleFlag("cf-protection-branch");
  110. // NB: We need to enable IBT in jitted code if JIT compiler is CET
  111. // enabled.
  112. const X86TargetMachine *TM =
  113. static_cast<const X86TargetMachine *>(&MF.getTarget());
  114. #ifdef __CET__
  115. bool isJITwithCET = TM->isJIT();
  116. #else
  117. bool isJITwithCET = false;
  118. #endif
  119. if (!isCFProtectionSupported && !IndirectBranchTracking && !isJITwithCET)
  120. return false;
  121. // True if the current MF was changed and false otherwise.
  122. bool Changed = false;
  123. TII = SubTarget.getInstrInfo();
  124. EndbrOpcode = SubTarget.is64Bit() ? X86::ENDBR64 : X86::ENDBR32;
  125. // If function is reachable indirectly, mark the first BB with ENDBR.
  126. if (needsPrologueENDBR(MF, M)) {
  127. auto MBB = MF.begin();
  128. Changed |= addENDBR(*MBB, MBB->begin());
  129. }
  130. for (auto &MBB : MF) {
  131. // Find all basic blocks that their address was taken (for example
  132. // in the case of indirect jump) and add ENDBR instruction.
  133. if (MBB.hasAddressTaken())
  134. Changed |= addENDBR(MBB, MBB.begin());
  135. for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
  136. if (I->isCall() && I->getNumOperands() > 0 &&
  137. IsCallReturnTwice(I->getOperand(0))) {
  138. Changed |= addENDBR(MBB, std::next(I));
  139. }
  140. }
  141. // Exception handle may indirectly jump to catch pad, So we should add
  142. // ENDBR before catch pad instructions. For SjLj exception model, it will
  143. // create a new BB(new landingpad) indirectly jump to the old landingpad.
  144. if (TM->Options.ExceptionModel == ExceptionHandling::SjLj) {
  145. for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
  146. // New Landingpad BB without EHLabel.
  147. if (MBB.isEHPad()) {
  148. if (I->isDebugInstr())
  149. continue;
  150. Changed |= addENDBR(MBB, I);
  151. break;
  152. } else if (I->isEHLabel()) {
  153. // Old Landingpad BB (is not Landingpad now) with
  154. // the the old "callee" EHLabel.
  155. MCSymbol *Sym = I->getOperand(0).getMCSymbol();
  156. if (!MF.hasCallSiteLandingPad(Sym))
  157. continue;
  158. Changed |= addENDBR(MBB, std::next(I));
  159. break;
  160. }
  161. }
  162. } else if (MBB.isEHPad()){
  163. for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) {
  164. if (!I->isEHLabel())
  165. continue;
  166. Changed |= addENDBR(MBB, std::next(I));
  167. break;
  168. }
  169. }
  170. }
  171. return Changed;
  172. }