X86LoadValueInjectionLoadHardening.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  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. DataFlowGraph DFG{MF, *TII, *TRI, MDT, MDF};
  292. DFG.build();
  293. Liveness L{MF.getRegInfo(), DFG};
  294. L.computePhiInfo();
  295. GraphBuilder Builder;
  296. using GraphIter = typename GraphBuilder::BuilderNodeRef;
  297. DenseMap<MachineInstr *, GraphIter> NodeMap;
  298. int FenceCount = 0, GadgetCount = 0;
  299. auto MaybeAddNode = [&NodeMap, &Builder](MachineInstr *MI) {
  300. auto Ref = NodeMap.find(MI);
  301. if (Ref == NodeMap.end()) {
  302. auto I = Builder.addVertex(MI);
  303. NodeMap[MI] = I;
  304. return std::pair<GraphIter, bool>{I, true};
  305. }
  306. return std::pair<GraphIter, bool>{Ref->getSecond(), false};
  307. };
  308. // The `Transmitters` map memoizes transmitters found for each def. If a def
  309. // has not yet been analyzed, then it will not appear in the map. If a def
  310. // has been analyzed and was determined not to have any transmitters, then
  311. // its list of transmitters will be empty.
  312. DenseMap<NodeId, std::vector<NodeId>> Transmitters;
  313. // Analyze all machine instructions to find gadgets and LFENCEs, adding
  314. // each interesting value to `Nodes`
  315. auto AnalyzeDef = [&](NodeAddr<DefNode *> SourceDef) {
  316. SmallSet<NodeId, 8> UsesVisited, DefsVisited;
  317. std::function<void(NodeAddr<DefNode *>)> AnalyzeDefUseChain =
  318. [&](NodeAddr<DefNode *> Def) {
  319. if (Transmitters.find(Def.Id) != Transmitters.end())
  320. return; // Already analyzed `Def`
  321. // Use RDF to find all the uses of `Def`
  322. rdf::NodeSet Uses;
  323. RegisterRef DefReg = Def.Addr->getRegRef(DFG);
  324. for (auto UseID : L.getAllReachedUses(DefReg, Def)) {
  325. auto Use = DFG.addr<UseNode *>(UseID);
  326. if (Use.Addr->getFlags() & NodeAttrs::PhiRef) { // phi node
  327. NodeAddr<PhiNode *> Phi = Use.Addr->getOwner(DFG);
  328. for (const auto& I : L.getRealUses(Phi.Id)) {
  329. if (DFG.getPRI().alias(RegisterRef(I.first), DefReg)) {
  330. for (const auto &UA : I.second)
  331. Uses.emplace(UA.first);
  332. }
  333. }
  334. } else { // not a phi node
  335. Uses.emplace(UseID);
  336. }
  337. }
  338. // For each use of `Def`, we want to know whether:
  339. // (1) The use can leak the Def'ed value,
  340. // (2) The use can further propagate the Def'ed value to more defs
  341. for (auto UseID : Uses) {
  342. if (!UsesVisited.insert(UseID).second)
  343. continue; // Already visited this use of `Def`
  344. auto Use = DFG.addr<UseNode *>(UseID);
  345. assert(!(Use.Addr->getFlags() & NodeAttrs::PhiRef));
  346. MachineOperand &UseMO = Use.Addr->getOp();
  347. MachineInstr &UseMI = *UseMO.getParent();
  348. assert(UseMO.isReg());
  349. // We naively assume that an instruction propagates any loaded
  350. // uses to all defs unless the instruction is a call, in which
  351. // case all arguments will be treated as gadget sources during
  352. // analysis of the callee function.
  353. if (UseMI.isCall())
  354. continue;
  355. // Check whether this use can transmit (leak) its value.
  356. if (instrUsesRegToAccessMemory(UseMI, UseMO.getReg()) ||
  357. (!NoConditionalBranches &&
  358. instrUsesRegToBranch(UseMI, UseMO.getReg()))) {
  359. Transmitters[Def.Id].push_back(Use.Addr->getOwner(DFG).Id);
  360. if (UseMI.mayLoad())
  361. continue; // Found a transmitting load -- no need to continue
  362. // traversing its defs (i.e., this load will become
  363. // a new gadget source anyways).
  364. }
  365. // Check whether the use propagates to more defs.
  366. NodeAddr<InstrNode *> Owner{Use.Addr->getOwner(DFG)};
  367. rdf::NodeList AnalyzedChildDefs;
  368. for (const auto &ChildDef :
  369. Owner.Addr->members_if(DataFlowGraph::IsDef, DFG)) {
  370. if (!DefsVisited.insert(ChildDef.Id).second)
  371. continue; // Already visited this def
  372. if (Def.Addr->getAttrs() & NodeAttrs::Dead)
  373. continue;
  374. if (Def.Id == ChildDef.Id)
  375. continue; // `Def` uses itself (e.g., increment loop counter)
  376. AnalyzeDefUseChain(ChildDef);
  377. // `Def` inherits all of its child defs' transmitters.
  378. for (auto TransmitterId : Transmitters[ChildDef.Id])
  379. Transmitters[Def.Id].push_back(TransmitterId);
  380. }
  381. }
  382. // Note that this statement adds `Def.Id` to the map if no
  383. // transmitters were found for `Def`.
  384. auto &DefTransmitters = Transmitters[Def.Id];
  385. // Remove duplicate transmitters
  386. llvm::sort(DefTransmitters);
  387. DefTransmitters.erase(
  388. std::unique(DefTransmitters.begin(), DefTransmitters.end()),
  389. DefTransmitters.end());
  390. };
  391. // Find all of the transmitters
  392. AnalyzeDefUseChain(SourceDef);
  393. auto &SourceDefTransmitters = Transmitters[SourceDef.Id];
  394. if (SourceDefTransmitters.empty())
  395. return; // No transmitters for `SourceDef`
  396. MachineInstr *Source = SourceDef.Addr->getFlags() & NodeAttrs::PhiRef
  397. ? MachineGadgetGraph::ArgNodeSentinel
  398. : SourceDef.Addr->getOp().getParent();
  399. auto GadgetSource = MaybeAddNode(Source);
  400. // Each transmitter is a sink for `SourceDef`.
  401. for (auto TransmitterId : SourceDefTransmitters) {
  402. MachineInstr *Sink = DFG.addr<StmtNode *>(TransmitterId).Addr->getCode();
  403. auto GadgetSink = MaybeAddNode(Sink);
  404. // Add the gadget edge to the graph.
  405. Builder.addEdge(MachineGadgetGraph::GadgetEdgeSentinel,
  406. GadgetSource.first, GadgetSink.first);
  407. ++GadgetCount;
  408. }
  409. };
  410. LLVM_DEBUG(dbgs() << "Analyzing def-use chains to find gadgets\n");
  411. // Analyze function arguments
  412. NodeAddr<BlockNode *> EntryBlock = DFG.getFunc().Addr->getEntryBlock(DFG);
  413. for (NodeAddr<PhiNode *> ArgPhi :
  414. EntryBlock.Addr->members_if(DataFlowGraph::IsPhi, DFG)) {
  415. NodeList Defs = ArgPhi.Addr->members_if(DataFlowGraph::IsDef, DFG);
  416. llvm::for_each(Defs, AnalyzeDef);
  417. }
  418. // Analyze every instruction in MF
  419. for (NodeAddr<BlockNode *> BA : DFG.getFunc().Addr->members(DFG)) {
  420. for (NodeAddr<StmtNode *> SA :
  421. BA.Addr->members_if(DataFlowGraph::IsCode<NodeAttrs::Stmt>, DFG)) {
  422. MachineInstr *MI = SA.Addr->getCode();
  423. if (isFence(MI)) {
  424. MaybeAddNode(MI);
  425. ++FenceCount;
  426. } else if (MI->mayLoad()) {
  427. NodeList Defs = SA.Addr->members_if(DataFlowGraph::IsDef, DFG);
  428. llvm::for_each(Defs, AnalyzeDef);
  429. }
  430. }
  431. }
  432. LLVM_DEBUG(dbgs() << "Found " << FenceCount << " fences\n");
  433. LLVM_DEBUG(dbgs() << "Found " << GadgetCount << " gadgets\n");
  434. if (GadgetCount == 0)
  435. return nullptr;
  436. NumGadgets += GadgetCount;
  437. // Traverse CFG to build the rest of the graph
  438. SmallSet<MachineBasicBlock *, 8> BlocksVisited;
  439. std::function<void(MachineBasicBlock *, GraphIter, unsigned)> TraverseCFG =
  440. [&](MachineBasicBlock *MBB, GraphIter GI, unsigned ParentDepth) {
  441. unsigned LoopDepth = MLI.getLoopDepth(MBB);
  442. if (!MBB->empty()) {
  443. // Always add the first instruction in each block
  444. auto NI = MBB->begin();
  445. auto BeginBB = MaybeAddNode(&*NI);
  446. Builder.addEdge(ParentDepth, GI, BeginBB.first);
  447. if (!BlocksVisited.insert(MBB).second)
  448. return;
  449. // Add any instructions within the block that are gadget components
  450. GI = BeginBB.first;
  451. while (++NI != MBB->end()) {
  452. auto Ref = NodeMap.find(&*NI);
  453. if (Ref != NodeMap.end()) {
  454. Builder.addEdge(LoopDepth, GI, Ref->getSecond());
  455. GI = Ref->getSecond();
  456. }
  457. }
  458. // Always add the terminator instruction, if one exists
  459. auto T = MBB->getFirstTerminator();
  460. if (T != MBB->end()) {
  461. auto EndBB = MaybeAddNode(&*T);
  462. if (EndBB.second)
  463. Builder.addEdge(LoopDepth, GI, EndBB.first);
  464. GI = EndBB.first;
  465. }
  466. }
  467. for (MachineBasicBlock *Succ : MBB->successors())
  468. TraverseCFG(Succ, GI, LoopDepth);
  469. };
  470. // ArgNodeSentinel is a pseudo-instruction that represents MF args in the
  471. // GadgetGraph
  472. GraphIter ArgNode = MaybeAddNode(MachineGadgetGraph::ArgNodeSentinel).first;
  473. TraverseCFG(&MF.front(), ArgNode, 0);
  474. std::unique_ptr<MachineGadgetGraph> G{Builder.get(FenceCount, GadgetCount)};
  475. LLVM_DEBUG(dbgs() << "Found " << G->nodes_size() << " nodes\n");
  476. return G;
  477. }
  478. // Returns the number of remaining gadget edges that could not be eliminated
  479. int X86LoadValueInjectionLoadHardeningPass::elimMitigatedEdgesAndNodes(
  480. MachineGadgetGraph &G, EdgeSet &ElimEdges /* in, out */,
  481. NodeSet &ElimNodes /* in, out */) const {
  482. if (G.NumFences > 0) {
  483. // Eliminate fences and CFG edges that ingress and egress the fence, as
  484. // they are trivially mitigated.
  485. for (const Edge &E : G.edges()) {
  486. const Node *Dest = E.getDest();
  487. if (isFence(Dest->getValue())) {
  488. ElimNodes.insert(*Dest);
  489. ElimEdges.insert(E);
  490. for (const Edge &DE : Dest->edges())
  491. ElimEdges.insert(DE);
  492. }
  493. }
  494. }
  495. // Find and eliminate gadget edges that have been mitigated.
  496. int RemainingGadgets = 0;
  497. NodeSet ReachableNodes{G};
  498. for (const Node &RootN : G.nodes()) {
  499. if (llvm::none_of(RootN.edges(), MachineGadgetGraph::isGadgetEdge))
  500. continue; // skip this node if it isn't a gadget source
  501. // Find all of the nodes that are CFG-reachable from RootN using DFS
  502. ReachableNodes.clear();
  503. std::function<void(const Node *, bool)> FindReachableNodes =
  504. [&](const Node *N, bool FirstNode) {
  505. if (!FirstNode)
  506. ReachableNodes.insert(*N);
  507. for (const Edge &E : N->edges()) {
  508. const Node *Dest = E.getDest();
  509. if (MachineGadgetGraph::isCFGEdge(E) && !ElimEdges.contains(E) &&
  510. !ReachableNodes.contains(*Dest))
  511. FindReachableNodes(Dest, false);
  512. }
  513. };
  514. FindReachableNodes(&RootN, true);
  515. // Any gadget whose sink is unreachable has been mitigated
  516. for (const Edge &E : RootN.edges()) {
  517. if (MachineGadgetGraph::isGadgetEdge(E)) {
  518. if (ReachableNodes.contains(*E.getDest())) {
  519. // This gadget's sink is reachable
  520. ++RemainingGadgets;
  521. } else { // This gadget's sink is unreachable, and therefore mitigated
  522. ElimEdges.insert(E);
  523. }
  524. }
  525. }
  526. }
  527. return RemainingGadgets;
  528. }
  529. std::unique_ptr<MachineGadgetGraph>
  530. X86LoadValueInjectionLoadHardeningPass::trimMitigatedEdges(
  531. std::unique_ptr<MachineGadgetGraph> Graph) const {
  532. NodeSet ElimNodes{*Graph};
  533. EdgeSet ElimEdges{*Graph};
  534. int RemainingGadgets =
  535. elimMitigatedEdgesAndNodes(*Graph, ElimEdges, ElimNodes);
  536. if (ElimEdges.empty() && ElimNodes.empty()) {
  537. Graph->NumFences = 0;
  538. Graph->NumGadgets = RemainingGadgets;
  539. } else {
  540. Graph = GraphBuilder::trim(*Graph, ElimNodes, ElimEdges, 0 /* NumFences */,
  541. RemainingGadgets);
  542. }
  543. return Graph;
  544. }
  545. int X86LoadValueInjectionLoadHardeningPass::hardenLoadsWithPlugin(
  546. MachineFunction &MF, std::unique_ptr<MachineGadgetGraph> Graph) const {
  547. int FencesInserted = 0;
  548. do {
  549. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths...\n");
  550. Graph = trimMitigatedEdges(std::move(Graph));
  551. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths... Done\n");
  552. if (Graph->NumGadgets == 0)
  553. break;
  554. LLVM_DEBUG(dbgs() << "Cutting edges...\n");
  555. EdgeSet CutEdges{*Graph};
  556. auto Nodes = std::make_unique<unsigned int[]>(Graph->nodes_size() +
  557. 1 /* terminator node */);
  558. auto Edges = std::make_unique<unsigned int[]>(Graph->edges_size());
  559. auto EdgeCuts = std::make_unique<int[]>(Graph->edges_size());
  560. auto EdgeValues = std::make_unique<int[]>(Graph->edges_size());
  561. for (const Node &N : Graph->nodes()) {
  562. Nodes[Graph->getNodeIndex(N)] = Graph->getEdgeIndex(*N.edges_begin());
  563. }
  564. Nodes[Graph->nodes_size()] = Graph->edges_size(); // terminator node
  565. for (const Edge &E : Graph->edges()) {
  566. Edges[Graph->getEdgeIndex(E)] = Graph->getNodeIndex(*E.getDest());
  567. EdgeValues[Graph->getEdgeIndex(E)] = E.getValue();
  568. }
  569. OptimizeCut(Nodes.get(), Graph->nodes_size(), Edges.get(), EdgeValues.get(),
  570. EdgeCuts.get(), Graph->edges_size());
  571. for (int I = 0; I < Graph->edges_size(); ++I)
  572. if (EdgeCuts[I])
  573. CutEdges.set(I);
  574. LLVM_DEBUG(dbgs() << "Cutting edges... Done\n");
  575. LLVM_DEBUG(dbgs() << "Cut " << CutEdges.count() << " edges\n");
  576. LLVM_DEBUG(dbgs() << "Inserting LFENCEs...\n");
  577. FencesInserted += insertFences(MF, *Graph, CutEdges);
  578. LLVM_DEBUG(dbgs() << "Inserting LFENCEs... Done\n");
  579. LLVM_DEBUG(dbgs() << "Inserted " << FencesInserted << " fences\n");
  580. Graph = GraphBuilder::trim(*Graph, NodeSet{*Graph}, CutEdges);
  581. } while (true);
  582. return FencesInserted;
  583. }
  584. int X86LoadValueInjectionLoadHardeningPass::hardenLoadsWithHeuristic(
  585. MachineFunction &MF, std::unique_ptr<MachineGadgetGraph> Graph) const {
  586. // If `MF` does not have any fences, then no gadgets would have been
  587. // mitigated at this point.
  588. if (Graph->NumFences > 0) {
  589. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths...\n");
  590. Graph = trimMitigatedEdges(std::move(Graph));
  591. LLVM_DEBUG(dbgs() << "Eliminating mitigated paths... Done\n");
  592. }
  593. if (Graph->NumGadgets == 0)
  594. return 0;
  595. LLVM_DEBUG(dbgs() << "Cutting edges...\n");
  596. EdgeSet CutEdges{*Graph};
  597. // Begin by collecting all ingress CFG edges for each node
  598. DenseMap<const Node *, SmallVector<const Edge *, 2>> IngressEdgeMap;
  599. for (const Edge &E : Graph->edges())
  600. if (MachineGadgetGraph::isCFGEdge(E))
  601. IngressEdgeMap[E.getDest()].push_back(&E);
  602. // For each gadget edge, make cuts that guarantee the gadget will be
  603. // mitigated. A computationally efficient way to achieve this is to either:
  604. // (a) cut all egress CFG edges from the gadget source, or
  605. // (b) cut all ingress CFG edges to the gadget sink.
  606. //
  607. // Moreover, the algorithm tries not to make a cut into a loop by preferring
  608. // to make a (b)-type cut if the gadget source resides at a greater loop depth
  609. // than the gadget sink, or an (a)-type cut otherwise.
  610. for (const Node &N : Graph->nodes()) {
  611. for (const Edge &E : N.edges()) {
  612. if (!MachineGadgetGraph::isGadgetEdge(E))
  613. continue;
  614. SmallVector<const Edge *, 2> EgressEdges;
  615. SmallVector<const Edge *, 2> &IngressEdges = IngressEdgeMap[E.getDest()];
  616. for (const Edge &EgressEdge : N.edges())
  617. if (MachineGadgetGraph::isCFGEdge(EgressEdge))
  618. EgressEdges.push_back(&EgressEdge);
  619. int EgressCutCost = 0, IngressCutCost = 0;
  620. for (const Edge *EgressEdge : EgressEdges)
  621. if (!CutEdges.contains(*EgressEdge))
  622. EgressCutCost += EgressEdge->getValue();
  623. for (const Edge *IngressEdge : IngressEdges)
  624. if (!CutEdges.contains(*IngressEdge))
  625. IngressCutCost += IngressEdge->getValue();
  626. auto &EdgesToCut =
  627. IngressCutCost < EgressCutCost ? IngressEdges : EgressEdges;
  628. for (const Edge *E : EdgesToCut)
  629. CutEdges.insert(*E);
  630. }
  631. }
  632. LLVM_DEBUG(dbgs() << "Cutting edges... Done\n");
  633. LLVM_DEBUG(dbgs() << "Cut " << CutEdges.count() << " edges\n");
  634. LLVM_DEBUG(dbgs() << "Inserting LFENCEs...\n");
  635. int FencesInserted = insertFences(MF, *Graph, CutEdges);
  636. LLVM_DEBUG(dbgs() << "Inserting LFENCEs... Done\n");
  637. LLVM_DEBUG(dbgs() << "Inserted " << FencesInserted << " fences\n");
  638. return FencesInserted;
  639. }
  640. int X86LoadValueInjectionLoadHardeningPass::insertFences(
  641. MachineFunction &MF, MachineGadgetGraph &G,
  642. EdgeSet &CutEdges /* in, out */) const {
  643. int FencesInserted = 0;
  644. for (const Node &N : G.nodes()) {
  645. for (const Edge &E : N.edges()) {
  646. if (CutEdges.contains(E)) {
  647. MachineInstr *MI = N.getValue(), *Prev;
  648. MachineBasicBlock *MBB; // Insert an LFENCE in this MBB
  649. MachineBasicBlock::iterator InsertionPt; // ...at this point
  650. if (MI == MachineGadgetGraph::ArgNodeSentinel) {
  651. // insert LFENCE at beginning of entry block
  652. MBB = &MF.front();
  653. InsertionPt = MBB->begin();
  654. Prev = nullptr;
  655. } else if (MI->isBranch()) { // insert the LFENCE before the branch
  656. MBB = MI->getParent();
  657. InsertionPt = MI;
  658. Prev = MI->getPrevNode();
  659. // Remove all egress CFG edges from this branch because the inserted
  660. // LFENCE prevents gadgets from crossing the branch.
  661. for (const Edge &E : N.edges()) {
  662. if (MachineGadgetGraph::isCFGEdge(E))
  663. CutEdges.insert(E);
  664. }
  665. } else { // insert the LFENCE after the instruction
  666. MBB = MI->getParent();
  667. InsertionPt = MI->getNextNode() ? MI->getNextNode() : MBB->end();
  668. Prev = InsertionPt == MBB->end()
  669. ? (MBB->empty() ? nullptr : &MBB->back())
  670. : InsertionPt->getPrevNode();
  671. }
  672. // Ensure this insertion is not redundant (two LFENCEs in sequence).
  673. if ((InsertionPt == MBB->end() || !isFence(&*InsertionPt)) &&
  674. (!Prev || !isFence(Prev))) {
  675. BuildMI(*MBB, InsertionPt, DebugLoc(), TII->get(X86::LFENCE));
  676. ++FencesInserted;
  677. }
  678. }
  679. }
  680. }
  681. return FencesInserted;
  682. }
  683. bool X86LoadValueInjectionLoadHardeningPass::instrUsesRegToAccessMemory(
  684. const MachineInstr &MI, unsigned Reg) const {
  685. if (!MI.mayLoadOrStore() || MI.getOpcode() == X86::MFENCE ||
  686. MI.getOpcode() == X86::SFENCE || MI.getOpcode() == X86::LFENCE)
  687. return false;
  688. // FIXME: This does not handle pseudo loading instruction like TCRETURN*
  689. const MCInstrDesc &Desc = MI.getDesc();
  690. int MemRefBeginIdx = X86II::getMemoryOperandNo(Desc.TSFlags);
  691. if (MemRefBeginIdx < 0) {
  692. LLVM_DEBUG(dbgs() << "Warning: unable to obtain memory operand for loading "
  693. "instruction:\n";
  694. MI.print(dbgs()); dbgs() << '\n';);
  695. return false;
  696. }
  697. MemRefBeginIdx += X86II::getOperandBias(Desc);
  698. const MachineOperand &BaseMO =
  699. MI.getOperand(MemRefBeginIdx + X86::AddrBaseReg);
  700. const MachineOperand &IndexMO =
  701. MI.getOperand(MemRefBeginIdx + X86::AddrIndexReg);
  702. return (BaseMO.isReg() && BaseMO.getReg() != X86::NoRegister &&
  703. TRI->regsOverlap(BaseMO.getReg(), Reg)) ||
  704. (IndexMO.isReg() && IndexMO.getReg() != X86::NoRegister &&
  705. TRI->regsOverlap(IndexMO.getReg(), Reg));
  706. }
  707. bool X86LoadValueInjectionLoadHardeningPass::instrUsesRegToBranch(
  708. const MachineInstr &MI, unsigned Reg) const {
  709. if (!MI.isConditionalBranch())
  710. return false;
  711. for (const MachineOperand &Use : MI.uses())
  712. if (Use.isReg() && Use.getReg() == Reg)
  713. return true;
  714. return false;
  715. }
  716. INITIALIZE_PASS_BEGIN(X86LoadValueInjectionLoadHardeningPass, PASS_KEY,
  717. "X86 LVI load hardening", false, false)
  718. INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
  719. INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
  720. INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
  721. INITIALIZE_PASS_END(X86LoadValueInjectionLoadHardeningPass, PASS_KEY,
  722. "X86 LVI load hardening", false, false)
  723. FunctionPass *llvm::createX86LoadValueInjectionLoadHardeningPass() {
  724. return new X86LoadValueInjectionLoadHardeningPass();
  725. }