LLVM  15.0.0git
X86LoadValueInjectionLoadHardening.cpp
Go to the documentation of this file.
1 //==-- X86LoadValueInjectionLoadHardening.cpp - LVI load hardening for x86 --=//
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 /// Description: This pass finds Load Value Injection (LVI) gadgets consisting
10 /// of a load from memory (i.e., SOURCE), and any operation that may transmit
11 /// the value loaded from memory over a covert channel, or use the value loaded
12 /// from memory to determine a branch/call target (i.e., SINK). After finding
13 /// all such gadgets in a given function, the pass minimally inserts LFENCE
14 /// instructions in such a manner that the following property is satisfied: for
15 /// all SOURCE+SINK pairs, all paths in the CFG from SOURCE to SINK contain at
16 /// least one LFENCE instruction. The algorithm that implements this minimal
17 /// insertion is influenced by an academic paper that minimally inserts memory
18 /// fences for high-performance concurrent programs:
19 /// http://www.cs.ucr.edu/~lesani/companion/oopsla15/OOPSLA15.pdf
20 /// The algorithm implemented in this pass is as follows:
21 /// 1. Build a condensed CFG (i.e., a GadgetGraph) consisting only of the
22 /// following components:
23 /// - SOURCE instructions (also includes function arguments)
24 /// - SINK instructions
25 /// - Basic block entry points
26 /// - Basic block terminators
27 /// - LFENCE instructions
28 /// 2. Analyze the GadgetGraph to determine which SOURCE+SINK pairs (i.e.,
29 /// gadgets) are already mitigated by existing LFENCEs. If all gadgets have been
30 /// mitigated, go to step 6.
31 /// 3. Use a heuristic or plugin to approximate minimal LFENCE insertion.
32 /// 4. Insert one LFENCE along each CFG edge that was cut in step 3.
33 /// 5. Go to step 2.
34 /// 6. If any LFENCEs were inserted, return `true` from runOnMachineFunction()
35 /// to tell LLVM that the function was modified.
36 ///
37 //===----------------------------------------------------------------------===//
38 
39 #include "ImmutableGraph.h"
40 #include "X86.h"
41 #include "X86Subtarget.h"
42 #include "X86TargetMachine.h"
43 #include "llvm/ADT/DenseMap.h"
44 #include "llvm/ADT/DenseSet.h"
45 #include "llvm/ADT/STLExtras.h"
46 #include "llvm/ADT/SmallSet.h"
47 #include "llvm/ADT/Statistic.h"
48 #include "llvm/ADT/StringRef.h"
58 #include "llvm/CodeGen/RDFGraph.h"
60 #include "llvm/InitializePasses.h"
63 #include "llvm/Support/Debug.h"
67 
68 using namespace llvm;
69 
70 #define PASS_KEY "x86-lvi-load"
71 #define DEBUG_TYPE PASS_KEY
72 
73 STATISTIC(NumFences, "Number of LFENCEs inserted for LVI mitigation");
74 STATISTIC(NumFunctionsConsidered, "Number of functions analyzed");
75 STATISTIC(NumFunctionsMitigated, "Number of functions for which mitigations "
76  "were deployed");
77 STATISTIC(NumGadgets, "Number of LVI gadgets detected during analysis");
78 
80  PASS_KEY "-opt-plugin",
81  cl::desc("Specify a plugin to optimize LFENCE insertion"), cl::Hidden);
82 
84  PASS_KEY "-no-cbranch",
85  cl::desc("Don't treat conditional branches as disclosure gadgets. This "
86  "may improve performance, at the cost of security."),
87  cl::init(false), cl::Hidden);
88 
89 static cl::opt<bool> EmitDot(
90  PASS_KEY "-dot",
91  cl::desc(
92  "For each function, emit a dot graph depicting potential LVI gadgets"),
93  cl::init(false), cl::Hidden);
94 
96  PASS_KEY "-dot-only",
97  cl::desc("For each function, emit a dot graph depicting potential LVI "
98  "gadgets, and do not insert any fences"),
99  cl::init(false), cl::Hidden);
100 
102  PASS_KEY "-dot-verify",
103  cl::desc("For each function, emit a dot graph to stdout depicting "
104  "potential LVI gadgets, used for testing purposes only"),
105  cl::init(false), cl::Hidden);
106 
108 typedef int (*OptimizeCutT)(unsigned int *Nodes, unsigned int NodesSize,
109  unsigned int *Edges, int *EdgeValues,
110  int *CutEdges /* out */, unsigned int EdgesSize);
111 static OptimizeCutT OptimizeCut = nullptr;
112 
113 namespace {
114 
115 struct MachineGadgetGraph : ImmutableGraph<MachineInstr *, int> {
116  static constexpr int GadgetEdgeSentinel = -1;
117  static constexpr MachineInstr *const ArgNodeSentinel = nullptr;
118 
120  using Node = typename GraphT::Node;
121  using Edge = typename GraphT::Edge;
122  using size_type = typename GraphT::size_type;
123  MachineGadgetGraph(std::unique_ptr<Node[]> Nodes,
124  std::unique_ptr<Edge[]> Edges, size_type NodesSize,
125  size_type EdgesSize, int NumFences = 0, int NumGadgets = 0)
126  : GraphT(std::move(Nodes), std::move(Edges), NodesSize, EdgesSize),
127  NumFences(NumFences), NumGadgets(NumGadgets) {}
128  static inline bool isCFGEdge(const Edge &E) {
129  return E.getValue() != GadgetEdgeSentinel;
130  }
131  static inline bool isGadgetEdge(const Edge &E) {
132  return E.getValue() == GadgetEdgeSentinel;
133  }
134  int NumFences;
135  int NumGadgets;
136 };
137 
138 class X86LoadValueInjectionLoadHardeningPass : public MachineFunctionPass {
139 public:
140  X86LoadValueInjectionLoadHardeningPass() : MachineFunctionPass(ID) {}
141 
142  StringRef getPassName() const override {
143  return "X86 Load Value Injection (LVI) Load Hardening";
144  }
145  void getAnalysisUsage(AnalysisUsage &AU) const override;
146  bool runOnMachineFunction(MachineFunction &MF) override;
147 
148  static char ID;
149 
150 private:
151  using GraphBuilder = ImmutableGraphBuilder<MachineGadgetGraph>;
152  using Edge = MachineGadgetGraph::Edge;
153  using Node = MachineGadgetGraph::Node;
154  using EdgeSet = MachineGadgetGraph::EdgeSet;
156 
157  const X86Subtarget *STI;
158  const TargetInstrInfo *TII;
159  const TargetRegisterInfo *TRI;
160 
161  std::unique_ptr<MachineGadgetGraph>
162  getGadgetGraph(MachineFunction &MF, const MachineLoopInfo &MLI,
163  const MachineDominatorTree &MDT,
164  const MachineDominanceFrontier &MDF) const;
165  int hardenLoadsWithPlugin(MachineFunction &MF,
166  std::unique_ptr<MachineGadgetGraph> Graph) const;
167  int hardenLoadsWithHeuristic(MachineFunction &MF,
168  std::unique_ptr<MachineGadgetGraph> Graph) const;
169  int elimMitigatedEdgesAndNodes(MachineGadgetGraph &G,
170  EdgeSet &ElimEdges /* in, out */,
171  NodeSet &ElimNodes /* in, out */) const;
172  std::unique_ptr<MachineGadgetGraph>
173  trimMitigatedEdges(std::unique_ptr<MachineGadgetGraph> Graph) const;
174  int insertFences(MachineFunction &MF, MachineGadgetGraph &G,
175  EdgeSet &CutEdges /* in, out */) const;
176  bool instrUsesRegToAccessMemory(const MachineInstr &I, unsigned Reg) const;
177  bool instrUsesRegToBranch(const MachineInstr &I, unsigned Reg) const;
178  inline bool isFence(const MachineInstr *MI) const {
179  return MI && (MI->getOpcode() == X86::LFENCE ||
180  (STI->useLVIControlFlowIntegrity() && MI->isCall()));
181  }
182 };
183 
184 } // end anonymous namespace
185 
186 namespace llvm {
187 
188 template <>
189 struct GraphTraits<MachineGadgetGraph *>
191 
192 template <>
193 struct DOTGraphTraits<MachineGadgetGraph *> : DefaultDOTGraphTraits {
194  using GraphType = MachineGadgetGraph;
196  using NodeRef = typename Traits::NodeRef;
197  using EdgeRef = typename Traits::EdgeRef;
198  using ChildIteratorType = typename Traits::ChildIteratorType;
199  using ChildEdgeIteratorType = typename Traits::ChildEdgeIteratorType;
200 
201  DOTGraphTraits(bool IsSimple = false) : DefaultDOTGraphTraits(IsSimple) {}
202 
203  std::string getNodeLabel(NodeRef Node, GraphType *) {
204  if (Node->getValue() == MachineGadgetGraph::ArgNodeSentinel)
205  return "ARGS";
206 
207  std::string Str;
208  raw_string_ostream OS(Str);
209  OS << *Node->getValue();
210  return OS.str();
211  }
212 
213  static std::string getNodeAttributes(NodeRef Node, GraphType *) {
214  MachineInstr *MI = Node->getValue();
215  if (MI == MachineGadgetGraph::ArgNodeSentinel)
216  return "color = blue";
217  if (MI->getOpcode() == X86::LFENCE)
218  return "color = green";
219  return "";
220  }
221 
223  GraphType *) {
224  int EdgeVal = (*E.getCurrent()).getValue();
225  return EdgeVal >= 0 ? "label = " + std::to_string(EdgeVal)
226  : "color = red, style = \"dashed\"";
227  }
228 };
229 
230 } // end namespace llvm
231 
232 constexpr MachineInstr *MachineGadgetGraph::ArgNodeSentinel;
233 constexpr int MachineGadgetGraph::GadgetEdgeSentinel;
234 
236 
237 void X86LoadValueInjectionLoadHardeningPass::getAnalysisUsage(
238  AnalysisUsage &AU) const {
243  AU.setPreservesCFG();
244 }
245 
247  MachineGadgetGraph *G) {
248  WriteGraph(OS, G, /*ShortNames*/ false,
249  "Speculative gadgets for \"" + MF.getName() + "\" function");
250 }
251 
252 bool X86LoadValueInjectionLoadHardeningPass::runOnMachineFunction(
253  MachineFunction &MF) {
254  LLVM_DEBUG(dbgs() << "***** " << getPassName() << " : " << MF.getName()
255  << " *****\n");
256  STI = &MF.getSubtarget<X86Subtarget>();
257  if (!STI->useLVILoadHardening())
258  return false;
259 
260  // FIXME: support 32-bit
261  if (!STI->is64Bit())
262  report_fatal_error("LVI load hardening is only supported on 64-bit", false);
263 
264  // Don't skip functions with the "optnone" attr but participate in opt-bisect.
265  const Function &F = MF.getFunction();
266  if (!F.hasOptNone() && skipFunction(F))
267  return false;
268 
269  ++NumFunctionsConsidered;
270  TII = STI->getInstrInfo();
271  TRI = STI->getRegisterInfo();
272  LLVM_DEBUG(dbgs() << "Building gadget graph...\n");
273  const auto &MLI = getAnalysis<MachineLoopInfo>();
274  const auto &MDT = getAnalysis<MachineDominatorTree>();
275  const auto &MDF = getAnalysis<MachineDominanceFrontier>();
276  std::unique_ptr<MachineGadgetGraph> Graph = getGadgetGraph(MF, MLI, MDT, MDF);
277  LLVM_DEBUG(dbgs() << "Building gadget graph... Done\n");
278  if (Graph == nullptr)
279  return false; // didn't find any gadgets
280 
281  if (EmitDotVerify) {
282  writeGadgetGraph(outs(), MF, Graph.get());
283  return false;
284  }
285 
286  if (EmitDot || EmitDotOnly) {
287  LLVM_DEBUG(dbgs() << "Emitting gadget graph...\n");
288  std::error_code FileError;
289  std::string FileName = "lvi.";
290  FileName += MF.getName();
291  FileName += ".dot";
292  raw_fd_ostream FileOut(FileName, FileError);
293  if (FileError)
294  errs() << FileError.message();
295  writeGadgetGraph(FileOut, MF, Graph.get());
296  FileOut.close();
297  LLVM_DEBUG(dbgs() << "Emitting gadget graph... Done\n");
298  if (EmitDotOnly)
299  return false;
300  }
301 
302  int FencesInserted;
303  if (!OptimizePluginPath.empty()) {
304  if (!OptimizeDL.isValid()) {
305  std::string ErrorMsg;
307  OptimizePluginPath.c_str(), &ErrorMsg);
308  if (!ErrorMsg.empty())
309  report_fatal_error(Twine("Failed to load opt plugin: \"") + ErrorMsg +
310  "\"");
312  if (!OptimizeCut)
313  report_fatal_error("Invalid optimization plugin");
314  }
315  FencesInserted = hardenLoadsWithPlugin(MF, std::move(Graph));
316  } else { // Use the default greedy heuristic
317  FencesInserted = hardenLoadsWithHeuristic(MF, std::move(Graph));
318  }
319 
320  if (FencesInserted > 0)
321  ++NumFunctionsMitigated;
322  NumFences += FencesInserted;
323  return (FencesInserted > 0);
324 }
325 
326 std::unique_ptr<MachineGadgetGraph>
327 X86LoadValueInjectionLoadHardeningPass::getGadgetGraph(
328  MachineFunction &MF, const MachineLoopInfo &MLI,
329  const MachineDominatorTree &MDT,
330  const MachineDominanceFrontier &MDF) const {
331  using namespace rdf;
332 
333  // Build the Register Dataflow Graph using the RDF framework
334  TargetOperandInfo TOI{*TII};
335  DataFlowGraph DFG{MF, *TII, *TRI, MDT, MDF, TOI};
336  DFG.build();
337  Liveness L{MF.getRegInfo(), DFG};
338  L.computePhiInfo();
339 
340  GraphBuilder Builder;
341  using GraphIter = typename GraphBuilder::BuilderNodeRef;
343  int FenceCount = 0, GadgetCount = 0;
344  auto MaybeAddNode = [&NodeMap, &Builder](MachineInstr *MI) {
345  auto Ref = NodeMap.find(MI);
346  if (Ref == NodeMap.end()) {
347  auto I = Builder.addVertex(MI);
348  NodeMap[MI] = I;
349  return std::pair<GraphIter, bool>{I, true};
350  }
351  return std::pair<GraphIter, bool>{Ref->getSecond(), false};
352  };
353 
354  // The `Transmitters` map memoizes transmitters found for each def. If a def
355  // has not yet been analyzed, then it will not appear in the map. If a def
356  // has been analyzed and was determined not to have any transmitters, then
357  // its list of transmitters will be empty.
359 
360  // Analyze all machine instructions to find gadgets and LFENCEs, adding
361  // each interesting value to `Nodes`
362  auto AnalyzeDef = [&](NodeAddr<DefNode *> SourceDef) {
363  SmallSet<NodeId, 8> UsesVisited, DefsVisited;
364  std::function<void(NodeAddr<DefNode *>)> AnalyzeDefUseChain =
365  [&](NodeAddr<DefNode *> Def) {
366  if (Transmitters.find(Def.Id) != Transmitters.end())
367  return; // Already analyzed `Def`
368 
369  // Use RDF to find all the uses of `Def`
371  RegisterRef DefReg = Def.Addr->getRegRef(DFG);
372  for (auto UseID : L.getAllReachedUses(DefReg, Def)) {
373  auto Use = DFG.addr<UseNode *>(UseID);
374  if (Use.Addr->getFlags() & NodeAttrs::PhiRef) { // phi node
375  NodeAddr<PhiNode *> Phi = Use.Addr->getOwner(DFG);
376  for (const auto& I : L.getRealUses(Phi.Id)) {
377  if (DFG.getPRI().alias(RegisterRef(I.first), DefReg)) {
378  for (const auto &UA : I.second)
379  Uses.emplace(UA.first);
380  }
381  }
382  } else { // not a phi node
383  Uses.emplace(UseID);
384  }
385  }
386 
387  // For each use of `Def`, we want to know whether:
388  // (1) The use can leak the Def'ed value,
389  // (2) The use can further propagate the Def'ed value to more defs
390  for (auto UseID : Uses) {
391  if (!UsesVisited.insert(UseID).second)
392  continue; // Already visited this use of `Def`
393 
394  auto Use = DFG.addr<UseNode *>(UseID);
395  assert(!(Use.Addr->getFlags() & NodeAttrs::PhiRef));
396  MachineOperand &UseMO = Use.Addr->getOp();
397  MachineInstr &UseMI = *UseMO.getParent();
398  assert(UseMO.isReg());
399 
400  // We naively assume that an instruction propagates any loaded
401  // uses to all defs unless the instruction is a call, in which
402  // case all arguments will be treated as gadget sources during
403  // analysis of the callee function.
404  if (UseMI.isCall())
405  continue;
406 
407  // Check whether this use can transmit (leak) its value.
408  if (instrUsesRegToAccessMemory(UseMI, UseMO.getReg()) ||
410  instrUsesRegToBranch(UseMI, UseMO.getReg()))) {
411  Transmitters[Def.Id].push_back(Use.Addr->getOwner(DFG).Id);
412  if (UseMI.mayLoad())
413  continue; // Found a transmitting load -- no need to continue
414  // traversing its defs (i.e., this load will become
415  // a new gadget source anyways).
416  }
417 
418  // Check whether the use propagates to more defs.
419  NodeAddr<InstrNode *> Owner{Use.Addr->getOwner(DFG)};
420  rdf::NodeList AnalyzedChildDefs;
421  for (const auto &ChildDef :
422  Owner.Addr->members_if(DataFlowGraph::IsDef, DFG)) {
423  if (!DefsVisited.insert(ChildDef.Id).second)
424  continue; // Already visited this def
425  if (Def.Addr->getAttrs() & NodeAttrs::Dead)
426  continue;
427  if (Def.Id == ChildDef.Id)
428  continue; // `Def` uses itself (e.g., increment loop counter)
429 
430  AnalyzeDefUseChain(ChildDef);
431 
432  // `Def` inherits all of its child defs' transmitters.
433  for (auto TransmitterId : Transmitters[ChildDef.Id])
434  Transmitters[Def.Id].push_back(TransmitterId);
435  }
436  }
437 
438  // Note that this statement adds `Def.Id` to the map if no
439  // transmitters were found for `Def`.
440  auto &DefTransmitters = Transmitters[Def.Id];
441 
442  // Remove duplicate transmitters
443  llvm::sort(DefTransmitters);
444  DefTransmitters.erase(
445  std::unique(DefTransmitters.begin(), DefTransmitters.end()),
446  DefTransmitters.end());
447  };
448 
449  // Find all of the transmitters
450  AnalyzeDefUseChain(SourceDef);
451  auto &SourceDefTransmitters = Transmitters[SourceDef.Id];
452  if (SourceDefTransmitters.empty())
453  return; // No transmitters for `SourceDef`
454 
455  MachineInstr *Source = SourceDef.Addr->getFlags() & NodeAttrs::PhiRef
456  ? MachineGadgetGraph::ArgNodeSentinel
457  : SourceDef.Addr->getOp().getParent();
458  auto GadgetSource = MaybeAddNode(Source);
459  // Each transmitter is a sink for `SourceDef`.
460  for (auto TransmitterId : SourceDefTransmitters) {
461  MachineInstr *Sink = DFG.addr<StmtNode *>(TransmitterId).Addr->getCode();
462  auto GadgetSink = MaybeAddNode(Sink);
463  // Add the gadget edge to the graph.
464  Builder.addEdge(MachineGadgetGraph::GadgetEdgeSentinel,
465  GadgetSource.first, GadgetSink.first);
466  ++GadgetCount;
467  }
468  };
469 
470  LLVM_DEBUG(dbgs() << "Analyzing def-use chains to find gadgets\n");
471  // Analyze function arguments
472  NodeAddr<BlockNode *> EntryBlock = DFG.getFunc().Addr->getEntryBlock(DFG);
473  for (NodeAddr<PhiNode *> ArgPhi :
474  EntryBlock.Addr->members_if(DataFlowGraph::IsPhi, DFG)) {
475  NodeList Defs = ArgPhi.Addr->members_if(DataFlowGraph::IsDef, DFG);
476  llvm::for_each(Defs, AnalyzeDef);
477  }
478  // Analyze every instruction in MF
479  for (NodeAddr<BlockNode *> BA : DFG.getFunc().Addr->members(DFG)) {
480  for (NodeAddr<StmtNode *> SA :
481  BA.Addr->members_if(DataFlowGraph::IsCode<NodeAttrs::Stmt>, DFG)) {
482  MachineInstr *MI = SA.Addr->getCode();
483  if (isFence(MI)) {
484  MaybeAddNode(MI);
485  ++FenceCount;
486  } else if (MI->mayLoad()) {
487  NodeList Defs = SA.Addr->members_if(DataFlowGraph::IsDef, DFG);
488  llvm::for_each(Defs, AnalyzeDef);
489  }
490  }
491  }
492  LLVM_DEBUG(dbgs() << "Found " << FenceCount << " fences\n");
493  LLVM_DEBUG(dbgs() << "Found " << GadgetCount << " gadgets\n");
494  if (GadgetCount == 0)
495  return nullptr;
496  NumGadgets += GadgetCount;
497 
498  // Traverse CFG to build the rest of the graph
499  SmallSet<MachineBasicBlock *, 8> BlocksVisited;
500  std::function<void(MachineBasicBlock *, GraphIter, unsigned)> TraverseCFG =
501  [&](MachineBasicBlock *MBB, GraphIter GI, unsigned ParentDepth) {
502  unsigned LoopDepth = MLI.getLoopDepth(MBB);
503  if (!MBB->empty()) {
504  // Always add the first instruction in each block
505  auto NI = MBB->begin();
506  auto BeginBB = MaybeAddNode(&*NI);
507  Builder.addEdge(ParentDepth, GI, BeginBB.first);
508  if (!BlocksVisited.insert(MBB).second)
509  return;
510 
511  // Add any instructions within the block that are gadget components
512  GI = BeginBB.first;
513  while (++NI != MBB->end()) {
514  auto Ref = NodeMap.find(&*NI);
515  if (Ref != NodeMap.end()) {
516  Builder.addEdge(LoopDepth, GI, Ref->getSecond());
517  GI = Ref->getSecond();
518  }
519  }
520 
521  // Always add the terminator instruction, if one exists
522  auto T = MBB->getFirstTerminator();
523  if (T != MBB->end()) {
524  auto EndBB = MaybeAddNode(&*T);
525  if (EndBB.second)
526  Builder.addEdge(LoopDepth, GI, EndBB.first);
527  GI = EndBB.first;
528  }
529  }
530  for (MachineBasicBlock *Succ : MBB->successors())
531  TraverseCFG(Succ, GI, LoopDepth);
532  };
533  // ArgNodeSentinel is a pseudo-instruction that represents MF args in the
534  // GadgetGraph
535  GraphIter ArgNode = MaybeAddNode(MachineGadgetGraph::ArgNodeSentinel).first;
536  TraverseCFG(&MF.front(), ArgNode, 0);
537  std::unique_ptr<MachineGadgetGraph> G{Builder.get(FenceCount, GadgetCount)};
538  LLVM_DEBUG(dbgs() << "Found " << G->nodes_size() << " nodes\n");
539  return G;
540 }
541 
542 // Returns the number of remaining gadget edges that could not be eliminated
543 int X86LoadValueInjectionLoadHardeningPass::elimMitigatedEdgesAndNodes(
544  MachineGadgetGraph &G, EdgeSet &ElimEdges /* in, out */,
545  NodeSet &ElimNodes /* in, out */) const {
546  if (G.NumFences > 0) {
547  // Eliminate fences and CFG edges that ingress and egress the fence, as
548  // they are trivially mitigated.
549  for (const Edge &E : G.edges()) {
550  const Node *Dest = E.getDest();
551  if (isFence(Dest->getValue())) {
552  ElimNodes.insert(*Dest);
553  ElimEdges.insert(E);
554  for (const Edge &DE : Dest->edges())
555  ElimEdges.insert(DE);
556  }
557  }
558  }
559 
560  // Find and eliminate gadget edges that have been mitigated.
561  int RemainingGadgets = 0;
562  NodeSet ReachableNodes{G};
563  for (const Node &RootN : G.nodes()) {
564  if (llvm::none_of(RootN.edges(), MachineGadgetGraph::isGadgetEdge))
565  continue; // skip this node if it isn't a gadget source
566 
567  // Find all of the nodes that are CFG-reachable from RootN using DFS
568  ReachableNodes.clear();
569  std::function<void(const Node *, bool)> FindReachableNodes =
570  [&](const Node *N, bool FirstNode) {
571  if (!FirstNode)
572  ReachableNodes.insert(*N);
573  for (const Edge &E : N->edges()) {
574  const Node *Dest = E.getDest();
575  if (MachineGadgetGraph::isCFGEdge(E) && !ElimEdges.contains(E) &&
576  !ReachableNodes.contains(*Dest))
577  FindReachableNodes(Dest, false);
578  }
579  };
580  FindReachableNodes(&RootN, true);
581 
582  // Any gadget whose sink is unreachable has been mitigated
583  for (const Edge &E : RootN.edges()) {
584  if (MachineGadgetGraph::isGadgetEdge(E)) {
585  if (ReachableNodes.contains(*E.getDest())) {
586  // This gadget's sink is reachable
587  ++RemainingGadgets;
588  } else { // This gadget's sink is unreachable, and therefore mitigated
589  ElimEdges.insert(E);
590  }
591  }
592  }
593  }
594  return RemainingGadgets;
595 }
596 
597 std::unique_ptr<MachineGadgetGraph>
598 X86LoadValueInjectionLoadHardeningPass::trimMitigatedEdges(
599  std::unique_ptr<MachineGadgetGraph> Graph) const {
600  NodeSet ElimNodes{*Graph};
601  EdgeSet ElimEdges{*Graph};
602  int RemainingGadgets =
603  elimMitigatedEdgesAndNodes(*Graph, ElimEdges, ElimNodes);
604  if (ElimEdges.empty() && ElimNodes.empty()) {
605  Graph->NumFences = 0;
606  Graph->NumGadgets = RemainingGadgets;
607  } else {
608  Graph = GraphBuilder::trim(*Graph, ElimNodes, ElimEdges, 0 /* NumFences */,
609  RemainingGadgets);
610  }
611  return Graph;
612 }
613 
614 int X86LoadValueInjectionLoadHardeningPass::hardenLoadsWithPlugin(
615  MachineFunction &MF, std::unique_ptr<MachineGadgetGraph> Graph) const {
616  int FencesInserted = 0;
617 
618  do {
619  LLVM_DEBUG(dbgs() << "Eliminating mitigated paths...\n");
620  Graph = trimMitigatedEdges(std::move(Graph));
621  LLVM_DEBUG(dbgs() << "Eliminating mitigated paths... Done\n");
622  if (Graph->NumGadgets == 0)
623  break;
624 
625  LLVM_DEBUG(dbgs() << "Cutting edges...\n");
626  EdgeSet CutEdges{*Graph};
627  auto Nodes = std::make_unique<unsigned int[]>(Graph->nodes_size() +
628  1 /* terminator node */);
629  auto Edges = std::make_unique<unsigned int[]>(Graph->edges_size());
630  auto EdgeCuts = std::make_unique<int[]>(Graph->edges_size());
631  auto EdgeValues = std::make_unique<int[]>(Graph->edges_size());
632  for (const Node &N : Graph->nodes()) {
633  Nodes[Graph->getNodeIndex(N)] = Graph->getEdgeIndex(*N.edges_begin());
634  }
635  Nodes[Graph->nodes_size()] = Graph->edges_size(); // terminator node
636  for (const Edge &E : Graph->edges()) {
637  Edges[Graph->getEdgeIndex(E)] = Graph->getNodeIndex(*E.getDest());
638  EdgeValues[Graph->getEdgeIndex(E)] = E.getValue();
639  }
640  OptimizeCut(Nodes.get(), Graph->nodes_size(), Edges.get(), EdgeValues.get(),
641  EdgeCuts.get(), Graph->edges_size());
642  for (int I = 0; I < Graph->edges_size(); ++I)
643  if (EdgeCuts[I])
644  CutEdges.set(I);
645  LLVM_DEBUG(dbgs() << "Cutting edges... Done\n");
646  LLVM_DEBUG(dbgs() << "Cut " << CutEdges.count() << " edges\n");
647 
648  LLVM_DEBUG(dbgs() << "Inserting LFENCEs...\n");
649  FencesInserted += insertFences(MF, *Graph, CutEdges);
650  LLVM_DEBUG(dbgs() << "Inserting LFENCEs... Done\n");
651  LLVM_DEBUG(dbgs() << "Inserted " << FencesInserted << " fences\n");
652 
653  Graph = GraphBuilder::trim(*Graph, NodeSet{*Graph}, CutEdges);
654  } while (true);
655 
656  return FencesInserted;
657 }
658 
659 int X86LoadValueInjectionLoadHardeningPass::hardenLoadsWithHeuristic(
660  MachineFunction &MF, std::unique_ptr<MachineGadgetGraph> Graph) const {
661  // If `MF` does not have any fences, then no gadgets would have been
662  // mitigated at this point.
663  if (Graph->NumFences > 0) {
664  LLVM_DEBUG(dbgs() << "Eliminating mitigated paths...\n");
665  Graph = trimMitigatedEdges(std::move(Graph));
666  LLVM_DEBUG(dbgs() << "Eliminating mitigated paths... Done\n");
667  }
668 
669  if (Graph->NumGadgets == 0)
670  return 0;
671 
672  LLVM_DEBUG(dbgs() << "Cutting edges...\n");
673  EdgeSet CutEdges{*Graph};
674 
675  // Begin by collecting all ingress CFG edges for each node
677  for (const Edge &E : Graph->edges())
678  if (MachineGadgetGraph::isCFGEdge(E))
679  IngressEdgeMap[E.getDest()].push_back(&E);
680 
681  // For each gadget edge, make cuts that guarantee the gadget will be
682  // mitigated. A computationally efficient way to achieve this is to either:
683  // (a) cut all egress CFG edges from the gadget source, or
684  // (b) cut all ingress CFG edges to the gadget sink.
685  //
686  // Moreover, the algorithm tries not to make a cut into a loop by preferring
687  // to make a (b)-type cut if the gadget source resides at a greater loop depth
688  // than the gadget sink, or an (a)-type cut otherwise.
689  for (const Node &N : Graph->nodes()) {
690  for (const Edge &E : N.edges()) {
691  if (!MachineGadgetGraph::isGadgetEdge(E))
692  continue;
693 
694  SmallVector<const Edge *, 2> EgressEdges;
695  SmallVector<const Edge *, 2> &IngressEdges = IngressEdgeMap[E.getDest()];
696  for (const Edge &EgressEdge : N.edges())
697  if (MachineGadgetGraph::isCFGEdge(EgressEdge))
698  EgressEdges.push_back(&EgressEdge);
699 
700  int EgressCutCost = 0, IngressCutCost = 0;
701  for (const Edge *EgressEdge : EgressEdges)
702  if (!CutEdges.contains(*EgressEdge))
703  EgressCutCost += EgressEdge->getValue();
704  for (const Edge *IngressEdge : IngressEdges)
705  if (!CutEdges.contains(*IngressEdge))
706  IngressCutCost += IngressEdge->getValue();
707 
708  auto &EdgesToCut =
709  IngressCutCost < EgressCutCost ? IngressEdges : EgressEdges;
710  for (const Edge *E : EdgesToCut)
711  CutEdges.insert(*E);
712  }
713  }
714  LLVM_DEBUG(dbgs() << "Cutting edges... Done\n");
715  LLVM_DEBUG(dbgs() << "Cut " << CutEdges.count() << " edges\n");
716 
717  LLVM_DEBUG(dbgs() << "Inserting LFENCEs...\n");
718  int FencesInserted = insertFences(MF, *Graph, CutEdges);
719  LLVM_DEBUG(dbgs() << "Inserting LFENCEs... Done\n");
720  LLVM_DEBUG(dbgs() << "Inserted " << FencesInserted << " fences\n");
721 
722  return FencesInserted;
723 }
724 
725 int X86LoadValueInjectionLoadHardeningPass::insertFences(
726  MachineFunction &MF, MachineGadgetGraph &G,
727  EdgeSet &CutEdges /* in, out */) const {
728  int FencesInserted = 0;
729  for (const Node &N : G.nodes()) {
730  for (const Edge &E : N.edges()) {
731  if (CutEdges.contains(E)) {
732  MachineInstr *MI = N.getValue(), *Prev;
733  MachineBasicBlock *MBB; // Insert an LFENCE in this MBB
734  MachineBasicBlock::iterator InsertionPt; // ...at this point
735  if (MI == MachineGadgetGraph::ArgNodeSentinel) {
736  // insert LFENCE at beginning of entry block
737  MBB = &MF.front();
738  InsertionPt = MBB->begin();
739  Prev = nullptr;
740  } else if (MI->isBranch()) { // insert the LFENCE before the branch
741  MBB = MI->getParent();
742  InsertionPt = MI;
743  Prev = MI->getPrevNode();
744  // Remove all egress CFG edges from this branch because the inserted
745  // LFENCE prevents gadgets from crossing the branch.
746  for (const Edge &E : N.edges()) {
747  if (MachineGadgetGraph::isCFGEdge(E))
748  CutEdges.insert(E);
749  }
750  } else { // insert the LFENCE after the instruction
751  MBB = MI->getParent();
752  InsertionPt = MI->getNextNode() ? MI->getNextNode() : MBB->end();
753  Prev = InsertionPt == MBB->end()
754  ? (MBB->empty() ? nullptr : &MBB->back())
755  : InsertionPt->getPrevNode();
756  }
757  // Ensure this insertion is not redundant (two LFENCEs in sequence).
758  if ((InsertionPt == MBB->end() || !isFence(&*InsertionPt)) &&
759  (!Prev || !isFence(Prev))) {
760  BuildMI(*MBB, InsertionPt, DebugLoc(), TII->get(X86::LFENCE));
761  ++FencesInserted;
762  }
763  }
764  }
765  }
766  return FencesInserted;
767 }
768 
769 bool X86LoadValueInjectionLoadHardeningPass::instrUsesRegToAccessMemory(
770  const MachineInstr &MI, unsigned Reg) const {
771  if (!MI.mayLoadOrStore() || MI.getOpcode() == X86::MFENCE ||
772  MI.getOpcode() == X86::SFENCE || MI.getOpcode() == X86::LFENCE)
773  return false;
774 
775  // FIXME: This does not handle pseudo loading instruction like TCRETURN*
776  const MCInstrDesc &Desc = MI.getDesc();
777  int MemRefBeginIdx = X86II::getMemoryOperandNo(Desc.TSFlags);
778  if (MemRefBeginIdx < 0) {
779  LLVM_DEBUG(dbgs() << "Warning: unable to obtain memory operand for loading "
780  "instruction:\n";
781  MI.print(dbgs()); dbgs() << '\n';);
782  return false;
783  }
784  MemRefBeginIdx += X86II::getOperandBias(Desc);
785 
786  const MachineOperand &BaseMO =
787  MI.getOperand(MemRefBeginIdx + X86::AddrBaseReg);
788  const MachineOperand &IndexMO =
789  MI.getOperand(MemRefBeginIdx + X86::AddrIndexReg);
790  return (BaseMO.isReg() && BaseMO.getReg() != X86::NoRegister &&
791  TRI->regsOverlap(BaseMO.getReg(), Reg)) ||
792  (IndexMO.isReg() && IndexMO.getReg() != X86::NoRegister &&
793  TRI->regsOverlap(IndexMO.getReg(), Reg));
794 }
795 
796 bool X86LoadValueInjectionLoadHardeningPass::instrUsesRegToBranch(
797  const MachineInstr &MI, unsigned Reg) const {
798  if (!MI.isConditionalBranch())
799  return false;
800  for (const MachineOperand &Use : MI.uses())
801  if (Use.isReg() && Use.getReg() == Reg)
802  return true;
803  return false;
804 }
805 
806 INITIALIZE_PASS_BEGIN(X86LoadValueInjectionLoadHardeningPass, PASS_KEY,
807  "X86 LVI load hardening", false, false)
811 INITIALIZE_PASS_END(X86LoadValueInjectionLoadHardeningPass, PASS_KEY,
813 
815  return new X86LoadValueInjectionLoadHardeningPass();
816 }
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:104
MachineInstr.h
llvm::DOTGraphTraits< MachineGadgetGraph * >::NodeRef
typename Traits::NodeRef NodeRef
Definition: X86LoadValueInjectionLoadHardening.cpp:196
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::X86II::getMemoryOperandNo
int getMemoryOperandNo(uint64_t TSFlags)
The function returns the MCInst operand # for the first field of the memory operand.
Definition: X86BaseInfo.h:1095
llvm::tgtok::Def
@ Def
Definition: TGLexer.h:50
llvm::ImmutableGraph
Definition: ImmutableGraph.h:38
UseMI
MachineInstrBuilder & UseMI
Definition: AArch64ExpandPseudoInsts.cpp:103
llvm::none_of
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1621
llvm::ImmutableGraphBuilder
Definition: ImmutableGraph.h:294
X86Subtarget.h
llvm::sys::DynamicLibrary::getAddressOfSymbol
void * getAddressOfSymbol(const char *symbolName)
Searches through the library for the symbol symbolName.
Definition: DynamicLibrary.cpp:168
T
llvm::DOTGraphTraits< MachineGadgetGraph * >::getNodeAttributes
static std::string getNodeAttributes(NodeRef Node, GraphType *)
Definition: X86LoadValueInjectionLoadHardening.cpp:213
llvm::Function
Definition: Function.h:60
StringRef.h
llvm::raw_string_ostream
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:632
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
Statistic.h
llvm::DOTGraphTraits< MachineGadgetGraph * >::EdgeRef
typename Traits::EdgeRef EdgeRef
Definition: X86LoadValueInjectionLoadHardening.cpp:197
llvm::X86Subtarget
Definition: X86Subtarget.h:52
llvm::X86Disassembler::Reg
Reg
All possible values of the reg field in the ModR/M byte.
Definition: X86DisassemblerDecoder.h:462
writeGadgetGraph
static void writeGadgetGraph(raw_ostream &OS, MachineFunction &MF, MachineGadgetGraph *G)
Definition: X86LoadValueInjectionLoadHardening.cpp:246
llvm::MachineFunctionPass
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Definition: MachineFunctionPass.h:30
llvm::rdf::NodeAttrs::PhiRef
@ PhiRef
Definition: RDFGraph.h:286
MachineBasicBlock.h
llvm::cl::Hidden
@ Hidden
Definition: CommandLine.h:139
llvm::DOTGraphTraits< MachineGadgetGraph * >::DOTGraphTraits
DOTGraphTraits(bool IsSimple=false)
Definition: X86LoadValueInjectionLoadHardening.cpp:201
llvm::TargetRegisterInfo
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Definition: TargetRegisterInfo.h:234
DynamicLibrary.h
DenseMap.h
llvm::FileError
This class wraps a filename and another Error.
Definition: Error.h:1263
llvm::SmallSet
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:136
OptimizePluginPath
static cl::opt< std::string > OptimizePluginPath(PASS_KEY "-opt-plugin", cl::desc("Specify a plugin to optimize LFENCE insertion"), cl::Hidden)
ImmutableGraph.h
llvm::errs
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: raw_ostream.cpp:893
llvm::NodeSet::empty
bool empty() const
Definition: MachinePipeliner.h:368
STLExtras.h
llvm::MachineBasicBlock::back
MachineInstr & back()
Definition: MachineBasicBlock.h:257
TRI
unsigned const TargetRegisterInfo * TRI
Definition: MachineSink.cpp:1618
PASS_KEY
#define PASS_KEY
Definition: X86LoadValueInjectionLoadHardening.cpp:70
EmitDot
static cl::opt< bool > EmitDot(PASS_KEY "-dot", cl::desc("For each function, emit a dot graph depicting potential LVI gadgets"), cl::init(false), cl::Hidden)
llvm::MachineFunctionPass::getAnalysisUsage
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Definition: MachineFunctionPass.cpp:103
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::sys::DynamicLibrary
This class provides a portable interface to dynamic libraries which also might be known as shared lib...
Definition: DynamicLibrary.h:36
F
#define F(x, y, z)
Definition: MD5.cpp:55
llvm::MachineLoopInfo
Definition: MachineLoopInfo.h:89
MachineRegisterInfo.h
Uses
SmallPtrSet< MachineInstr *, 2 > Uses
Definition: ARMLowOverheadLoops.cpp:585
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
CommandLine.h
RDFLiveness.h
llvm::MachineFunction::front
const MachineBasicBlock & front() const
Definition: MachineFunction.h:834
llvm::MachineFunction::getRegInfo
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Definition: MachineFunction.h:650
llvm::MCInstrDesc::TSFlags
uint64_t TSFlags
Definition: MCInstrDesc.h:205
X86.h
llvm::TargetInstrInfo
TargetInstrInfo - Interface to description of machine instruction set.
Definition: TargetInstrInfo.h:97
MachineLoopInfo.h
llvm::ModRefInfo::Ref
@ Ref
The access may reference the value stored in memory.
llvm::outs
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
Definition: raw_ostream.cpp:885
INITIALIZE_PASS_BEGIN
INITIALIZE_PASS_BEGIN(X86LoadValueInjectionLoadHardeningPass, PASS_KEY, "X86 LVI load hardening", false, false) INITIALIZE_PASS_END(X86LoadValueInjectionLoadHardeningPass
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::sys::DynamicLibrary::getPermanentLibrary
static DynamicLibrary getPermanentLibrary(const char *filename, std::string *errMsg=nullptr)
This function permanently loads the dynamic library at the given path.
Definition: DynamicLibrary.cpp:143
int
Clang compiles this i1 i64 store i64 i64 store i64 i64 store i64 i64 store i64 align Which gets codegen d xmm0 movaps rbp movaps rbp movaps rbp movaps rbp rbp rbp rbp rbp It would be better to have movq s of instead of the movaps s LLVM produces ret int
Definition: README.txt:536
llvm::AnalysisUsage
Represent the analysis usage information of a pass.
Definition: PassAnalysisSupport.h:47
DenseSet.h
false
Definition: StackSlotColoring.cpp:141
llvm::X86ISD::MFENCE
@ MFENCE
Definition: X86ISelLowering.h:664
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:127
llvm::MCInstrDesc
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:197
llvm::MachineOperand
MachineOperand class - Representation of each machine instruction operand.
Definition: MachineOperand.h:48
NodeList
Definition: MicrosoftDemangle.cpp:37
llvm::X86::AddrIndexReg
@ AddrIndexReg
Definition: X86BaseInfo.h:34
llvm::report_fatal_error
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:143
llvm::STATISTIC
STATISTIC(NumFunctions, "Total number of functions")
llvm::rdf::detail::NodeRef
std::pair< NodeId, LaneBitmask > NodeRef
Definition: RDFLiveness.h:39
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:54
llvm::rdf::DataFlowGraph::IsDef
static bool IsDef(const NodeAddr< NodeBase * > BA)
Definition: RDFGraph.h:793
llvm::DOTGraphTraits< MachineGadgetGraph * >::ChildIteratorType
typename Traits::ChildIteratorType ChildIteratorType
Definition: X86LoadValueInjectionLoadHardening.cpp:198
llvm::NodeSet
A NodeSet contains a set of SUnit DAG nodes with additional information that assigns a priority to th...
Definition: MachinePipeliner.h:320
llvm::sys::DynamicLibrary::isValid
bool isValid() const
Returns true if the object refers to a valid library.
Definition: DynamicLibrary.h:49
llvm::MachineOperand::getParent
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Definition: MachineOperand.h:237
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
llvm::ErrorInfoBase::message
virtual std::string message() const
Return the error message as a string.
Definition: Error.h:54
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:94
INITIALIZE_PASS_END
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:58
llvm::Pass::print
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
Definition: Pass.cpp:129
llvm::DOTGraphTraits
DOTGraphTraits - Template class that can be specialized to customize how graphs are converted to 'dot...
Definition: DOTGraphTraits.h:166
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:200
llvm::MachineFunction::getSubtarget
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Definition: MachineFunction.h:640
llvm::cl::opt
Definition: CommandLine.h:1392
llvm::X86II::getOperandBias
unsigned getOperandBias(const MCInstrDesc &Desc)
Compute whether all of the def operands are repeated in the uses and therefore should be skipped.
Definition: X86BaseInfo.h:1055
llvm::TargetRegisterInfo::regsOverlap
bool regsOverlap(Register RegA, Register RegB) const
Returns true if the two registers are equal or alias each other.
Definition: TargetRegisterInfo.h:419
llvm::MachineOperand::isReg
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Definition: MachineOperand.h:320
llvm::MachineInstr
Representation of each machine instruction.
Definition: MachineInstr.h:66
llvm::for_each
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1600
llvm::MachineDominanceFrontier
Definition: MachineDominanceFrontier.h:20
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:78
INITIALIZE_PASS_DEPENDENCY
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
OptimizeDL
static llvm::sys::DynamicLibrary OptimizeDL
Definition: X86LoadValueInjectionLoadHardening.cpp:107
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::DenseMap
Definition: DenseMap.h:716
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::X86::AddrBaseReg
@ AddrBaseReg
Definition: X86BaseInfo.h:32
llvm::cl::init
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:432
MachineFunctionPass.h
llvm::DenseMapBase< DenseMap< KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >, KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >::find
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:152
llvm::MachineFunction::getName
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Definition: MachineFunction.cpp:567
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::rdf::DataFlowGraph::IsPhi
static bool IsPhi(const NodeAddr< NodeBase * > BA)
Definition: RDFGraph.h:803
load
LLVM currently emits rax rax movq rax rax ret It could narrow the loads and stores to emit rax rax movq rax rax ret The trouble is that there is a TokenFactor between the store and the load
Definition: README.txt:1531
llvm::WriteGraph
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
Definition: GraphWriter.h:359
function
print Print MemDeps of function
Definition: MemDepPrinter.cpp:82
llvm::MachineOperand::getReg
Register getReg() const
getReg - Returns the register number.
Definition: MachineOperand.h:359
Builder
assume Assume Builder
Definition: AssumeBundleBuilder.cpp:651
llvm::MachineFunction
Definition: MachineFunction.h:241
llvm::MachineBasicBlock::getFirstTerminator
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
Definition: MachineBasicBlock.cpp:238
llvm::Sched::Source
@ Source
Definition: TargetLowering.h:99
llvm::MachineBasicBlock::successors
iterator_range< succ_iterator > successors()
Definition: MachineBasicBlock.h:364
llvm::AnalysisUsage::setPreservesCFG
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:263
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
RDFGraph.h
llvm::cl::Sink
@ Sink
Definition: CommandLine.h:167
OptimizeCut
static OptimizeCutT OptimizeCut
Definition: X86LoadValueInjectionLoadHardening.cpp:111
llvm::SmallSet::insert
std::pair< NoneType, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:182
llvm::raw_fd_ostream
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:444
llvm::rdf::NodeAttrs::Dead
@ Dead
Definition: RDFGraph.h:290
MBB
MachineBasicBlock & MBB
Definition: AArch64SLSHardening.cpp:74
llvm::createX86LoadValueInjectionLoadHardeningPass
FunctionPass * createX86LoadValueInjectionLoadHardeningPass()
Definition: X86LoadValueInjectionLoadHardening.cpp:814
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
GraphWriter.h
llvm::MachineFunction::getFunction
Function & getFunction()
Return the LLVM function that this machine code represents.
Definition: MachineFunction.h:606
llvm::DenseMapBase< DenseMap< KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >, KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >::end
iterator end()
Definition: DenseMap.h:84
X86TargetMachine.h
MachineDominanceFrontier.h
DOTGraphTraits.h
llvm::sort
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1552
llvm::unique
auto unique(Range &&R, Predicate P)
Definition: STLExtras.h:1769
EmitDotVerify
static cl::opt< bool > EmitDotVerify(PASS_KEY "-dot-verify", cl::desc("For each function, emit a dot graph to stdout depicting " "potential LVI gadgets, used for testing purposes only"), cl::init(false), cl::Hidden)
llvm::MachineLoopInfo::getLoopDepth
unsigned getLoopDepth(const MachineBasicBlock *BB) const
Return the loop nesting level of the specified block.
Definition: MachineLoopInfo.h:136
OptimizeCutT
int(* OptimizeCutT)(unsigned int *Nodes, unsigned int NodesSize, unsigned int *Edges, int *EdgeValues, int *CutEdges, unsigned int EdgesSize)
Definition: X86LoadValueInjectionLoadHardening.cpp:108
llvm::DOTGraphTraits< MachineGadgetGraph * >::getEdgeAttributes
static std::string getEdgeAttributes(NodeRef, ChildIteratorType E, GraphType *)
Definition: X86LoadValueInjectionLoadHardening.cpp:222
llvm::MachineBasicBlock::begin
iterator begin()
Definition: MachineBasicBlock.h:277
llvm::rdf::NodeSet
std::set< NodeId > NodeSet
Definition: RDFGraph.h:513
MachineInstrBuilder.h
llvm::DOTGraphTraits< MachineGadgetGraph * >::getNodeLabel
std::string getNodeLabel(NodeRef Node, GraphType *)
Definition: X86LoadValueInjectionLoadHardening.cpp:203
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
N
#define N
llvm::to_string
std::string to_string(const T &Value)
Definition: ScopedPrinter.h:86
llvm::MachineBasicBlock::empty
bool empty() const
Definition: MachineBasicBlock.h:249
hardening
X86 LVI load hardening
Definition: X86LoadValueInjectionLoadHardening.cpp:812
llvm::DefaultDOTGraphTraits
DefaultDOTGraphTraits - This class provides the default implementations of all of the DOTGraphTraits ...
Definition: DOTGraphTraits.h:28
llvm::NodeSet::insert
bool insert(SUnit *SU)
Definition: MachinePipeliner.h:354
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
llvm::AnalysisUsage::addRequired
AnalysisUsage & addRequired()
Definition: PassAnalysisSupport.h:75
llvm::GraphTraits
Definition: GraphTraits.h:37
llvm::DebugLoc
A debug info location.
Definition: DebugLoc.h:33
llvm::cl::desc
Definition: CommandLine.h:405
NoConditionalBranches
static cl::opt< bool > NoConditionalBranches(PASS_KEY "-no-cbranch", cl::desc("Don't treat conditional branches as disclosure gadgets. This " "may improve performance, at the cost of security."), cl::init(false), cl::Hidden)
raw_ostream.h
llvm::MachineDominatorTree
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
Definition: MachineDominators.h:51
MachineFunction.h
llvm::DOTGraphTraits< MachineGadgetGraph * >::ChildEdgeIteratorType
typename Traits::ChildEdgeIteratorType ChildEdgeIteratorType
Definition: X86LoadValueInjectionLoadHardening.cpp:199
llvm::DOTGraphTraits< MachineGadgetGraph * >::GraphType
MachineGadgetGraph GraphType
Definition: X86LoadValueInjectionLoadHardening.cpp:194
X86
Unrolling by would eliminate the &in both leading to a net reduction in code size The resultant code would then also be suitable for exit value computation We miss a bunch of rotate opportunities on various including etc On X86
Definition: README.txt:568
llvm::MachineInstrBundleIterator< MachineInstr >
llvm::raw_string_ostream::str
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:650
InitializePasses.h
Debug.h
llvm::MachineBasicBlock::end
iterator end()
Definition: MachineBasicBlock.h:279
EmitDotOnly
static cl::opt< bool > EmitDotOnly(PASS_KEY "-dot-only", cl::desc("For each function, emit a dot graph depicting potential LVI " "gadgets, and do not insert any fences"), cl::init(false), cl::Hidden)
llvm::Use
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
MachineDominators.h
SmallSet.h
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37
llvm::SmallVectorImpl::insert
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:792