[llvm-branch-commits] [llvm] 5bc4d47 - Revert "[X86] Add Support for Load Hardening to Mitigate Load Value Injection (LVI)"
Tom Stellard via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jun 24 09:35:59 PDT 2020
Author: Craig Topper
Date: 2020-06-24T09:31:04-07:00
New Revision: 5bc4d476f344e39d80df1c6df01279523adb83ef
URL: https://github.com/llvm/llvm-project/commit/5bc4d476f344e39d80df1c6df01279523adb83ef
DIFF: https://github.com/llvm/llvm-project/commit/5bc4d476f344e39d80df1c6df01279523adb83ef.diff
LOG: Revert "[X86] Add Support for Load Hardening to Mitigate Load Value Injection (LVI)"
This reverts commit 62c42e29ba43c9d79cd5bd2084b641fbff6a96d5
Reverting to address coding standard issues raised in post-commit
review.
Added:
Modified:
llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
Removed:
llvm/test/CodeGen/X86/lvi-hardening-loads.ll
################################################################################
diff --git a/llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp b/llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
index 5d8a81e33510..7c027e5fca67 100644
--- a/llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
+++ b/llvm/lib/Target/X86/X86LoadValueInjectionLoadHardening.cpp
@@ -9,30 +9,7 @@
/// Description: This pass finds Load Value Injection (LVI) gadgets consisting
/// of a load from memory (i.e., SOURCE), and any operation that may transmit
/// the value loaded from memory over a covert channel, or use the value loaded
-/// from memory to determine a branch/call target (i.e., SINK). After finding
-/// all such gadgets in a given function, the pass minimally inserts LFENCE
-/// instructions in such a manner that the following property is satisfied: for
-/// all SOURCE+SINK pairs, all paths in the CFG from SOURCE to SINK contain at
-/// least one LFENCE instruction. The algorithm that implements this minimal
-/// insertion is influenced by an academic paper that minimally inserts memory
-/// fences for high-performance concurrent programs:
-/// http://www.cs.ucr.edu/~lesani/companion/oopsla15/OOPSLA15.pdf
-/// The algorithm implemented in this pass is as follows:
-/// 1. Build a condensed CFG (i.e., a GadgetGraph) consisting only of the
-/// following components:
-/// - SOURCE instructions (also includes function arguments)
-/// - SINK instructions
-/// - Basic block entry points
-/// - Basic block terminators
-/// - LFENCE instructions
-/// 2. Analyze the GadgetGraph to determine which SOURCE+SINK pairs (i.e.,
-/// gadgets) are already mitigated by existing LFENCEs. If all gadgets have been
-/// mitigated, go to step 6.
-/// 3. Use a heuristic or plugin to approximate minimal LFENCE insertion.
-/// 4. Insert one LFENCE along each CFG edge that was cut in step 3.
-/// 5. Go to step 2.
-/// 6. If any LFENCEs were inserted, return `true` from runOnFunction() to tell
-/// LLVM that the function was modified.
+/// from memory to determine a branch/call target (i.e., SINK).
///
//===----------------------------------------------------------------------===//
@@ -60,7 +37,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
@@ -69,16 +45,11 @@ using namespace llvm;
#define PASS_KEY "x86-lvi-load"
#define DEBUG_TYPE PASS_KEY
-STATISTIC(NumFences, "Number of LFENCEs inserted for LVI mitigation");
STATISTIC(NumFunctionsConsidered, "Number of functions analyzed");
STATISTIC(NumFunctionsMitigated, "Number of functions for which mitigations "
"were deployed");
STATISTIC(NumGadgets, "Number of LVI gadgets detected during analysis");
-static cl::opt<std::string> OptimizePluginPath(
- PASS_KEY "-opt-plugin",
- cl::desc("Specify a plugin to optimize LFENCE insertion"), cl::Hidden);
-
static cl::opt<bool> NoConditionalBranches(
PASS_KEY "-no-cbranch",
cl::desc("Don't treat conditional branches as disclosure gadgets. This "
@@ -109,12 +80,6 @@ static cl::opt<bool> NoFixedLoads(
"may improve performance, at the cost of security."),
cl::init(false), cl::Hidden);
-static llvm::sys::DynamicLibrary OptimizeDL{};
-typedef int (*OptimizeCutT)(unsigned int *nodes, unsigned int nodes_size,
- unsigned int *edges, int *edge_values,
- int *cut_edges /* out */, unsigned int edges_size);
-static OptimizeCutT OptimizeCut = nullptr;
-
#define ARG_NODE nullptr
#define GADGET_EDGE ((int)(-1))
#define WEIGHT(EdgeValue) ((double)(2 * (EdgeValue) + 1))
@@ -174,11 +139,6 @@ class X86LoadValueInjectionLoadHardeningPass : public MachineFunctionPass {
getGadgetGraph(MachineFunction &MF, const MachineLoopInfo &MLI,
const MachineDominatorTree &MDT,
const MachineDominanceFrontier &MDF, bool FixedLoads) const;
- std::unique_ptr<MachineGadgetGraph>
- elimEdges(std::unique_ptr<MachineGadgetGraph> Graph) const;
- void cutEdges(MachineGadgetGraph &G, EdgeSet &CutEdges /* out */) const;
- int insertFences(MachineGadgetGraph &G,
- EdgeSet &CutEdges /* in, out */) const;
bool instrUsesRegToAccessMemory(const MachineInstr &I, unsigned Reg) const;
bool instrUsesRegToBranch(const MachineInstr &I, unsigned Reg) const;
@@ -281,17 +241,14 @@ bool X86LoadValueInjectionLoadHardeningPass::runOnMachineFunction(
TII = STI->getInstrInfo();
TRI = STI->getRegisterInfo();
LLVM_DEBUG(dbgs() << "Hardening data-dependent loads...\n");
- int FencesInserted = hardenLoads(MF, false);
+ hardenLoads(MF, false);
LLVM_DEBUG(dbgs() << "Hardening data-dependent loads... Done\n");
if (!NoFixedLoads) {
LLVM_DEBUG(dbgs() << "Hardening fixed loads...\n");
- FencesInserted += hardenLoads(MF, true);
+ hardenLoads(MF, true);
LLVM_DEBUG(dbgs() << "Hardening fixed loads... Done\n");
}
- if (FencesInserted > 0)
- ++NumFunctionsMitigated;
- NumFences += FencesInserted;
- return (FencesInserted > 0);
+ return false;
}
// Apply the mitigation to `MF`, return the number of fences inserted.
@@ -299,8 +256,6 @@ bool X86LoadValueInjectionLoadHardeningPass::runOnMachineFunction(
// loads; otherwise, mitigation will be applied to non-fixed loads.
int X86LoadValueInjectionLoadHardeningPass::hardenLoads(MachineFunction &MF,
bool FixedLoads) const {
- int FencesInserted = 0;
-
LLVM_DEBUG(dbgs() << "Building gadget graph...\n");
const auto &MLI = getAnalysis<MachineLoopInfo>();
const auto &MDT = getAnalysis<MachineDominatorTree>();
@@ -334,27 +289,7 @@ int X86LoadValueInjectionLoadHardeningPass::hardenLoads(MachineFunction &MF,
return 0;
}
- do {
- LLVM_DEBUG(dbgs() << "Eliminating mitigated paths...\n");
- std::unique_ptr<MachineGadgetGraph> ElimGraph = elimEdges(std::move(Graph));
- LLVM_DEBUG(dbgs() << "Eliminating mitigated paths... Done\n");
- if (ElimGraph->NumGadgets == 0)
- break;
-
- EdgeSet CutEdges{*ElimGraph};
- LLVM_DEBUG(dbgs() << "Cutting edges...\n");
- cutEdges(*ElimGraph, CutEdges);
- LLVM_DEBUG(dbgs() << "Cutting edges... Done\n");
-
- LLVM_DEBUG(dbgs() << "Inserting LFENCEs...\n");
- FencesInserted += insertFences(*ElimGraph, CutEdges);
- LLVM_DEBUG(dbgs() << "Inserting LFENCEs... Done\n");
-
- Graph.reset(GraphBuilder::trim(
- *ElimGraph, MachineGadgetGraph::NodeSet{*ElimGraph}, CutEdges));
- } while (true);
-
- return FencesInserted;
+ return 0;
}
std::unique_ptr<X86LoadValueInjectionLoadHardeningPass::MachineGadgetGraph>
@@ -526,213 +461,6 @@ X86LoadValueInjectionLoadHardeningPass::getGadgetGraph(
return G;
}
-std::unique_ptr<X86LoadValueInjectionLoadHardeningPass::MachineGadgetGraph>
-X86LoadValueInjectionLoadHardeningPass::elimEdges(
- std::unique_ptr<MachineGadgetGraph> Graph) const {
- MachineGadgetGraph::NodeSet ElimNodes{*Graph};
- MachineGadgetGraph::EdgeSet ElimEdges{*Graph};
-
- if (Graph->NumFences > 0) { // eliminate fences
- for (auto EI = Graph->edges_begin(), EE = Graph->edges_end(); EI != EE;
- ++EI) {
- GTraits::NodeRef Dest = GTraits::edge_dest(*EI);
- if (isFence(Dest->value())) {
- ElimNodes.insert(Dest);
- ElimEdges.insert(EI);
- std::for_each(
- GTraits::child_edge_begin(Dest), GTraits::child_edge_end(Dest),
- [&ElimEdges](GTraits::EdgeRef E) { ElimEdges.insert(&E); });
- }
- }
- LLVM_DEBUG(dbgs() << "Eliminated " << ElimNodes.count()
- << " fence nodes\n");
- }
-
- // eliminate gadget edges that are mitigated
- int NumGadgets = 0;
- MachineGadgetGraph::NodeSet Visited{*Graph}, GadgetSinks{*Graph};
- MachineGadgetGraph::EdgeSet ElimGadgets{*Graph};
- for (auto NI = GTraits::nodes_begin(Graph.get()),
- NE = GTraits::nodes_end(Graph.get());
- NI != NE; ++NI) {
- // collect the gadgets for this node
- for (auto EI = GTraits::child_edge_begin(*NI),
- EE = GTraits::child_edge_end(*NI);
- EI != EE; ++EI) {
- if (MachineGadgetGraph::isGadgetEdge(*EI)) {
- ++NumGadgets;
- ElimGadgets.insert(EI);
- GadgetSinks.insert(GTraits::edge_dest(*EI));
- }
- }
- if (GadgetSinks.empty())
- continue;
- std::function<void(GTraits::NodeRef, bool)> TraverseDFS =
- [&](GTraits::NodeRef N, bool FirstNode) {
- if (!FirstNode) {
- Visited.insert(N);
- if (GadgetSinks.contains(N)) {
- for (auto CEI = GTraits::child_edge_begin(*NI),
- CEE = GTraits::child_edge_end(*NI);
- CEI != CEE; ++CEI) {
- if (MachineGadgetGraph::isGadgetEdge(*CEI) &&
- GTraits::edge_dest(*CEI) == N)
- ElimGadgets.erase(CEI);
- }
- }
- }
- for (auto CEI = GTraits::child_edge_begin(N),
- CEE = GTraits::child_edge_end(N);
- CEI != CEE; ++CEI) {
- GTraits::NodeRef Dest = GTraits::edge_dest(*CEI);
- if (MachineGadgetGraph::isCFGEdge(*CEI) &&
- !Visited.contains(Dest) && !ElimEdges.contains(CEI))
- TraverseDFS(Dest, false);
- }
- };
- TraverseDFS(*NI, true);
- Visited.clear();
- GadgetSinks.clear();
- }
- LLVM_DEBUG(dbgs() << "Eliminated " << ElimGadgets.count()
- << " gadget edges\n");
- ElimEdges |= ElimGadgets;
-
- if (!(ElimEdges.empty() && ElimNodes.empty())) {
- int NumRemainingGadgets = NumGadgets - ElimGadgets.count();
- Graph.reset(GraphBuilder::trim(*Graph, ElimNodes, ElimEdges,
- 0 /* NumFences */, NumRemainingGadgets));
- } else {
- Graph->NumFences = 0;
- Graph->NumGadgets = NumGadgets;
- }
- return Graph;
-}
-
-void X86LoadValueInjectionLoadHardeningPass::cutEdges(
- MachineGadgetGraph &G,
- MachineGadgetGraph::EdgeSet &CutEdges /* out */) const {
- if (!OptimizePluginPath.empty()) {
- if (!OptimizeDL.isValid()) {
- std::string ErrorMsg{};
- OptimizeDL = llvm::sys::DynamicLibrary::getPermanentLibrary(
- OptimizePluginPath.c_str(), &ErrorMsg);
- if (!ErrorMsg.empty())
- report_fatal_error("Failed to load opt plugin: \"" + ErrorMsg + '\"');
- OptimizeCut = (OptimizeCutT)OptimizeDL.getAddressOfSymbol("optimize_cut");
- if (!OptimizeCut)
- report_fatal_error("Invalid optimization plugin");
- }
- auto *Nodes = new unsigned int[G.nodes_size() + 1 /* terminator node */];
- auto *Edges = new unsigned int[G.edges_size()];
- auto *EdgeCuts = new int[G.edges_size()];
- auto *EdgeValues = new int[G.edges_size()];
- for (auto *NI = G.nodes_begin(), *NE = G.nodes_end(); NI != NE; ++NI) {
- Nodes[std::distance(G.nodes_begin(), NI)] =
- std::distance(G.edges_begin(), GTraits::child_edge_begin(NI));
- }
- Nodes[G.nodes_size()] = G.edges_size(); // terminator node
- for (auto *EI = G.edges_begin(), *EE = G.edges_end(); EI != EE; ++EI) {
- Edges[std::distance(G.edges_begin(), EI)] =
- std::distance(G.nodes_begin(), GTraits::edge_dest(*EI));
- EdgeValues[std::distance(G.edges_begin(), EI)] = EI->value();
- }
- OptimizeCut(Nodes, G.nodes_size(), Edges, EdgeValues, EdgeCuts,
- G.edges_size());
- for (int I = 0; I < G.edges_size(); ++I) {
- if (EdgeCuts[I])
- CutEdges.set(I);
- }
- delete[] Nodes;
- delete[] Edges;
- delete[] EdgeCuts;
- delete[] EdgeValues;
- } else { // Use the default greedy heuristic
- // Find the cheapest CFG edge that will eliminate a gadget (by being egress
- // from a SOURCE node or ingress to a SINK node), and cut it.
- MachineGadgetGraph::NodeSet GadgetSinks{G};
- MachineGadgetGraph::Edge *CheapestSoFar = nullptr;
- for (auto NI = GTraits::nodes_begin(&G), NE = GTraits::nodes_end(&G);
- NI != NE; ++NI) {
- for (auto EI = GTraits::child_edge_begin(*NI),
- EE = GTraits::child_edge_end(*NI);
- EI != EE; ++EI) {
- if (MachineGadgetGraph::isGadgetEdge(*EI)) {
- // NI is a SOURCE node. Look for a cheap egress edge
- for (auto EEI = GTraits::child_edge_begin(*NI); EEI != EE; ++EEI) {
- if (MachineGadgetGraph::isCFGEdge(*EEI)) {
- if (!CheapestSoFar || EEI->value() < CheapestSoFar->value())
- CheapestSoFar = EEI;
- }
- }
- GadgetSinks.insert(GTraits::edge_dest(*EI));
- } else { // EI is a CFG edge
- if (GadgetSinks.contains(GTraits::edge_dest(*EI))) {
- // The dest is a SINK node. Hence EI is an ingress edge
- if (!CheapestSoFar || EI->value() < CheapestSoFar->value())
- CheapestSoFar = EI;
- }
- }
- }
- }
- assert(CheapestSoFar && "Failed to cut an edge");
- CutEdges.insert(CheapestSoFar);
- }
- LLVM_DEBUG(dbgs() << "Cut " << CutEdges.count() << " edges\n");
-}
-
-int X86LoadValueInjectionLoadHardeningPass::insertFences(
- MachineGadgetGraph &G, EdgeSet &CutEdges /* in, out */) const {
- int FencesInserted = 0, AdditionalEdgesCut = 0;
- auto CutAllCFGEdges = [&CutEdges, &AdditionalEdgesCut](GTraits::NodeRef N) {
- for (auto CEI = GTraits::child_edge_begin(N),
- CEE = GTraits::child_edge_end(N);
- CEI != CEE; ++CEI) {
- if (MachineGadgetGraph::isCFGEdge(*CEI) && !CutEdges.contains(CEI)) {
- CutEdges.insert(CEI);
- ++AdditionalEdgesCut;
- }
- }
- };
- for (auto NI = GTraits::nodes_begin(&G), NE = GTraits::nodes_end(&G);
- NI != NE; ++NI) {
- for (auto CEI = GTraits::child_edge_begin(*NI),
- CEE = GTraits::child_edge_end(*NI);
- CEI != CEE; ++CEI) {
- if (CutEdges.contains(CEI)) {
- MachineInstr *MI = (*NI)->value(), *Prev;
- MachineBasicBlock *MBB;
- MachineBasicBlock::iterator InsertionPt;
- if (MI == ARG_NODE) { // insert LFENCE at beginning of entry block
- MBB = &G.getMF().front();
- InsertionPt = MBB->begin();
- Prev = nullptr;
- } else if (MI->isBranch()) { // insert the LFENCE before the branch
- MBB = MI->getParent();
- InsertionPt = MI;
- Prev = MI->getPrevNode();
- CutAllCFGEdges(*NI);
- } else { // insert the LFENCE after the instruction
- MBB = MI->getParent();
- InsertionPt = MI->getNextNode() ? MI->getNextNode() : MBB->end();
- Prev = InsertionPt == MBB->end()
- ? (MBB->empty() ? nullptr : &MBB->back())
- : InsertionPt->getPrevNode();
- }
- if ((InsertionPt == MBB->end() || !isFence(&*InsertionPt)) &&
- (!Prev || !isFence(Prev))) {
- BuildMI(*MBB, InsertionPt, DebugLoc(), TII->get(X86::LFENCE));
- ++FencesInserted;
- }
- }
- }
- }
- LLVM_DEBUG(dbgs() << "Inserted " << FencesInserted << " fences\n");
- LLVM_DEBUG(dbgs() << "Cut an additional " << AdditionalEdgesCut
- << " edges during fence insertion\n");
- return FencesInserted;
-}
-
bool X86LoadValueInjectionLoadHardeningPass::instrUsesRegToAccessMemory(
const MachineInstr &MI, unsigned Reg) const {
if (!MI.mayLoadOrStore() || MI.getOpcode() == X86::MFENCE ||
diff --git a/llvm/test/CodeGen/X86/lvi-hardening-loads.ll b/llvm/test/CodeGen/X86/lvi-hardening-loads.ll
deleted file mode 100644
index 296fa39b17ed..000000000000
--- a/llvm/test/CodeGen/X86/lvi-hardening-loads.ll
+++ /dev/null
@@ -1,102 +0,0 @@
-; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown < %s | FileCheck %s --check-prefix=X64 --check-prefix=X64-CBFX
-; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown --x86-lvi-load-no-fixed < %s | FileCheck %s --check-prefix=X64 --check-prefix=X64-CB
-; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown --x86-lvi-load-no-cbranch < %s | FileCheck %s --check-prefix=X64 --check-prefix=X64-FX
-; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown --x86-lvi-load-no-fixed --x86-lvi-load-no-cbranch < %s | FileCheck %s --check-prefix=X64 --check-prefix=X64-BASE
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local i32 @test(i32** %secret, i32 %secret_size) #0 {
-; X64-LABEL: test:
-entry:
- %secret.addr = alloca i32**, align 8
- %secret_size.addr = alloca i32, align 4
- %ret_val = alloca i32, align 4
- %i = alloca i32, align 4
- store i32** %secret, i32*** %secret.addr, align 8
- store i32 %secret_size, i32* %secret_size.addr, align 4
- store i32 0, i32* %ret_val, align 4
- call void @llvm.x86.sse2.lfence()
- store i32 0, i32* %i, align 4
- br label %for.cond
-
-; X64: # %bb.0: # %entry
-; X64-NEXT: movq %rdi, -{{[0-9]+}}(%rsp)
-; X64-NEXT: movl %esi, -{{[0-9]+}}(%rsp)
-; X64-NEXT: movl $0, -{{[0-9]+}}(%rsp)
-; X64-NEXT: lfence
-; X64-NEXT: movl $0, -{{[0-9]+}}(%rsp)
-; X64-NEXT: jmp .LBB0_1
-
-for.cond: ; preds = %for.inc, %entry
- %0 = load i32, i32* %i, align 4
- %1 = load i32, i32* %secret_size.addr, align 4
- %cmp = icmp slt i32 %0, %1
- br i1 %cmp, label %for.body, label %for.end
-
-; X64: .LBB0_1: # %for.cond
-; X64-NEXT: # =>This Inner Loop Header: Depth=1
-; X64-NEXT: movl -{{[0-9]+}}(%rsp), %eax
-; X64-CBFX-NEXT: lfence
-; X64-NEXT: cmpl -{{[0-9]+}}(%rsp), %eax
-; X64-CBFX-NEXT: lfence
-; X64-NEXT: jge .LBB0_5
-
-for.body: ; preds = %for.cond
- %2 = load i32, i32* %i, align 4
- %rem = srem i32 %2, 2
- %cmp1 = icmp eq i32 %rem, 0
- br i1 %cmp1, label %if.then, label %if.end
-
-; X64: # %bb.2: # %for.body
-; X64-NEXT: # in Loop: Header=BB0_1 Depth=1
-; X64-NEXT: movl -{{[0-9]+}}(%rsp), %eax
-; X64-CBFX-NEXT: lfence
-; X64-NEXT: movl %eax, %ecx
-; X64-NEXT: shrl $31, %ecx
-; X64-NEXT: addl %eax, %ecx
-; X64-NEXT: andl $-2, %ecx
-; X64-NEXT: cmpl %ecx, %eax
-; X64-NEXT: jne .LBB0_4
-
-if.then: ; preds = %for.body
- %3 = load i32**, i32*** %secret.addr, align 8
- %4 = load i32, i32* %ret_val, align 4
- %idxprom = sext i32 %4 to i64
- %arrayidx = getelementptr inbounds i32*, i32** %3, i64 %idxprom
- %5 = load i32*, i32** %arrayidx, align 8
- %6 = load i32, i32* %5, align 4
- store i32 %6, i32* %ret_val, align 4
- br label %if.end
-
-; X64: # %bb.3: # %if.then
-; X64-NEXT: # in Loop: Header=BB0_1 Depth=1
-; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rax
-; X64-CBFX-NEXT: lfence
-; X64-FX-NEXT: lfence
-; X64-NEXT: movslq -{{[0-9]+}}(%rsp), %rcx
-; X64-CBFX-NEXT: lfence
-; X64-FX-NEXT: lfence
-; X64-NEXT: movq (%rax,%rcx,8), %rax
-; X64-NEXT: lfence
-; X64-NEXT: movl (%rax), %eax
-; X64-NEXT: movl %eax, -{{[0-9]+}}(%rsp)
-; X64-NEXT: jmp .LBB0_4
-
-if.end: ; preds = %if.then, %for.body
- br label %for.inc
-
-for.inc: ; preds = %if.end
- %7 = load i32, i32* %i, align 4
- %inc = add nsw i32 %7, 1
- store i32 %inc, i32* %i, align 4
- br label %for.cond
-
-for.end: ; preds = %for.cond
- %8 = load i32, i32* %ret_val, align 4
- ret i32 %8
-}
-
-; Function Attrs: nounwind
-declare void @llvm.x86.sse2.lfence() #1
-
-attributes #0 = { "target-features"="+lvi-load-hardening" }
-attributes #1 = { nounwind }
More information about the llvm-branch-commits
mailing list