LLVM  12.0.0git
X86SpeculativeExecutionSideEffectSuppression.cpp
Go to the documentation of this file.
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"
24 #include "llvm/Pass.h"
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "x86-seses"
29 
30 STATISTIC(NumLFENCEsInserted, "Number of lfence instructions inserted");
31 
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 
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 
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 
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.
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.
98  !(Subtarget.useLVILoadHardening() && OptLevel == CodeGenOpt::None) &&
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  }
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 
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 
176  return new X86SpeculativeExecutionSideEffectSuppression();
177 }
178 
179 INITIALIZE_PASS(X86SpeculativeExecutionSideEffectSuppression, "x86-seses",
180  "X86 Speculative Execution Side Effect Suppression", false,
181  false)
This class represents lattice values for constants.
Definition: AllocatorList.h:23
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
Definition: MachineInstr.h:603
static cl::opt< bool > OnlyLFENCENonConst("x86-seses-only-lfence-non-const", cl::desc("Only lfence before groups of terminators where at least one " "branch instruction has an input to the addressing mode that is a " "register other than %rip."), cl::init(false), cl::Hidden)
const X86InstrInfo * getInstrInfo() const override
Definition: X86Subtarget.h:538
STATISTIC(NumFunctions, "Total number of functions")
A debug info location.
Definition: DebugLoc.h:33
MachineBasicBlock & MBB
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
FunctionPass * createX86SpeculativeExecutionSideEffectSuppression()
bool useSpeculativeExecutionSideEffectSuppression() const
Definition: X86Subtarget.h:765
static cl::opt< bool > OmitBranchLFENCEs("x86-seses-omit-branch-lfences", cl::desc("Omit all lfences before branch instructions."), cl::init(false), cl::Hidden)
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:434
CodeGenOpt::Level getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
static bool hasConstantAddressingMode(const MachineInstr &MI)
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:284
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:37
static cl::opt< bool > EnableSpeculativeExecutionSideEffectSuppression("x86-seses-enable-without-lvi-cfi", cl::desc("Force enable speculative execution side effect suppression. " "(Note: User must pass -mlvi-cfi in order to mitigate indirect " "branches and returns.)"), cl::init(false), cl::Hidden)
MachineOperand class - Representation of each machine instruction operand.
bool useLVILoadHardening() const
Definition: X86Subtarget.h:764
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
static cl::opt< bool > OneLFENCEPerBasicBlock("x86-seses-one-lfence-per-bb", cl::desc("Omit all lfences other than the first to be placed in a basic block."), cl::init(false), cl::Hidden)
Representation of each machine instruction.
Definition: MachineInstr.h:62
const LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
IRTranslator LLVM IR MI
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
#define LLVM_DEBUG(X)
Definition: Debug.h:122