X86LoadValueInjectionLoadHardening.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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. #include "ImmutableGraph.h"
  39. #include "X86.h"
  40. #include "X86Subtarget.h"
  41. #include "X86TargetMachine.h"
  42. #include "llvm/ADT/DenseMap.h"
  43. #include "llvm/ADT/DenseSet.h"
  44. #include "llvm/ADT/STLExtras.h"
  45. #include "llvm/ADT/SmallSet.h"
  46. #include "llvm/ADT/Statistic.h"
  47. #include "llvm/ADT/StringRef.h"
  48. #include "llvm/CodeGen/MachineBasicBlock.h"
  49. #include "llvm/CodeGen/MachineDominanceFrontier.h"
  50. #include "llvm/CodeGen/MachineDominators.h"
  51. #include "llvm/CodeGen/MachineFunction.h"
  52. #include "llvm/CodeGen/MachineFunctionPass.h"
  53. #include "llvm/CodeGen/MachineInstr.h"
  54. #include "llvm/CodeGen/MachineInstrBuilder.h"
  55. #include "llvm/CodeGen/MachineLoopInfo.h"
  56. #include "llvm/CodeGen/MachineRegisterInfo.h"
  57. #include "llvm/CodeGen/RDFGraph.h"
  58. #include "llvm/CodeGen/RDFLiveness.h"
  59. #include "llvm/InitializePasses.h"
  60. #include "llvm/Support/CommandLine.h"
  61. #include "llvm/Support/DOTGraphTraits.h"
  62. #include "llvm/Support/Debug.h"
  63. #include "llvm/Support/DynamicLibrary.h"
  64. #include "llvm/Support/GraphWriter.h"
  65. #include "llvm/Support/raw_ostream.h"
  66. using namespace llvm;
  67. #define PASS_KEY "x86-lvi-load"
  68. #define DEBUG_TYPE PASS_KEY
  69. STATISTIC(NumFences, "Number of LFENCEs inserted for LVI mitigation");
  70. STATISTIC(NumFunctionsConsidered, "Number of functions analyzed");
  71. STATISTIC(NumFunctionsMitigated, "Number of functions for which mitigations "
  72. "were deployed");
  73. STATISTIC(NumGadgets, "Number of LVI gadgets detected during analysis");
  74. static cl::opt<std::string> OptimizePluginPath(
  75. PASS_KEY "-opt-plugin",
  76. cl::desc("Specify a plugin to optimize LFENCE insertion"), cl::Hidden);
  77. static cl::opt<bool> NoConditionalBranches(
  78. PASS_KEY "-no-cbranch",
  79. cl::desc("Don't treat conditional branches as disclosure gadgets. This "
  80. "may improve performance, at the cost of security."),
  81. cl::init(false), cl::Hidden);
  82. static cl::opt<bool> EmitDot(
  83. PASS_KEY "-dot",
  84. cl::desc(
  85. "For each function, emit a dot graph depicting potential LVI gadgets"),
  86. cl::init(false), cl::Hidden);
  87. static cl::opt<bool> EmitDotOnly(
  88. PASS_KEY "-dot-only",
  89. cl::desc("For each function, emit a dot graph depicting potential LVI "
  90. "gadgets, and do not insert any fences"),
  91. cl::init(false), cl::Hidden);
  92. static cl::opt<bool> EmitDotVerify(
  93. PASS_KEY "-dot-verify",
  94. cl::desc("For each function, emit a dot graph to stdout depicting "
  95. "potential LVI gadgets, used for testing purposes only"),
  96. cl::init(false), cl::Hidden);
  97. static llvm::sys::DynamicLibrary OptimizeDL;
  98. typedef int (*OptimizeCutT)(unsigned int *Nodes, unsigned int NodesSize,
  99. unsigned int *Edges, int *EdgeValues,
  100. int *CutEdges /* out */, unsigned int EdgesSize);
  101. static OptimizeCutT OptimizeCut = nullptr;
  102. namespace {
  103. struct MachineGadgetGraph : ImmutableGraph<MachineInstr *, int> {
  104. static constexpr int GadgetEdgeSentinel = -1;
  105. static constexpr MachineInstr *const ArgNodeSentinel = nullptr;
  106. using GraphT = ImmutableGraph<MachineInstr *, int>;
  107. using Node = typename GraphT::Node;
  108. using Edge = typename GraphT::Edge;
  109. using size_type = typename GraphT::size_type;
  110. MachineGadgetGraph(std::unique_ptr<Node[]> Nodes,
  111. std::unique_ptr<Edge[]> Edges, size_type NodesSize,
  112. size_type EdgesSize, int NumFences = 0, int NumGadgets = 0)
  113. : GraphT(std::move(Nodes), std::move(Edges), NodesSize, EdgesSize),
  114. NumFences(NumFences), NumGadgets(NumGadgets) {}
  115. static inline bool isCFGEdge(const Edge &E) {
  116. return E.getValue() != GadgetEdgeSentinel;
  117. }
  118. static inline bool isGadgetEdge(const Edge &E) {
  119. return E.getValue() == GadgetEdgeSentinel;
  120. }
  121. int NumFences;
  122. int NumGadgets;
  123. };
  124. class X86LoadValueInjectionLoadHardeningPass : public MachineFunctionPass {
  125. public:
  126. X86LoadValueInjectionLoadHardeningPass() : MachineFunctionPass(ID) {}
  127. StringRef getPassName() const override {
  128. return "X86 Load Value Injection (LVI) Load Hardening";
  129. }
  130. void getAnalysisUsage(AnalysisUsage &AU) const override;
  131. bool runOnMachineFunction(MachineFunction &MF) override;
  132. static char ID;
  133. private:
  134. using GraphBuilder = ImmutableGraphBuilder<MachineGadgetGraph>;
  135. using Edge = MachineGadgetGraph::Edge;
  136. using Node = MachineGadgetGraph::Node;
  137. using EdgeSet = MachineGadgetGraph::EdgeSet;
  138. using NodeSet = MachineGadgetGraph::NodeSet;
  139. const X86Subtarget *STI;
  140. const TargetInstrInfo *TII;
  141. const TargetRegisterInfo *TRI;
  142. std::unique_ptr<MachineGadgetGraph>
  143. getGadgetGraph(MachineFunction &MF, const MachineLoopInfo &MLI,
  144. const MachineDominatorTree &MDT,
  145. const MachineDominanceFrontier &MDF) const;
  146. int hardenLoadsWithPlugin(MachineFunction &MF,
  147. std::unique_ptr<MachineGadgetGraph> Graph) const;
  148. int hardenLoadsWithHeuristic(MachineFunction &MF,
  149. std::unique_ptr<MachineGadgetGraph> Graph) const;
  150. int elimMitigatedEdgesAndNodes(MachineGadgetGraph &G,
  151. EdgeSet &ElimEdges /* in, out */,
  152. NodeSet &ElimNodes /* in, out */) const;
  153. std::unique_ptr<MachineGadgetGraph>
  154. trimMitigatedEdges(std::unique_ptr<MachineGadgetGraph> Graph) const;
  155. int insertFences(MachineFunction &MF, MachineGadgetGraph &G,
  156. EdgeSet &CutEdges /* in, out */) const;
  157. bool instrUsesRegToAccessMemory(const MachineInstr &I, unsigned Reg) const;
  158. bool instrUsesRegToBranch(const MachineInstr &I, unsigned Reg) const;
  159. inline bool isFence(const MachineInstr *MI) const {
  160. return MI && (MI->getOpcode() == X86::LFENCE ||
  161. (STI->useLVIControlFlowIntegrity() && MI->isCall()));
  162. }
  163. };
  164. } // end anonymous namespace
  165. namespace llvm {
  166. template <>
  167. struct GraphTraits<MachineGadgetGraph *>
  168. : GraphTraits<ImmutableGraph<MachineInstr *, int> *> {};
  169. template <>
  170. struct DOTGraphTraits<MachineGadgetGraph *> : DefaultDOTGraphTraits {
  171. using GraphType = MachineGadgetGraph;
  172. using Traits = llvm::GraphTraits<GraphType *>;
  173. using NodeRef = typename Traits::NodeRef;
  174. using EdgeRef = typename Traits::EdgeRef;
  175. using ChildIteratorType = typename Traits::ChildIteratorType;
  176. using ChildEdgeIteratorType = typename Traits::ChildEdgeIteratorType;
  177. DOTGraphTraits(bool IsSimple = false) : DefaultDOTGraphTraits(IsSimple) {}
  178. std::string getNodeLabel(NodeRef Node, GraphType *) {
  179. if (Node->getValue() == MachineGadgetGraph::ArgNodeSentinel)
  180. return "ARGS";
  181. std::string Str;
  182. raw_string_ostream OS(Str);
  183. OS << *Node->getValue();
  184. return OS.str();
  185. }
  186. static std::string getNodeAttributes(NodeRef Node, GraphType *) {
  187. MachineInstr *MI = Node->getValue();
  188. if (MI == MachineGadgetGraph::ArgNodeSentinel)
  189. return "color = blue";
  190. if (MI->getOpcode() == X86::LFENCE)
  191. return "color = green";
  192. return "";
  193. }
  194. static std::string getEdgeAttributes(NodeRef, ChildIteratorType E,
  195. GraphType *) {
  196. int EdgeVal = (*E.getCurrent()).getValue();
  197. return EdgeVal >= 0 ? "label = " + std::to_string(EdgeVal)
  198. : "color = red, style = \"dashed\"";
  199. }
  200. };
  201. } // end namespace llvm
  202. constexpr MachineInstr *MachineGadgetGraph::ArgNodeSentinel;
  203. constexpr int MachineGadgetGraph::GadgetEdgeSentinel;
  204. char X86LoadValueInjectionLoadHardeningPass::ID = 0;
  205. void X86LoadValueInjectionLoadHardeningPass::getAnalysisUsage(
  206. AnalysisUsage &AU) const {
  207. MachineFunctionPass::getAnalysisUsage(AU);
  208. AU.addRequired<MachineLoopInfo>();
  209. AU.addRequired<MachineDominatorTree>();
  210. AU.addRequired<MachineDominanceFrontier>();
  211. AU.setPreservesCFG();
  212. }
  213. static void writeGadgetGraph(raw_ostream &OS, MachineFunction &MF,
  214. MachineGadgetGraph *G) {
  215. WriteGraph(OS, G, /*ShortNames*/ false,
  216. "Speculative gadgets for \"" + MF.getName() + "\" function");
  217. }
  218. bool X86LoadValueInjectionLoadHardeningPass::runOnMachineFunction(
  219. MachineFunction &MF) {
  220. LLVM_DEBUG(dbgs() << "***** " << getPassName() << " : " << MF.getName()
  221. << " *****\n");
  222. STI = &MF.getSubtarget<X86Subtarget>();
  223. if (!STI->useLVILoadHardening())
  224. return false;
  225. // FIXME: support 32-bit
  226. if (!STI->is64Bit())
  227. report_fatal_error("LVI load hardening is only supported on 64-bit", false);
  228. // Don't skip functions with the "optnone" attr but participate in opt-bisect.
  229. const Function &F = MF.getFunction();
  230. if (!F.hasOptNone() && skipFunction(F))
  231. return false;
  232. ++NumFunctionsConsidered;
  233. TII = STI->getInstrInfo();
  234. TRI = STI->getRegisterInfo();
  235. LLVM_DEBUG(dbgs() << "Building gadget graph...\n");
  236. const auto &MLI = getAnalysis<MachineLoopInfo>();
  237. const auto &MDT = getAnalysis<MachineDominatorTree>();
  238. const auto &MDF = getAnalysis<MachineDominanceFrontier>();
  239. std::unique_ptr<MachineGadgetGraph> Graph = getGadgetGraph(MF, MLI, MDT, MDF);
  240. LLVM_DEBUG(dbgs() << "Building gadget graph... Done\n");
  241. if (Graph == nullptr)
  242. return false; // didn't find any gadgets
  243. if (EmitDotVerify) {
  244. writeGadgetGraph(outs(), MF, Graph.get());
  245. return false;
  246. }
  247. if (EmitDot || EmitDotOnly) {
  248. LLVM_DEBUG(dbgs() << "Emitting gadget graph...\n");
  249. std::error_code FileError;
  250. std::string FileName = "lvi.";
  251. FileName += MF.getName();
  252. FileName += ".dot";
  253. raw_fd_ostream FileOut(FileName, FileError);
  254. if (FileError)
  255. errs() << FileError.message();
  256. writeGadgetGraph(FileOut, MF, Graph.get());
  257. FileOut.close();
  258. LLVM_DEBUG(dbgs() << "Emitting gadget graph... Done\n");
  259. if (EmitDotOnly)
  260. return false;
  261. }
  262. int FencesInserted;
  263. if (!OptimizePluginPath.empty()) {
  264. if (!OptimizeDL.isValid()) {
  265. std::string ErrorMsg;
  266. OptimizeDL = llvm::sys::DynamicLibrary::getPermanentLibrary(
  267. OptimizePluginPath.c_str(), &ErrorMsg);
  268. if (!ErrorMsg.empty())
  269. report_fatal_error(Twine("Failed to load opt plugin: \"") + ErrorMsg +
  270. "\"");
  271. OptimizeCut = (OptimizeCutT)OptimizeDL.getAddressOfSymbol("optimize_cut");
  272. if (!OptimizeCut)
  273. report_fatal_error("Invalid optimization plugin");
  274. }
  275. FencesInserted = hardenLoadsWithPlugin(MF, std::move(Graph));
  276. } else { // Use the default greedy heuristic
  277. FencesInserted = hardenLoadsWithHeuristic(MF, std::move(Graph));
  278. }
  279. if (FencesInserted > 0)
  280. ++NumFunctionsMitigated;
  281. NumFences += FencesInserted;
  282. return (FencesInserted > 0);
  283. }
  284. std::unique_ptr<MachineGadgetGraph>
  285. X86LoadValueInjectionLoadHardeningPass::getGadgetGraph(
  286. MachineFunction &MF, const MachineLoopInfo &MLI,
  287. const MachineDominatorTree &MDT,
  288. const MachineDominanceFrontier &MDF) const {
  289. using namespace rdf;
  290. // Build the Register Dataflow Graph using the RDF framework
  291. TargetOperandInfo TOI{*TII};
  292. DataFlowGraph DFG{MF, *TII, *TRI, MDT, MDF, TOI};
  293. DFG.build();
  294. Liveness L{MF.getRegInfo(), DFG};
  295. L.computePhiInfo();
  296. GraphBuilder Builder;
  297. using GraphIter = typename GraphBuilder::BuilderNodeRef;
  298. DenseMap<MachineInstr *, GraphIter> NodeMap;
  299. int FenceCount = 0, GadgetCount = 0;
  300. auto MaybeAddNode = [&NodeMap, &Builder](MachineInstr *MI) {
  301. auto Ref = NodeMap.find(MI);
  302. if (Ref == NodeMap.end()) {
  303. auto I = Builder.addVertex(MI);
  304. NodeMap[MI] = I;
  305. return std::pair<GraphIter, bool>{I, true};
  306. }
  307. return std::pair<GraphIter, bool>{Ref->getSecond(), false};
  308. };
  309. // The `Transmitters` map memoizes transmitters found for each def. If a def
  310. // has not yet been analyzed, then it will not appear in the map. If a def
  311. // has been analyzed and was determined not to have any transmitters, then
  312. // its list of transmitters will be empty.
  313. DenseMap<NodeId, std::vector<NodeId>> Transmitters;
  314. // Analyze all machine instructions to find gadgets and LFENCEs, adding
  315. // each interesting value to `Nodes`
  316. auto AnalyzeDef = [&](NodeAddr<DefNode *> SourceDef) {
  317. SmallSet<NodeId, 8> UsesVisited, DefsVisited;
  318. std::function<void(NodeAddr<DefNode *>)> AnalyzeDefUseChain =
  319. [&](NodeAddr<DefNode *> Def) {
  320. if (Transmitters.find(Def.Id) != Transmitters.end())
  321. return; // Already analyzed `Def`
  322. // Use RDF to find all the uses of `Def`
  323. rdf::NodeSet Uses;
  324. RegisterRef DefReg = Def.Addr->getRegRef(DFG);
  325. for (auto UseID : L.getAllReachedUses(DefReg, Def)) {
  326. auto Use = DFG.addr<UseNode *>(UseID);
  327. if (Use.Addr->getFlags() & NodeAttrs::PhiRef) { // phi node
  328. NodeAddr<PhiNode *> Phi = Use.Addr->getOwner(DFG);
  329. for (const auto& I : L.getRealUses(Phi.Id)) {
  330. if (DFG.getPRI().alias(RegisterRef(I.first), DefReg)) {
  331. for (const auto &UA : I.second)
  332. Uses.emplace(UA.first);
  333. }
  334. }
  335. } else { // not a phi node
  336. Uses.emplace(UseID);
  337. }
  338. }
  339. // For each use of `Def`, we want to know whether:
  340. // (1) The use can leak the Def'ed value,
  341. // (2) The use can further propagate the Def'ed value to more defs
  342. for (auto UseID : Uses) {
  343. if (!UsesVisited.insert(UseID).second)
  344. continue; // Already visited this use of `Def`
  345. auto Use = DFG.addr<UseNode *>(UseID);
  346. assert(!(Use.Addr->getFlags() & NodeAttrs::PhiRef));
  347. MachineOperand &UseMO = Use.Addr->getOp();
  348. MachineInstr &UseMI = *UseMO.getParent();
  349. assert(UseMO.isReg());
  350. // We naively assume that an instruction propagates any loaded
  351. // uses to all defs unless the instruction is a call, in which
  352. // case all arguments will be treated as gadget sources during
  353. // analysis of the callee function.
  354. if (UseMI.isCall())
  355. continue;
  356. // Check whether this use can transmit (leak) its value.
  357. if (instrUsesRegToAccessMemory(UseMI, UseMO.getReg()) ||
  358. (!NoConditionalBranches &&
  359. instrUsesRegToBranch(UseMI, UseMO.getReg()))) {
  360. Transmitters[Def.Id].push_back(Use.Addr->getOwner(DFG).Id);
  361. if (UseMI.mayLoad())
  362. continue; // Found a transmitting load -- no need to continue
  363. // traversing its defs (i.e., this load will become
  364. // a new gadget source anyways).
  365. }
  366. // Check whether the use propagates to more defs.
  367. NodeAddr<InstrNode *> Owner{Use.Addr->getOwner(DFG)};
  368. rdf::NodeList AnalyzedChildDefs;
  369. for (const auto &ChildDef :
  370. Owner.Addr->members_if(DataFlowGraph::IsDef, DFG)) {
  371. if (!DefsVisited.insert(ChildDef.Id).second)
  372. continue; // Already visited this def
  373. if (Def.Addr->getAttrs() & NodeAttrs::Dead)
  374. continue;
  375. if (Def.Id == ChildDef.Id)
  376. continue; // `Def` uses itself (e.g., increment loop counter)
  377. AnalyzeDefUseChain(ChildDef);
  378. // `Def` inherits all of its child defs' transmitters.
  379. for (auto TransmitterId : Transmitters[ChildDef.Id])
  380. Transmitters[Def.Id].push_back(TransmitterId);
  381. }
  382. }
  383. // Note that this statement adds `Def.Id` to the map if no
  384. // transmitters were found for `Def`.
  385. auto &DefTransmitters = Transmitters[Def.Id];
  386. // Remove duplicate transmitters
  387. llvm::sort(DefTransmitters);
  388. DefTransmitters.erase(
  389. std::unique(DefTransmitters.begin(), DefTransmitters.end()),
  390. DefTransmitters.end());
  391. };
  392. // Find all of the transmitters
  393. AnalyzeDefUseChain(SourceDef);
  394. auto &SourceDefTransmitters = Transmitters[SourceDef.Id];
  395. if (SourceDefTransmitters.empty())
  396. return; // No transmitters for `SourceDef`
  397. MachineInstr *Source = SourceDef.Addr->getFlags() & NodeAttrs::PhiRef
  398. ? MachineGadgetGraph::ArgNodeSentinel
  399. : SourceDef.Addr->getOp().getParent();
  400. auto GadgetSource = MaybeAddNode(Source);
  401. // Each transmitter is a sink for `SourceDef`.
  402. for (auto TransmitterId : SourceDefTransmitters) {
  403. MachineInstr *Sink = DFG.addr<StmtNode *>(TransmitterId).Addr->getCode();
  404. auto GadgetSink = MaybeAddNode(Sink);
  405. // Add the gadget edge to the graph.
  406. Builder.addEdge(MachineGadgetGraph::GadgetEdgeSentinel,
  407. GadgetSource.first, GadgetSink.first);
  408. ++GadgetCount;
  409. }
  410. };
  411. LLVM_DEBUG(dbgs() << "Analyzing def-use chains to find gadgets\n");
  412. // Analyze function arguments
  413. NodeAddr<BlockNode *> EntryBlock = DFG.getFunc().Addr->getEntryBlock(DFG);
  414. for (NodeAddr<PhiNode *> ArgPhi :
  415. EntryBlock.Addr->members_if(DataFlowGraph::IsPhi, DFG)) {
  416. NodeList Defs = ArgPhi.Addr->members_if(DataFlowGraph::IsDef, DFG);
  417. llvm::for_each(Defs, AnalyzeDef);
  418. }
  419. // Analyze every instruction in MF
  420. for (NodeAddr<BlockNode *> BA : DFG.getFunc().Addr->members(DFG)) {
  421. for (NodeAddr<StmtNode *> SA :
  422. BA.Addr->members_if(DataFlowGraph::IsCode<NodeAttrs::Stmt>, DFG)) {
  423. MachineInstr *MI = SA.Addr->getCode();
  424. if (isFence(MI)) {
  425. MaybeAddNode(MI);
  426. ++FenceCount;
  427. } else if (MI->mayLoad()) {
  428. NodeList Defs = SA.Addr->members_if(DataFlowGraph::IsDef, DFG);
  429. llvm::for_each(Defs, AnalyzeDef);
  430. }
  431. }
  432. }
  433. LLVM_DEBUG(dbgs() << "Found " << FenceCount << " fences\n");
  434. LLVM_DEBUG(dbgs() << "Found " << GadgetCount << " gadgets\n");
  435. if (GadgetCount == 0)
  436. return nullptr;
  437. NumGadgets += GadgetCount;
  438. // Traverse CFG to build the rest of the graph
  439. SmallSet<MachineBasicBlock *, 8> BlocksVisited;
  440. std::function<void(MachineBasicBlock *, GraphIter, unsigned)> TraverseCFG =
  441. [&](MachineBasicBlock *MBB, GraphIter GI, unsigned ParentDepth) {
  442. unsigned LoopDepth = MLI.getLoopDepth(MBB);
  443. if (!MBB->empty()) {
  444. // Always add the first instruction in each block
  445. auto NI = MBB->begin();
  446. auto BeginBB = MaybeAddNode(&*NI);
  447. Builder.addEdge(ParentDepth, GI, BeginBB.first);
  448. if (!BlocksVisited.insert(MBB).second)
  449. return;
  450. // Add any instructions within the block that are gadget components
  451. GI = BeginBB.first;
  452. while (++NI != MBB->end()) {
  453. auto Ref = NodeMap.find(&*NI);
  454. if (Ref != NodeMap.end()) {
  455. Builder.addEdge(LoopDepth, GI, Ref->getSecond());
  456. GI = Ref->getSecond();
  457. }
  458. }
  459. // Always add the terminator instruction, if one exists
  460. auto T = MBB->getFirstTerminator();
  461. if (T != MBB->end()) {
  462. auto EndBB = MaybeAddNode(&*T);
  463. if (EndBB.second)
  464. Builder.addEdge(LoopDepth, GI, EndBB.first);
  465. GI = EndBB.first;
  466. }
  467. }
  468. for (MachineBasicBlock *Succ : MBB->successors())
  469. TraverseCFG(Succ, GI, LoopDepth);
  470. };
  471. // ArgNodeSentinel is a pseudo-instruction that represents MF args in the
  472. // GadgetGraph
  473. GraphIter ArgNode = MaybeAddNode(MachineGadgetGraph::ArgNodeSentinel).first;
  474. TraverseCFG(&MF.front(), ArgNode, 0);
  475. std::unique_ptr<MachineGadgetGraph> G{Builder.get(FenceCount, GadgetCount)};
  476. LLVM_DEBUG(dbgs() << "Found " << G->nodes_size() << " nodes\n");
  477. return G;
  478. }
  479. // Returns the number of remaining gadget edges that could not be eliminated
  480. int X86LoadValueInjectionLoadHardeningPass::elimMitigatedEdgesAndNodes(
  481. MachineGadgetGraph &G, EdgeSet &ElimEdges /* in, out */,
  482. NodeSet &ElimNodes /* in, out */) const {
  483. if (G.NumFences > 0) {
  484. // Eliminate fences and CFG edges that ingress and egress the fence, as
  485. // they are trivially mitigated.
  486. for (const Edge &E : G.edges()) {
  487. const Node *Dest = E.getDest();
  488. if (isFence(Dest->getValue())) {
  489. ElimNodes.insert(*Dest);
  490. ElimEdges.insert(E);
  491. for (const Edge &DE : Dest->edges())
  492. ElimEdges.insert(DE);
  493. }
  494. }
  495. }
  496. // Find and eliminate gadget edges that have been mitigated.
  497. int MitigatedGadgets = 0, RemainingGadgets = 0;
  498. NodeSet ReachableNodes{G};
  499. for (const Node &RootN : G.nodes()) {
  500. if (llvm::none_of(RootN.edges(), MachineGadgetGraph::isGadgetEdge))
  501. continue; // skip this node if it isn't a gadget source
  502. // Find all of the nodes that are CFG-reachable from RootN using DFS
  503. ReachableNodes.clear();
  504. std::function<void(const Node *, bool)> FindReachableNodes =
  505. [&](const Node *N, bool FirstNode) {
  506. if (!FirstNode)
  507. ReachableNodes.insert(*N);
  508. for (const Edge &E : N->edges()) {
  509. const Node *Dest = E.getDest();
  510. if (MachineGadgetGraph::isCFGEdge(E) && !ElimEdges.contains(E) &&
  511. !ReachableNodes.contains(*Dest))
  512. FindReachableNodes(Dest, false);
  513. }
  514. };
  515. FindReachableNodes(&RootN, true);
  516. // Any gadget whose sink is unreachable has been mitigated
  517. for (const Edge &E : RootN.edges()) {
  518. if (MachineGadgetGraph::isGadgetEdge(E)) {
  519. if (ReachableNodes.contains(*E.getDest())) {
  520. // This gadget's sink is reachable
  521. ++RemainingGadgets;
  522. } else { // This gadget's sink is unreachable, and therefore mitigated
  523. ++MitigatedGadgets;
  524. ElimEdges.insert(E);
  525. }
  526. }
  527. }
  528. }
  529. return RemainingGadgets;
  530. }
  531. std::unique_ptr<MachineGadgetGraph>
  532. X86LoadValueInjectionLoadHardeningPass::trimMitigatedEdges(
  533. std::unique_ptr<MachineGadgetGraph> Graph) const {
  534. NodeSet ElimNodes{*Graph};
  535. EdgeSet ElimEdges{*Graph};
  536. int RemainingGadgets =
  537. elimMitigatedEdgesAndNodes(*Graph, ElimEdges, ElimNodes);
  538. if (ElimEdges.empty() && ElimNodes.empty()) {
  539. Graph->NumFences = 0;
  540. Graph->NumGadgets = RemainingGadgets;
  541. } else {
  542. Graph = GraphBuilder::trim(*Graph, ElimNodes, ElimEdges, 0 /* NumFences */,
  543. RemainingGadgets);
  544. }
  545. return Graph;
  546. }
  547. int X86LoadValueInjectionLoadHardeningPass::hardenLoadsWithPlugin(
  548. MachineFunction &MF, std::unique_ptr<MachineGadgetGraph> Graph) const {
  549. int FencesInserted = 0;
  550. do {
  551. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths...\n");
  552. Graph = trimMitigatedEdges(std::move(Graph));
  553. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths... Done\n");
  554. if (Graph->NumGadgets == 0)
  555. break;
  556. LLVM_DEBUG(dbgs() << "Cutting edges...\n");
  557. EdgeSet CutEdges{*Graph};
  558. auto Nodes = std::make_unique<unsigned int[]>(Graph->nodes_size() +
  559. 1 /* terminator node */);
  560. auto Edges = std::make_unique<unsigned int[]>(Graph->edges_size());
  561. auto EdgeCuts = std::make_unique<int[]>(Graph->edges_size());
  562. auto EdgeValues = std::make_unique<int[]>(Graph->edges_size());
  563. for (const Node &N : Graph->nodes()) {
  564. Nodes[Graph->getNodeIndex(N)] = Graph->getEdgeIndex(*N.edges_begin());
  565. }
  566. Nodes[Graph->nodes_size()] = Graph->edges_size(); // terminator node
  567. for (const Edge &E : Graph->edges()) {
  568. Edges[Graph->getEdgeIndex(E)] = Graph->getNodeIndex(*E.getDest());
  569. EdgeValues[Graph->getEdgeIndex(E)] = E.getValue();
  570. }
  571. OptimizeCut(Nodes.get(), Graph->nodes_size(), Edges.get(), EdgeValues.get(),
  572. EdgeCuts.get(), Graph->edges_size());
  573. for (int I = 0; I < Graph->edges_size(); ++I)
  574. if (EdgeCuts[I])
  575. CutEdges.set(I);
  576. LLVM_DEBUG(dbgs() << "Cutting edges... Done\n");
  577. LLVM_DEBUG(dbgs() << "Cut " << CutEdges.count() << " edges\n");
  578. LLVM_DEBUG(dbgs() << "Inserting LFENCEs...\n");
  579. FencesInserted += insertFences(MF, *Graph, CutEdges);
  580. LLVM_DEBUG(dbgs() << "Inserting LFENCEs... Done\n");
  581. LLVM_DEBUG(dbgs() << "Inserted " << FencesInserted << " fences\n");
  582. Graph = GraphBuilder::trim(*Graph, NodeSet{*Graph}, CutEdges);
  583. } while (true);
  584. return FencesInserted;
  585. }
  586. int X86LoadValueInjectionLoadHardeningPass::hardenLoadsWithHeuristic(
  587. MachineFunction &MF, std::unique_ptr<MachineGadgetGraph> Graph) const {
  588. // If `MF` does not have any fences, then no gadgets would have been
  589. // mitigated at this point.
  590. if (Graph->NumFences > 0) {
  591. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths...\n");
  592. Graph = trimMitigatedEdges(std::move(Graph));
  593. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths... Done\n");
  594. }
  595. if (Graph->NumGadgets == 0)
  596. return 0;
  597. LLVM_DEBUG(dbgs() << "Cutting edges...\n");
  598. EdgeSet CutEdges{*Graph};
  599. // Begin by collecting all ingress CFG edges for each node
  600. DenseMap<const Node *, SmallVector<const Edge *, 2>> IngressEdgeMap;
  601. for (const Edge &E : Graph->edges())
  602. if (MachineGadgetGraph::isCFGEdge(E))
  603. IngressEdgeMap[E.getDest()].push_back(&E);
  604. // For each gadget edge, make cuts that guarantee the gadget will be
  605. // mitigated. A computationally efficient way to achieve this is to either:
  606. // (a) cut all egress CFG edges from the gadget source, or
  607. // (b) cut all ingress CFG edges to the gadget sink.
  608. //
  609. // Moreover, the algorithm tries not to make a cut into a loop by preferring
  610. // to make a (b)-type cut if the gadget source resides at a greater loop depth
  611. // than the gadget sink, or an (a)-type cut otherwise.
  612. for (const Node &N : Graph->nodes()) {
  613. for (const Edge &E : N.edges()) {
  614. if (!MachineGadgetGraph::isGadgetEdge(E))
  615. continue;
  616. SmallVector<const Edge *, 2> EgressEdges;
  617. SmallVector<const Edge *, 2> &IngressEdges = IngressEdgeMap[E.getDest()];
  618. for (const Edge &EgressEdge : N.edges())
  619. if (MachineGadgetGraph::isCFGEdge(EgressEdge))
  620. EgressEdges.push_back(&EgressEdge);
  621. int EgressCutCost = 0, IngressCutCost = 0;
  622. for (const Edge *EgressEdge : EgressEdges)
  623. if (!CutEdges.contains(*EgressEdge))
  624. EgressCutCost += EgressEdge->getValue();
  625. for (const Edge *IngressEdge : IngressEdges)
  626. if (!CutEdges.contains(*IngressEdge))
  627. IngressCutCost += IngressEdge->getValue();
  628. auto &EdgesToCut =
  629. IngressCutCost < EgressCutCost ? IngressEdges : EgressEdges;
  630. for (const Edge *E : EdgesToCut)
  631. CutEdges.insert(*E);
  632. }
  633. }
  634. LLVM_DEBUG(dbgs() << "Cutting edges... Done\n");
  635. LLVM_DEBUG(dbgs() << "Cut " << CutEdges.count() << " edges\n");
  636. LLVM_DEBUG(dbgs() << "Inserting LFENCEs...\n");
  637. int FencesInserted = insertFences(MF, *Graph, CutEdges);
  638. LLVM_DEBUG(dbgs() << "Inserting LFENCEs... Done\n");
  639. LLVM_DEBUG(dbgs() << "Inserted " << FencesInserted << " fences\n");
  640. return FencesInserted;
  641. }
  642. int X86LoadValueInjectionLoadHardeningPass::insertFences(
  643. MachineFunction &MF, MachineGadgetGraph &G,
  644. EdgeSet &CutEdges /* in, out */) const {
  645. int FencesInserted = 0;
  646. for (const Node &N : G.nodes()) {
  647. for (const Edge &E : N.edges()) {
  648. if (CutEdges.contains(E)) {
  649. MachineInstr *MI = N.getValue(), *Prev;
  650. MachineBasicBlock *MBB; // Insert an LFENCE in this MBB
  651. MachineBasicBlock::iterator InsertionPt; // ...at this point
  652. if (MI == MachineGadgetGraph::ArgNodeSentinel) {
  653. // insert LFENCE at beginning of entry block
  654. MBB = &MF.front();
  655. InsertionPt = MBB->begin();
  656. Prev = nullptr;
  657. } else if (MI->isBranch()) { // insert the LFENCE before the branch
  658. MBB = MI->getParent();
  659. InsertionPt = MI;
  660. Prev = MI->getPrevNode();
  661. // Remove all egress CFG edges from this branch because the inserted
  662. // LFENCE prevents gadgets from crossing the branch.
  663. for (const Edge &E : N.edges()) {
  664. if (MachineGadgetGraph::isCFGEdge(E))
  665. CutEdges.insert(E);
  666. }
  667. } else { // insert the LFENCE after the instruction
  668. MBB = MI->getParent();
  669. InsertionPt = MI->getNextNode() ? MI->getNextNode() : MBB->end();
  670. Prev = InsertionPt == MBB->end()
  671. ? (MBB->empty() ? nullptr : &MBB->back())
  672. : InsertionPt->getPrevNode();
  673. }
  674. // Ensure this insertion is not redundant (two LFENCEs in sequence).
  675. if ((InsertionPt == MBB->end() || !isFence(&*InsertionPt)) &&
  676. (!Prev || !isFence(Prev))) {
  677. BuildMI(*MBB, InsertionPt, DebugLoc(), TII->get(X86::LFENCE));
  678. ++FencesInserted;
  679. }
  680. }
  681. }
  682. }
  683. return FencesInserted;
  684. }
  685. bool X86LoadValueInjectionLoadHardeningPass::instrUsesRegToAccessMemory(
  686. const MachineInstr &MI, unsigned Reg) const {
  687. if (!MI.mayLoadOrStore() || MI.getOpcode() == X86::MFENCE ||
  688. MI.getOpcode() == X86::SFENCE || MI.getOpcode() == X86::LFENCE)
  689. return false;
  690. // FIXME: This does not handle pseudo loading instruction like TCRETURN*
  691. const MCInstrDesc &Desc = MI.getDesc();
  692. int MemRefBeginIdx = X86II::getMemoryOperandNo(Desc.TSFlags);
  693. if (MemRefBeginIdx < 0) {
  694. LLVM_DEBUG(dbgs() << "Warning: unable to obtain memory operand for loading "
  695. "instruction:\n";
  696. MI.print(dbgs()); dbgs() << '\n';);
  697. return false;
  698. }
  699. MemRefBeginIdx += X86II::getOperandBias(Desc);
  700. const MachineOperand &BaseMO =
  701. MI.getOperand(MemRefBeginIdx + X86::AddrBaseReg);
  702. const MachineOperand &IndexMO =
  703. MI.getOperand(MemRefBeginIdx + X86::AddrIndexReg);
  704. return (BaseMO.isReg() && BaseMO.getReg() != X86::NoRegister &&
  705. TRI->regsOverlap(BaseMO.getReg(), Reg)) ||
  706. (IndexMO.isReg() && IndexMO.getReg() != X86::NoRegister &&
  707. TRI->regsOverlap(IndexMO.getReg(), Reg));
  708. }
  709. bool X86LoadValueInjectionLoadHardeningPass::instrUsesRegToBranch(
  710. const MachineInstr &MI, unsigned Reg) const {
  711. if (!MI.isConditionalBranch())
  712. return false;
  713. for (const MachineOperand &Use : MI.uses())
  714. if (Use.isReg() && Use.getReg() == Reg)
  715. return true;
  716. return false;
  717. }
  718. INITIALIZE_PASS_BEGIN(X86LoadValueInjectionLoadHardeningPass, PASS_KEY,
  719. "X86 LVI load hardening", false, false)
  720. INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
  721. INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
  722. INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
  723. INITIALIZE_PASS_END(X86LoadValueInjectionLoadHardeningPass, PASS_KEY,
  724. "X86 LVI load hardening", false, false)
  725. FunctionPass *llvm::createX86LoadValueInjectionLoadHardeningPass() {
  726. return new X86LoadValueInjectionLoadHardeningPass();
  727. }