forked from OSchip/llvm-project
[x86/SLH] Extract the logic to trace predicate state through calls to
a helper function with a nice overview comment. NFC. This is a preperatory refactoring to implementing another component of mitigation here that was descibed in the design document but hadn't been implemented yet. llvm-svn: 338016
This commit is contained in:
parent
f8823f3ccc
commit
1387159b93
|
@ -207,6 +207,7 @@ private:
|
||||||
DebugLoc Loc);
|
DebugLoc Loc);
|
||||||
unsigned hardenPostLoad(MachineInstr &MI);
|
unsigned hardenPostLoad(MachineInstr &MI);
|
||||||
void hardenReturnInstr(MachineInstr &MI);
|
void hardenReturnInstr(MachineInstr &MI);
|
||||||
|
void tracePredStateThroughCall(MachineInstr &MI);
|
||||||
void hardenIndirectCallOrJumpInstr(
|
void hardenIndirectCallOrJumpInstr(
|
||||||
MachineInstr &MI,
|
MachineInstr &MI,
|
||||||
SmallDenseMap<unsigned, unsigned, 32> &AddrRegToHardenedReg);
|
SmallDenseMap<unsigned, unsigned, 32> &AddrRegToHardenedReg);
|
||||||
|
@ -1588,25 +1589,7 @@ void X86SpeculativeLoadHardeningPass::tracePredStateThroughBlocksAndHarden(
|
||||||
// state into a call and recovering it after the call returns unless this
|
// state into a call and recovering it after the call returns unless this
|
||||||
// is a tail call.
|
// is a tail call.
|
||||||
assert(MI.isCall() && "Should only reach here for calls!");
|
assert(MI.isCall() && "Should only reach here for calls!");
|
||||||
auto InsertPt = MI.getIterator();
|
tracePredStateThroughCall(MI);
|
||||||
DebugLoc Loc = MI.getDebugLoc();
|
|
||||||
|
|
||||||
// First, we transfer the predicate state into the called function by
|
|
||||||
// merging it into the stack pointer. This will kill the current def of
|
|
||||||
// the state.
|
|
||||||
unsigned StateReg = PS->SSA.GetValueAtEndOfBlock(&MBB);
|
|
||||||
mergePredStateIntoSP(MBB, InsertPt, Loc, StateReg);
|
|
||||||
|
|
||||||
// If this call is also a return, it is a tail call and we don't need
|
|
||||||
// anything else to handle it so just continue.
|
|
||||||
if (MI.isReturn())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// We need to step past the call and recover the predicate
|
|
||||||
// state from SP after the return, and make this new state available.
|
|
||||||
++InsertPt;
|
|
||||||
unsigned NewStateReg = extractPredStateFromSP(MBB, InsertPt, Loc);
|
|
||||||
PS->SSA.AddAvailableValue(&MBB, NewStateReg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HardenPostLoad.clear();
|
HardenPostLoad.clear();
|
||||||
|
@ -2148,6 +2131,43 @@ void X86SpeculativeLoadHardeningPass::hardenReturnInstr(MachineInstr &MI) {
|
||||||
mergePredStateIntoSP(MBB, InsertPt, Loc, PS->SSA.GetValueAtEndOfBlock(&MBB));
|
mergePredStateIntoSP(MBB, InsertPt, Loc, PS->SSA.GetValueAtEndOfBlock(&MBB));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trace the predicate state through a call.
|
||||||
|
///
|
||||||
|
/// There are several layers of this needed to handle the full complexity of
|
||||||
|
/// calls.
|
||||||
|
///
|
||||||
|
/// First, we need to send the predicate state into the called function. We do
|
||||||
|
/// this by merging it into the high bits of the stack pointer.
|
||||||
|
///
|
||||||
|
/// For tail calls, this is all we need to do.
|
||||||
|
///
|
||||||
|
/// For calls where we might return to control flow, we further need to extract
|
||||||
|
/// the predicate state built up within that function from the high bits of the
|
||||||
|
/// stack pointer, and make that the newly available predicate state.
|
||||||
|
void X86SpeculativeLoadHardeningPass::tracePredStateThroughCall(
|
||||||
|
MachineInstr &MI) {
|
||||||
|
MachineBasicBlock &MBB = *MI.getParent();
|
||||||
|
auto InsertPt = MI.getIterator();
|
||||||
|
DebugLoc Loc = MI.getDebugLoc();
|
||||||
|
|
||||||
|
// First, we transfer the predicate state into the called function by merging
|
||||||
|
// it into the stack pointer. This will kill the current def of the state.
|
||||||
|
unsigned StateReg = PS->SSA.GetValueAtEndOfBlock(&MBB);
|
||||||
|
mergePredStateIntoSP(MBB, InsertPt, Loc, StateReg);
|
||||||
|
|
||||||
|
// If this call is also a return, it is a tail call and we don't need anything
|
||||||
|
// else to handle it so just continue.
|
||||||
|
// FIXME: We should also handle noreturn calls.
|
||||||
|
if (MI.isReturn())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We need to step past the call and recover the predicate state from SP after
|
||||||
|
// the return, and make this new state available.
|
||||||
|
++InsertPt;
|
||||||
|
unsigned NewStateReg = extractPredStateFromSP(MBB, InsertPt, Loc);
|
||||||
|
PS->SSA.AddAvailableValue(&MBB, NewStateReg);
|
||||||
|
}
|
||||||
|
|
||||||
/// An attacker may speculatively store over a value that is then speculatively
|
/// An attacker may speculatively store over a value that is then speculatively
|
||||||
/// loaded and used as the target of an indirect call or jump instruction. This
|
/// loaded and used as the target of an indirect call or jump instruction. This
|
||||||
/// is called Spectre v1.2 or Bounds Check Bypass Store (BCBS) and is described
|
/// is called Spectre v1.2 or Bounds Check Bypass Store (BCBS) and is described
|
||||||
|
|
Loading…
Reference in New Issue