Compare commits

...

2 Commits
lvi ... master

Author SHA1 Message Date
Nolan Leake
130d2c7589 Error if function using indirect jmp touches redzone
The indirect jmp mitigation clobbers the redzone, so
verify that that is harmless.
2020-07-07 14:29:31 -07:00
Nolan Leake
fe8082af97 Comment fix. 2020-05-14 16:23:55 -07:00

View File

@ -13,7 +13,11 @@
//
// The runtime performance impact of this is significant!
//
// NOTE: This pass is incompatible with RetpolineInsertion.
// NOTE: This pass is incompatible with RetpolineInsertion. It is also
// incompatible with ABIs that allow red-zones, due the the
// flags-preserving jmp mitigation clobbering 8 bytes in the red-zone.
// Options are to disable red-zone when compiling the target binary,
// or configure the compilers to never generate memory-indirect jmps.
//===----------------------------------------------------------------------===//
#include "LFenceInsertion.h"
#include "RewriteInstance.h"
@ -78,6 +82,11 @@ LFenceIndirectJumps("lfence-indirect-jumps",
namespace llvm {
namespace bolt {
static void report_redzone_error() {
errs() << "BOLT-ERROR: 'Redzone access in function with indirect jmp mitigation'\n";
exit(1);
}
void LFenceInsertion::runOnFunctions(BinaryContext &BC) {
if (!opts::InsertLFences)
@ -96,6 +105,8 @@ void LFenceInsertion::runOnFunctions(BinaryContext &BC) {
uint32_t LFencedIndirectJmps = 0;
for (auto &It : BC.getBinaryFunctions()) {
auto &Function = It.second;
bool MemIndirectJmp = false;
bool Redzone = false;
// For performance reasons, we may want to skip some functions and
// manually add lfences to them only where absolutely needed.
@ -107,6 +118,19 @@ void LFenceInsertion::runOnFunctions(BinaryContext &BC) {
for (auto It = BB.begin(); It != BB.end(); ++It) {
auto &Inst = *It;
if (MIB.isActualLoad(Inst) && MIB.isBranchOnMem(Inst)) {
IndirectBranchInfo BrInfo(Inst, MIB);
const auto &MemRef = BrInfo.Memory;
if (MemRef.BaseRegNum == MIB.getStackPointer() &&
MemRef.DispValue < 0) {
if (MemIndirectJmp) {
report_redzone_error();
}
Redzone = true;
}
}
if (opts::LFenceConditionalBranches &&
MIB.isConditionalBranch(Inst)) {
// Inserts a lfence before every conditional branch.
@ -171,15 +195,14 @@ void LFenceInsertion::runOnFunctions(BinaryContext &BC) {
// pushq %rdi //Dummy to overwrite later
// pushq %rdi
// leaq 0x18(%rip), %rdi //After the retq
// mov %rax, 8(%rsp) //Overwrite the dummy
// movq %rdi, 8(%rsp) //Overwrite the dummy
// popq %rdi
// lfence
// pushq (%rsi)
// lfence
// lfence //XXX Not needed, according to Intel?
// shlq $0, (%rsp)
// lfence
// retq
IndirectBranchInfo BrInfo(Inst, MIB);
const auto &MemRef = BrInfo.Memory;
auto *Ctx = BC.Ctx.get();
@ -250,10 +273,18 @@ void LFenceInsertion::runOnFunctions(BinaryContext &BC) {
// jmpq *(%rsi)
// gets rewritten to:
// pushq (%rsi)
// lfence
// lfence //XXX Not needed, according to Intel?
// shlq $0, (%rsp)
// lfence
// retq
// Since this mitigation clobbers the redzone, we need to make
// sure that this function never uses it.
if (Redzone) {
report_redzone_error();
}
MemIndirectJmp = true;
IndirectBranchInfo BrInfo(Inst, MIB);
const auto &MemRef = BrInfo.Memory;