LLVM  10.0.0svn
Macros | Functions | Variables
X86SpeculativeLoadHardening.cpp File Reference

Provide a pass which mitigates speculative execution attacks which operate by speculating incorrectly past some predicate (a type check, bounds check, or other condition) to reach a load with invalid inputs and leak the data accessed by that load using a side channel out of the speculative domain. More...

#include "X86.h"
#include "X86InstrBuilder.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseBitVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineSSAUpdater.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/MC/MCSchedule.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <utility>
Include dependency graph for X86SpeculativeLoadHardening.cpp:

Go to the source code of this file.

Macros

#define PASS_KEY   "x86-slh"
 
#define DEBUG_TYPE   PASS_KEY
 

Functions

 STATISTIC (NumCondBranchesTraced, "Number of conditional branches traced")
 
 STATISTIC (NumBranchesUntraced, "Number of branches unable to trace")
 
 STATISTIC (NumAddrRegsHardened, "Number of address mode used registers hardaned")
 
 STATISTIC (NumPostLoadRegsHardened, "Number of post-load register values hardened")
 
 STATISTIC (NumCallsOrJumpsHardened, "Number of calls or jumps requiring extra hardening")
 
 STATISTIC (NumInstsInserted, "Number of instructions inserted")
 
 STATISTIC (NumLFENCEsInserted, "Number of lfence instructions inserted")
 
static MachineBasicBlocksplitEdge (MachineBasicBlock &MBB, MachineBasicBlock &Succ, int SuccCount, MachineInstr *Br, MachineInstr *&UncondBr, const X86InstrInfo &TII)
 
static void canonicalizePHIOperands (MachineFunction &MF)
 Removing duplicate PHI operands to leave the PHI in a canonical and predictable form. More...
 
static bool hasVulnerableLoad (MachineFunction &MF)
 Helper to scan a function for loads vulnerable to misspeculation that we want to harden. More...
 
static const TargetRegisterClassgetRegClassForUnfoldedLoad (MachineFunction &MF, const X86InstrInfo &TII, unsigned Opcode)
 Compute the register class for the unfolded load. More...
 
static bool isDataInvariant (MachineInstr &MI)
 Returns true if the instruction has no behavior (specified or otherwise) that is based on the value of any of its register operands. More...
 
static bool isDataInvariantLoad (MachineInstr &MI)
 Returns true if the instruction has no behavior (specified or otherwise) that is based on the value loaded from memory or the value of any non-address register operands. More...
 
static bool isEFLAGSLive (MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const TargetRegisterInfo &TRI)
 
 INITIALIZE_PASS_BEGIN (X86SpeculativeLoadHardeningPass, PASS_KEY, "X86 speculative load hardener", false, false) INITIALIZE_PASS_END(X86SpeculativeLoadHardeningPass
 

Variables

static cl::opt< boolEnableSpeculativeLoadHardening ("x86-speculative-load-hardening", cl::desc("Force enable speculative load hardening"), cl::init(false), cl::Hidden)
 
static cl::opt< boolHardenEdgesWithLFENCE (PASS_KEY "-lfence", cl::desc("Use LFENCE along each conditional edge to harden against speculative " "loads rather than conditional movs and poisoned pointers."), cl::init(false), cl::Hidden)
 
static cl::opt< boolEnablePostLoadHardening (PASS_KEY "-post-load", cl::desc("Harden the value loaded *after* it is loaded by " "flushing the loaded bits to 1. This is hard to do " "in general but can be done easily for GPRs."), cl::init(true), cl::Hidden)
 
static cl::opt< boolFenceCallAndRet (PASS_KEY "-fence-call-and-ret", cl::desc("Use a full speculation fence to harden both call and ret edges " "rather than a lighter weight mitigation."), cl::init(false), cl::Hidden)
 
static cl::opt< boolHardenInterprocedurally (PASS_KEY "-ip", cl::desc("Harden interprocedurally by passing our state in and out of " "functions in the high bits of the stack pointer."), cl::init(true), cl::Hidden)
 
static cl::opt< boolHardenLoads (PASS_KEY "-loads", cl::desc("Sanitize loads from memory. When disable, no " "significant security is provided."), cl::init(true), cl::Hidden)
 
static cl::opt< boolHardenIndirectCallsAndJumps (PASS_KEY "-indirect", cl::desc("Harden indirect calls and jumps against using speculatively " "stored attacker controlled addresses. This is designed to " "mitigate Spectre v1.2 style attacks."), cl::init(true), cl::Hidden)
 
 PASS_KEY
 
X86 speculative load hardener
 
X86 speculative load false
 

Detailed Description

Provide a pass which mitigates speculative execution attacks which operate by speculating incorrectly past some predicate (a type check, bounds check, or other condition) to reach a load with invalid inputs and leak the data accessed by that load using a side channel out of the speculative domain.

For details on the attacks, see the first variant in both the Project Zero writeup and the Spectre paper: https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html https://spectreattack.com/spectre.pdf

Definition in file X86SpeculativeLoadHardening.cpp.

Macro Definition Documentation

◆ DEBUG_TYPE

#define DEBUG_TYPE   PASS_KEY

Definition at line 64 of file X86SpeculativeLoadHardening.cpp.

◆ PASS_KEY

#define PASS_KEY   "x86-slh"

Definition at line 63 of file X86SpeculativeLoadHardening.cpp.

Referenced by isEFLAGSLive().

Function Documentation

◆ canonicalizePHIOperands()

static void canonicalizePHIOperands ( MachineFunction MF)
static

Removing duplicate PHI operands to leave the PHI in a canonical and predictable form.

FIXME: It's really frustrating that we have to do this, but SSA-form in MIR isn't what you might expect. We may have multiple entries in PHI nodes for a single predecessor. This makes CFG-updating extremely complex, so here we simplify all PHI nodes to a model even simpler than the IR's model: exactly one entry per predecessor, regardless of how many edges there are.

Definition at line 327 of file X86SpeculativeLoadHardening.cpp.

References llvm::SmallPtrSetImplBase::clear(), llvm::SmallVectorBase::empty(), llvm::SmallPtrSetImpl< PtrType >::insert(), MI, llvm::SmallVectorImpl< T >::pop_back_val(), llvm::SmallVectorTemplateBase< T, bool >::push_back(), and second.

Referenced by hasVulnerableLoad().

◆ getRegClassForUnfoldedLoad()

static const TargetRegisterClass* getRegClassForUnfoldedLoad ( MachineFunction MF,
const X86InstrInfo TII,
unsigned  Opcode 
)
static

Compute the register class for the unfolded load.

FIXME: This should probably live in X86InstrInfo, potentially by adding a way to unfold into a newly created vreg rather than requiring a register input.

Definition at line 840 of file X86SpeculativeLoadHardening.cpp.

References llvm::MachineSSAUpdater::AddAvailableValue(), llvm::MachineInstrBuilder::addImm(), llvm::MachineInstrBuilder::addMBB(), llvm::MachineInstrBuilder::addReg(), llvm::all_of(), llvm::any_of(), assert(), llvm::BuildMI(), llvm::X86::COND_NE, llvm::SmallPtrSetImpl< PtrType >::count(), llvm::dbgs(), llvm::Pass::dump(), llvm::MachineInstr::dump(), llvm::SmallPtrSetImplBase::empty(), llvm::MachineInstr::eraseFromParent(), llvm::MachineInstr::findRegisterUseOperand(), llvm::X86::getCMovOpcode(), llvm::ilist_node_impl< OptionsT >::getIterator(), llvm::MachineInstr::getOpcode(), llvm::X86InstrInfo::getOpcodeAfterMemoryUnfold(), llvm::MachineInstr::getOperand(), llvm::MachineOperand::getReg(), llvm::X86InstrInfo::getRegisterInfo(), llvm::MachineSSAUpdater::GetValueInMiddleOfBlock(), llvm::MachineSSAUpdater::Initialize(), llvm::SmallPtrSetImpl< PtrType >::insert(), llvm::MachineInstr::isBranch(), llvm::MachineInstr::isCall(), llvm::MachineInstr::isTerminator(), llvm::RegState::Kill, LLVM_DEBUG, llvm_unreachable, llvm::MachineInstr::mayLoad(), MI, MRI, llvm::MachineBasicBlock::predecessors(), llvm::SmallVectorTemplateBase< T >::push_back(), Reg, llvm::report_fatal_error(), llvm::MachineOperand::setIsKill(), llvm::CodeModel::Small, llvm::MachineBasicBlock::successors(), TII, and TRI.

◆ hasVulnerableLoad()

static bool hasVulnerableLoad ( MachineFunction MF)
static

Helper to scan a function for loads vulnerable to misspeculation that we want to harden.

We use this to avoid making changes to functions where there is nothing we need to do to harden against misspeculation.

Definition at line 371 of file X86SpeculativeLoadHardening.cpp.

References llvm::MachineInstrBuilder::addImm(), llvm::MachineInstrBuilder::addReg(), assert(), llvm::MachineBasicBlock::begin(), llvm::MachineFunction::begin(), llvm::BuildMI(), canonicalizePHIOperands(), llvm::X86::COND_INVALID, llvm::dbgs(), llvm::MachineFunction::dump(), llvm::SmallVectorBase::empty(), EnableSpeculativeLoadHardening, llvm::MachineFunction::end(), FenceCallAndRet, llvm::X86::getCondFromBranch(), llvm::MachineFunction::getFunction(), llvm::MachineOperand::getMBB(), llvm::MachineBasicBlock::getName(), llvm::MachineFunction::getName(), llvm::MachineInstr::getOpcode(), llvm::MachineInstr::getOperand(), llvm::MachineFunction::getRegInfo(), llvm::MachineFunction::getSubtarget(), HardenEdgesWithLFENCE, HardenIndirectCallsAndJumps, HardenInterprocedurally, llvm::Function::hasFnAttribute(), Info, llvm::SetVector< T, SmallVector< T, N >, SmallDenseSet< T, N > >::insert(), llvm::MachineOperand::isImplicit(), llvm::MachineBasicBlock::isLiveIn(), LLVM_DEBUG, llvm::X86ISD::MFENCE, MI, MRI, llvm::SmallVectorTemplateBase< T >::push_back(), llvm::reverse(), llvm::MachineOperand::setIsDead(), llvm::MachineBasicBlock::SkipPHIsLabelsAndDebug(), splitEdge(), llvm::MachineBasicBlock::successors(), TII, TRI, and llvm::MachineFunction::verify().

◆ INITIALIZE_PASS_BEGIN()

INITIALIZE_PASS_BEGIN ( X86SpeculativeLoadHardeningPass  ,
PASS_KEY  ,
"X86 speculative load hardener ,
false  ,
false   
)

Referenced by isEFLAGSLive().

◆ isDataInvariant()

static bool isDataInvariant ( MachineInstr MI)
static

Returns true if the instruction has no behavior (specified or otherwise) that is based on the value of any of its register operands.

A classical example of something that is inherently not data invariant is an indirect jump – the destination is loaded into icache based on the bits set in the jump destination register.

FIXME: This should become part of our instruction tables.

Definition at line 1206 of file X86SpeculativeLoadHardening.cpp.

References llvm::dbgs(), llvm::MachineInstr::dump(), llvm::MachineInstr::findRegisterDefOperand(), llvm::MachineInstr::getOpcode(), llvm::MachineOperand::isDead(), LLVM_DEBUG, and LLVM_FALLTHROUGH.

Referenced by isEFLAGSLive().

◆ isDataInvariantLoad()

static bool isDataInvariantLoad ( MachineInstr MI)
static

Returns true if the instruction has no behavior (specified or otherwise) that is based on the value loaded from memory or the value of any non-address register operands.

For example, if the latency of the instruction is dependent on the particular bits set in any of the registers or any of the bits loaded from memory.

A classical example of something that is inherently not data invariant is an indirect jump – the destination is loaded into icache based on the bits set in the jump destination register.

FIXME: This should become part of our instruction tables.

Definition at line 1405 of file X86SpeculativeLoadHardening.cpp.

References llvm::dbgs(), llvm::MachineInstr::dump(), llvm::MachineInstr::findRegisterDefOperand(), llvm::MachineInstr::getOpcode(), llvm::MachineOperand::isDead(), LLVM_DEBUG, and LLVM_FALLTHROUGH.

Referenced by isEFLAGSLive().

◆ isEFLAGSLive()

static bool isEFLAGSLive ( MachineBasicBlock MBB,
MachineBasicBlock::iterator  I,
const TargetRegisterInfo TRI 
)
static

Definition at line 1588 of file X86SpeculativeLoadHardening.cpp.

References llvm::MachineInstrBuilder::addImm(), llvm::X86::AddrBaseReg, llvm::MachineInstrBuilder::addReg(), llvm::MachineInstr::addRegisterDead(), llvm::X86::AddrIndexReg, llvm::MachineInstrBuilder::addSym(), llvm::any_of(), assert(), llvm::MachineBasicBlock::begin(), llvm::BuildMI(), llvm::SmallPtrSetImplBase::clear(), llvm::DenseMapBase< SmallDenseMap< KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT >, KeyT, ValueT, KeyInfoT, BucketT >::clear(), llvm::SmallSet< T, N, C >::clear(), llvm::SparseBitVector< ElementSize >::clear(), llvm::X86::COND_NE, llvm::DenseMapBase< SmallDenseMap< KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT >, KeyT, ValueT, KeyInfoT, BucketT >::count(), llvm::SmallSet< T, N, C >::count(), llvm::SmallPtrSetImpl< PtrType >::count(), llvm::MCContext::createTempSymbol(), llvm::dbgs(), llvm::tgtok::Def, llvm::Pass::dump(), llvm::MachineInstr::dump(), EnablePostLoadHardening, llvm::DenseMapBase< SmallDenseMap< KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT >, KeyT, ValueT, KeyInfoT, BucketT >::end(), llvm::MachineBasicBlock::end(), llvm::SmallPtrSetImpl< PtrType >::erase(), llvm::erase_if(), llvm::MachineFunction::exposesReturnsTwice(), FenceCallAndRet, llvm::DenseMapBase< SmallDenseMap< KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT >, KeyT, ValueT, KeyInfoT, BucketT >::find(), llvm::MachineInstr::findRegisterUseOperand(), llvm::X86::getCMovOpcode(), llvm::TargetMachine::getCodeModel(), llvm::MachineFunction::getContext(), llvm::MachineInstr::getDebugLoc(), llvm::ilist_node_impl< OptionsT >::getIterator(), llvm::X86II::getMemoryOperandNo(), llvm::MachineInstr::getOpcode(), llvm::MachineInstr::getOperand(), llvm::X86II::getOperandBias(), llvm::MachineBasicBlock::getParent(), llvm::MachineInstr::getParent(), llvm::MachineInstrBuilder::getReg(), llvm::MachineOperand::getReg(), llvm::MachineFunction::getTarget(), HardenIndirectCallsAndJumps, HardenInterprocedurally, HardenLoads, llvm::TargetRegisterClass::hasSuperClassEq(), I, INITIALIZE_PASS_BEGIN(), llvm::SmallSet< T, N, C >::insert(), llvm::SmallPtrSetImpl< PtrType >::insert(), llvm::SystemZII::Is128Bit, isDataInvariant(), isDataInvariantLoad(), llvm::MachineOperand::isFI(), llvm::MachineBasicBlock::isLiveIn(), llvm::MachineOperand::isReg(), llvm::MachineInstr::isReturn(), llvm::Register::isVirtualRegister(), llvm::RegState::Kill, LLVM_DEBUG, llvm::Log2_32(), llvm::make_range(), llvm::MachineInstr::mayLoad(), llvm::X86ISD::MFENCE, MI, MRI, PASS_KEY, Reg, llvm::reverse(), llvm::SparseBitVector< ElementSize >::set(), llvm::MachineOperand::setIsKill(), llvm::MachineInstr::setPostInstrSymbol(), llvm::MachineOperand::setReg(), llvm::CodeModel::Small, llvm::MachineBasicBlock::succ_empty(), llvm::SparseBitVector< ElementSize >::test(), TII, TRI, llvm::MCInstrDesc::TSFlags, and UseMI.

◆ splitEdge()

static MachineBasicBlock& splitEdge ( MachineBasicBlock MBB,
MachineBasicBlock Succ,
int  SuccCount,
MachineInstr Br,
MachineInstr *&  UncondBr,
const X86InstrInfo TII 
)
static

◆ STATISTIC() [1/7]

STATISTIC ( NumCondBranchesTraced  ,
"Number of conditional branches traced"   
)

◆ STATISTIC() [2/7]

STATISTIC ( NumBranchesUntraced  ,
"Number of branches unable to trace"   
)

◆ STATISTIC() [3/7]

STATISTIC ( NumAddrRegsHardened  ,
"Number of address mode used registers hardaned"   
)

◆ STATISTIC() [4/7]

STATISTIC ( NumPostLoadRegsHardened  ,
"Number of post-load register values hardened"   
)

◆ STATISTIC() [5/7]

STATISTIC ( NumCallsOrJumpsHardened  ,
"Number of calls or jumps requiring extra hardening"   
)

◆ STATISTIC() [6/7]

STATISTIC ( NumInstsInserted  ,
"Number of instructions inserted"   
)

◆ STATISTIC() [7/7]

STATISTIC ( NumLFENCEsInserted  ,
"Number of lfence instructions inserted"   
)

Variable Documentation

◆ EnablePostLoadHardening

cl::opt<bool> EnablePostLoadHardening(PASS_KEY "-post-load", cl::desc("Harden the value loaded *after* it is loaded by " "flushing the loaded bits to 1. This is hard to do " "in general but can be done easily for GPRs."), cl::init(true), cl::Hidden)
static

Referenced by isEFLAGSLive().

◆ EnableSpeculativeLoadHardening

cl::opt<bool> EnableSpeculativeLoadHardening("x86-speculative-load-hardening", cl::desc("Force enable speculative load hardening"), cl::init(false), cl::Hidden)
static

Referenced by hasVulnerableLoad().

◆ false

X86 speculative load false

Definition at line 2643 of file X86SpeculativeLoadHardening.cpp.

◆ FenceCallAndRet

cl::opt<bool> FenceCallAndRet(PASS_KEY "-fence-call-and-ret", cl::desc("Use a full speculation fence to harden both call and ret edges " "rather than a lighter weight mitigation."), cl::init(false), cl::Hidden)
static

Referenced by hasVulnerableLoad(), and isEFLAGSLive().

◆ HardenEdgesWithLFENCE

cl::opt<bool> HardenEdgesWithLFENCE(PASS_KEY "-lfence", cl::desc( "Use LFENCE along each conditional edge to harden against speculative " "loads rather than conditional movs and poisoned pointers."), cl::init(false), cl::Hidden)
static

Referenced by hasVulnerableLoad().

◆ hardener

X86 speculative load hardener

Definition at line 2643 of file X86SpeculativeLoadHardening.cpp.

◆ HardenIndirectCallsAndJumps

cl::opt<bool> HardenIndirectCallsAndJumps(PASS_KEY "-indirect", cl::desc("Harden indirect calls and jumps against using speculatively " "stored attacker controlled addresses. This is designed to " "mitigate Spectre v1.2 style attacks."), cl::init(true), cl::Hidden)
static

Referenced by hasVulnerableLoad(), and isEFLAGSLive().

◆ HardenInterprocedurally

cl::opt<bool> HardenInterprocedurally(PASS_KEY "-ip", cl::desc("Harden interprocedurally by passing our state in and out of " "functions in the high bits of the stack pointer."), cl::init(true), cl::Hidden)
static

Referenced by hasVulnerableLoad(), and isEFLAGSLive().

◆ HardenLoads

cl::opt<bool> HardenLoads(PASS_KEY "-loads", cl::desc("Sanitize loads from memory. When disable, no " "significant security is provided."), cl::init(true), cl::Hidden)
static

Referenced by isEFLAGSLive().

◆ PASS_KEY

PASS_KEY

Definition at line 2643 of file X86SpeculativeLoadHardening.cpp.