LLVM  13.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  assert(FirstTerminator && "Unknown terminator instruction");
165  BuildMI(MBB, FirstTerminator, DebugLoc(), TII->get(X86::LFENCE));
166  NumLFENCEsInserted++;
167  Modified = true;
168  }
169  break;
170  }
171  }
172 
173  return Modified;
174 }
175 
177  return new X86SpeculativeExecutionSideEffectSuppression();
178 }
179 
180 INITIALIZE_PASS(X86SpeculativeExecutionSideEffectSuppression, "x86-seses",
181  "X86 Speculative Execution Side Effect Suppression", false,
182  false)
llvm::TargetMachine::getOptLevel
CodeGenOpt::Level getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
Definition: TargetMachine.cpp:198
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:102
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
X86Subtarget.h
Pass.h
llvm::X86Subtarget::getInstrInfo
const X86InstrInfo * getInstrInfo() const override
Definition: X86Subtarget.h:553
Statistic.h
llvm::X86Subtarget
Definition: X86Subtarget.h:52
llvm::MachineFunctionPass
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Definition: MachineFunctionPass.h:30
llvm::cl::Hidden
@ Hidden
Definition: CommandLine.h:143
OnlyLFENCENonConst
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)
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:122
hasConstantAddressingMode
static bool hasConstantAddressingMode(const MachineInstr &MI)
Definition: X86SpeculativeExecutionSideEffectSuppression.cpp:81
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
X86.h
TargetMachine.h
INITIALIZE_PASS
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:37
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:129
llvm::MachineOperand
MachineOperand class - Representation of each machine instruction operand.
Definition: MachineOperand.h:49
llvm::STATISTIC
STATISTIC(NumFunctions, "Total number of functions")
LoopDeletionResult::Modified
@ Modified
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:95
llvm::MachineFunction::getSubtarget
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Definition: MachineFunction.h:622
llvm::createX86SpeculativeExecutionSideEffectSuppression
FunctionPass * createX86SpeculativeExecutionSideEffectSuppression()
Definition: X86SpeculativeExecutionSideEffectSuppression.cpp:176
llvm::cl::opt< bool >
llvm::MachineInstr
Representation of each machine instruction.
Definition: MachineInstr.h:64
llvm::cl::init
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
MachineFunctionPass.h
llvm::MachineFunction::getName
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Definition: MachineFunction.cpp:541
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
OneLFENCEPerBasicBlock
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)
OmitBranchLFENCEs
static cl::opt< bool > OmitBranchLFENCEs("x86-seses-omit-branch-lfences", cl::desc("Omit all lfences before branch instructions."), cl::init(false), cl::Hidden)
llvm::MachineFunction
Definition: MachineFunction.h:230
llvm::CodeGenOpt::None
@ None
Definition: CodeGen.h:53
llvm::X86InstrInfo
Definition: X86InstrInfo.h:130
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::X86Subtarget::useSpeculativeExecutionSideEffectSuppression
bool useSpeculativeExecutionSideEffectSuppression() const
Definition: X86Subtarget.h:790
MBB
MachineBasicBlock & MBB
Definition: AArch64SLSHardening.cpp:74
llvm::MachineFunction::getTarget
const LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Definition: MachineFunction.h:618
MachineInstrBuilder.h
EnableSpeculativeExecutionSideEffectSuppression
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)
llvm::BuildMI
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
Definition: MachineInstrBuilder.h:328
llvm::X86Subtarget::useLVILoadHardening
bool useLVILoadHardening() const
Definition: X86Subtarget.h:789
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:298
llvm::DebugLoc
A debug info location.
Definition: DebugLoc.h:33
llvm::cl::desc
Definition: CommandLine.h:414
MachineFunction.h
X86InstrInfo.h
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38