mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[X86] Automatically harden inline assembly RET instructions against Load Value Injection (LVI)
Previously, the X86AsmParser would issue a warning whenever a ret instruction is encountered. This patch changes the behavior to automatically transform each ret instruction in an inline assembly stream into: shlq $0, (%rsp) lfence ret which is secure, according to https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions. Patch by Scott Constable with some minor changes by Craig Topper.
This commit is contained in:
parent
1b3f3aebe1
commit
0f96f788ae
@ -938,8 +938,8 @@ private:
|
||||
|
||||
// Load Value Injection (LVI) Mitigations for machine code
|
||||
void emitWarningForSpecialLVIInstruction(SMLoc Loc);
|
||||
bool applyLVICFIMitigation(MCInst &Inst);
|
||||
bool applyLVILoadHardeningMitigation(MCInst &Inst, MCStreamer &Out);
|
||||
void applyLVICFIMitigation(MCInst &Inst, MCStreamer &Out);
|
||||
void applyLVILoadHardeningMitigation(MCInst &Inst, MCStreamer &Out);
|
||||
|
||||
/// Wrapper around MCStreamer::emitInstruction(). Possibly adds
|
||||
/// instrumentation around Inst.
|
||||
@ -3178,7 +3178,7 @@ void X86AsmParser::emitWarningForSpecialLVIInstruction(SMLoc Loc) {
|
||||
/// - https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection
|
||||
///
|
||||
/// Returns `true` if a mitigation was applied or warning was emitted.
|
||||
bool X86AsmParser::applyLVICFIMitigation(MCInst &Inst) {
|
||||
void X86AsmParser::applyLVICFIMitigation(MCInst &Inst, MCStreamer &Out) {
|
||||
// Information on control-flow instructions that require manual mitigation can
|
||||
// be found here:
|
||||
// https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions
|
||||
@ -3188,7 +3188,23 @@ bool X86AsmParser::applyLVICFIMitigation(MCInst &Inst) {
|
||||
case X86::RETQ:
|
||||
case X86::RETIL:
|
||||
case X86::RETIQ:
|
||||
case X86::RETIW:
|
||||
case X86::RETIW: {
|
||||
MCInst ShlInst, FenceInst;
|
||||
bool Parse32 = is32BitMode() || Code16GCC;
|
||||
unsigned Basereg =
|
||||
is64BitMode() ? X86::RSP : (Parse32 ? X86::ESP : X86::SP);
|
||||
const MCExpr *Disp = MCConstantExpr::create(0, getContext());
|
||||
auto ShlMemOp = X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp,
|
||||
/*BaseReg=*/Basereg, /*IndexReg=*/0,
|
||||
/*Scale=*/1, SMLoc{}, SMLoc{}, 0);
|
||||
ShlInst.setOpcode(X86::SHL64mi);
|
||||
ShlMemOp->addMemOperands(ShlInst, 5);
|
||||
ShlInst.addOperand(MCOperand::createImm(0));
|
||||
FenceInst.setOpcode(X86::LFENCE);
|
||||
Out.emitInstruction(ShlInst, getSTI());
|
||||
Out.emitInstruction(FenceInst, getSTI());
|
||||
return;
|
||||
}
|
||||
case X86::JMP16m:
|
||||
case X86::JMP32m:
|
||||
case X86::JMP64m:
|
||||
@ -3196,9 +3212,8 @@ bool X86AsmParser::applyLVICFIMitigation(MCInst &Inst) {
|
||||
case X86::CALL32m:
|
||||
case X86::CALL64m:
|
||||
emitWarningForSpecialLVIInstruction(Inst.getLoc());
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// To mitigate LVI, every instruction that performs a load can be followed by
|
||||
@ -3208,7 +3223,7 @@ bool X86AsmParser::applyLVICFIMitigation(MCInst &Inst) {
|
||||
/// https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection
|
||||
///
|
||||
/// Returns `true` if a mitigation was applied or warning was emitted.
|
||||
bool X86AsmParser::applyLVILoadHardeningMitigation(MCInst &Inst,
|
||||
void X86AsmParser::applyLVILoadHardeningMitigation(MCInst &Inst,
|
||||
MCStreamer &Out) {
|
||||
auto Opcode = Inst.getOpcode();
|
||||
auto Flags = Inst.getFlags();
|
||||
@ -3226,38 +3241,41 @@ bool X86AsmParser::applyLVILoadHardeningMitigation(MCInst &Inst,
|
||||
case X86::SCASL:
|
||||
case X86::SCASQ:
|
||||
emitWarningForSpecialLVIInstruction(Inst.getLoc());
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
} else if (Opcode == X86::REP_PREFIX || Opcode == X86::REPNE_PREFIX) {
|
||||
// If a REP instruction is found on its own line, it may or may not be
|
||||
// followed by a vulnerable instruction. Emit a warning just in case.
|
||||
emitWarningForSpecialLVIInstruction(Inst.getLoc());
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
|
||||
|
||||
// Can't mitigate after terminators or calls. A control flow change may have
|
||||
// already occurred.
|
||||
if (MCID.isTerminator() || MCID.isCall())
|
||||
return;
|
||||
|
||||
// LFENCE has the mayLoad property, don't double fence.
|
||||
if (MCID.mayLoad() && Inst.getOpcode() != X86::LFENCE) {
|
||||
MCInst FenceInst;
|
||||
FenceInst.setOpcode(X86::LFENCE);
|
||||
FenceInst.setLoc(Inst.getLoc());
|
||||
Out.emitInstruction(FenceInst, getSTI());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void X86AsmParser::emitInstruction(MCInst &Inst, OperandVector &Operands,
|
||||
MCStreamer &Out) {
|
||||
if (LVIInlineAsmHardening &&
|
||||
getSTI().getFeatureBits()[X86::FeatureLVIControlFlowIntegrity])
|
||||
applyLVICFIMitigation(Inst, Out);
|
||||
|
||||
Out.emitInstruction(Inst, getSTI());
|
||||
|
||||
if (LVIInlineAsmHardening) {
|
||||
if (getSTI().getFeatureBits()[X86::FeatureLVIControlFlowIntegrity] &&
|
||||
applyLVICFIMitigation(Inst))
|
||||
return;
|
||||
if (getSTI().getFeatureBits()[X86::FeatureLVILoadHardening])
|
||||
applyLVILoadHardeningMitigation(Inst, Out);
|
||||
}
|
||||
if (LVIInlineAsmHardening &&
|
||||
getSTI().getFeatureBits()[X86::FeatureLVILoadHardening])
|
||||
applyLVILoadHardeningMitigation(Inst, Out);
|
||||
}
|
||||
|
||||
bool X86AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
|
@ -5,10 +5,11 @@
|
||||
; Test module-level assembly
|
||||
module asm "pop %rbx"
|
||||
module asm "ret"
|
||||
; WARN: warning: Instruction may be vulnerable to LVI
|
||||
; WARN-NEXT: ret
|
||||
; WARN-NEXT: ^
|
||||
; WARN-NEXT: note: See https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions for more information
|
||||
; X86: popq %rbx
|
||||
; X86-NEXT: lfence
|
||||
; X86-NEXT: shlq $0, (%rsp)
|
||||
; X86-NEXT: lfence
|
||||
; X86-NEXT: retq
|
||||
|
||||
; Function Attrs: noinline nounwind optnone uwtable
|
||||
define dso_local void @test_inline_asm() {
|
||||
@ -106,18 +107,14 @@ entry:
|
||||
; X86: pinsrw $6, (%eax), %xmm0
|
||||
; X86-NEXT: lfence
|
||||
call void asm sideeffect "ret", "~{dirflag},~{fpsr},~{flags}"() #1
|
||||
; WARN: warning: Instruction may be vulnerable to LVI
|
||||
; WARN-NEXT: ret
|
||||
; WARN-NEXT: ^
|
||||
; WARN-NEXT: note: See https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions for more information
|
||||
; X86: retq
|
||||
; X86: shlq $0, (%rsp)
|
||||
; X86-NEXT: lfence
|
||||
; X86-NEXT: retq
|
||||
; X86-NOT: lfence
|
||||
call void asm sideeffect "ret $$8", "~{dirflag},~{fpsr},~{flags}"() #1
|
||||
; WARN: warning: Instruction may be vulnerable to LVI
|
||||
; WARN-NEXT: ret $8
|
||||
; WARN-NEXT: ^
|
||||
; WARN-NEXT: note: See https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions for more information
|
||||
; X86: retq $8
|
||||
; X86: shlq $0, (%rsp)
|
||||
; X86-NEXT: lfence
|
||||
; X86-NEXT: retq $8
|
||||
; X86-NOT: lfence
|
||||
call void asm sideeffect "jmpq *(%rdx)", "~{dirflag},~{fpsr},~{flags}"() #1
|
||||
; WARN: warning: Instruction may be vulnerable to LVI
|
||||
|
Loading…
Reference in New Issue
Block a user