1 //===-- X86SpeculativeExecutionSideEffectSuppression.cpp ------------------===// 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 /// \file 9 /// 10 /// This file contains the X86 implementation of the speculative execution side 11 /// effect suppression mitigation. 12 /// 13 /// This must be used with the -mlvi-cfi flag in order to mitigate indirect 14 /// branches and returns. 15 //===----------------------------------------------------------------------===// 16 17 #include "X86.h" 18 #include "X86InstrInfo.h" 19 #include "X86Subtarget.h" 20 #include "llvm/ADT/Statistic.h" 21 #include "llvm/CodeGen/MachineFunction.h" 22 #include "llvm/CodeGen/MachineFunctionPass.h" 23 #include "llvm/CodeGen/MachineInstrBuilder.h" 24 #include "llvm/Pass.h" 25 #include "llvm/Target/TargetMachine.h" 26 using namespace llvm; 27 28 #define DEBUG_TYPE "x86-seses" 29 30 STATISTIC(NumLFENCEsInserted, "Number of lfence instructions inserted"); 31 32 static cl::opt<bool> EnableSpeculativeExecutionSideEffectSuppression( 33 "x86-seses-enable-without-lvi-cfi", 34 cl::desc("Force enable speculative execution side effect suppression. " 35 "(Note: User must pass -mlvi-cfi in order to mitigate indirect " 36 "branches and returns.)"), 37 cl::init(false), cl::Hidden); 38 39 static cl::opt<bool> OneLFENCEPerBasicBlock( 40 "x86-seses-one-lfence-per-bb", 41 cl::desc( 42 "Omit all lfences other than the first to be placed in a basic block."), 43 cl::init(false), cl::Hidden); 44 45 static cl::opt<bool> OnlyLFENCENonConst( 46 "x86-seses-only-lfence-non-const", 47 cl::desc("Only lfence before groups of terminators where at least one " 48 "branch instruction has an input to the addressing mode that is a " 49 "register other than %rip."), 50 cl::init(false), cl::Hidden); 51 52 static cl::opt<bool> 53 OmitBranchLFENCEs("x86-seses-omit-branch-lfences", 54 cl::desc("Omit all lfences before branch instructions."), 55 cl::init(false), cl::Hidden); 56 57 namespace { 58 59 class X86SpeculativeExecutionSideEffectSuppression 60 : public MachineFunctionPass { 61 public: 62 X86SpeculativeExecutionSideEffectSuppression() : MachineFunctionPass(ID) {} 63 64 static char ID; 65 StringRef getPassName() const override { 66 return "X86 Speculative Execution Side Effect Suppression"; 67 } 68 69 bool runOnMachineFunction(MachineFunction &MF) override; 70 }; 71 } // namespace 72 73 char X86SpeculativeExecutionSideEffectSuppression::ID = 0; 74 75 // This function returns whether the passed instruction uses a memory addressing 76 // mode that is constant. We treat all memory addressing modes that read 77 // from a register that is not %rip as non-constant. Note that the use 78 // of the EFLAGS register results in an addressing mode being considered 79 // non-constant, therefore all JCC instructions will return false from this 80 // function since one of their operands will always be the EFLAGS register. 81 static bool hasConstantAddressingMode(const MachineInstr &MI) { 82 for (const MachineOperand &MO : MI.uses()) 83 if (MO.isReg() && X86::RIP != MO.getReg()) 84 return false; 85 return true; 86 } 87 88 bool X86SpeculativeExecutionSideEffectSuppression::runOnMachineFunction( 89 MachineFunction &MF) { 90 91 const auto &OptLevel = MF.getTarget().getOptLevel(); 92 const X86Subtarget &Subtarget = MF.getSubtarget<X86Subtarget>(); 93 94 // Check whether SESES needs to run as the fallback for LVI at O0, whether the 95 // user explicitly passed an SESES flag, or whether the SESES target feature 96 // was set. 97 if (!EnableSpeculativeExecutionSideEffectSuppression && 98 !(Subtarget.useLVILoadHardening() && OptLevel == CodeGenOpt::None) && 99 !Subtarget.useSpeculativeExecutionSideEffectSuppression()) 100 return false; 101 102 LLVM_DEBUG(dbgs() << "********** " << getPassName() << " : " << MF.getName() 103 << " **********\n"); 104 bool Modified = false; 105 const X86InstrInfo *TII = Subtarget.getInstrInfo(); 106 for (MachineBasicBlock &MBB : MF) { 107 MachineInstr *FirstTerminator = nullptr; 108 // Keep track of whether the previous instruction was an LFENCE to avoid 109 // adding redundant LFENCEs. 110 bool PrevInstIsLFENCE = false; 111 for (auto &MI : MBB) { 112 113 if (MI.getOpcode() == X86::LFENCE) { 114 PrevInstIsLFENCE = true; 115 continue; 116 } 117 // We want to put an LFENCE before any instruction that 118 // may load or store. This LFENCE is intended to avoid leaking any secret 119 // data due to a given load or store. This results in closing the cache 120 // and memory timing side channels. We will treat terminators that load 121 // or store separately. 122 if (MI.mayLoadOrStore() && !MI.isTerminator()) { 123 if (!PrevInstIsLFENCE) { 124 BuildMI(MBB, MI, DebugLoc(), TII->get(X86::LFENCE)); 125 NumLFENCEsInserted++; 126 Modified = true; 127 } 128 if (OneLFENCEPerBasicBlock) 129 break; 130 } 131 // The following section will be LFENCEing before groups of terminators 132 // that include branches. This will close the branch prediction side 133 // channels since we will prevent code executing after misspeculation as 134 // a result of the LFENCEs placed with this logic. 135 136 // Keep track of the first terminator in a basic block since if we need 137 // to LFENCE the terminators in this basic block we must add the 138 // instruction before the first terminator in the basic block (as 139 // opposed to before the terminator that indicates an LFENCE is 140 // required). An example of why this is necessary is that the 141 // X86InstrInfo::analyzeBranch method assumes all terminators are grouped 142 // together and terminates it's analysis once the first non-termintor 143 // instruction is found. 144 if (MI.isTerminator() && FirstTerminator == nullptr) 145 FirstTerminator = &MI; 146 147 // Look for branch instructions that will require an LFENCE to be put 148 // before this basic block's terminators. 149 if (!MI.isBranch() || OmitBranchLFENCEs) { 150 // This isn't a branch or we're not putting LFENCEs before branches. 151 PrevInstIsLFENCE = false; 152 continue; 153 } 154 155 if (OnlyLFENCENonConst && hasConstantAddressingMode(MI)) { 156 // This is a branch, but it only has constant addressing mode and we're 157 // not adding LFENCEs before such branches. 158 PrevInstIsLFENCE = false; 159 continue; 160 } 161 162 // This branch requires adding an LFENCE. 163 if (!PrevInstIsLFENCE) { 164 BuildMI(MBB, FirstTerminator, DebugLoc(), TII->get(X86::LFENCE)); 165 NumLFENCEsInserted++; 166 Modified = true; 167 } 168 break; 169 } 170 } 171 172 return Modified; 173 } 174 175 FunctionPass *llvm::createX86SpeculativeExecutionSideEffectSuppression() { 176 return new X86SpeculativeExecutionSideEffectSuppression(); 177 } 178 179 INITIALIZE_PASS(X86SpeculativeExecutionSideEffectSuppression, "x86-seses", 180 "X86 Speculative Execution Side Effect Suppression", false, 181 false) 182