[llvm] 0cbe713 - [X86] Automatically harden inline assembly RET instructions against Load Value Injection (LVI)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 13 15:18:23 PDT 2020
Author: Craig Topper
Date: 2020-06-13T15:16:05-07:00
New Revision: 0cbe713c69f7c12682855ffd61ecb0d7edc262e3
URL: https://github.com/llvm/llvm-project/commit/0cbe713c69f7c12682855ffd61ecb0d7edc262e3
DIFF: https://github.com/llvm/llvm-project/commit/0cbe713c69f7c12682855ffd61ecb0d7edc262e3.diff
LOG: [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.
Added:
Modified:
llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/test/CodeGen/X86/lvi-hardening-inline-asm.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 91edc1a81c3f..a9577e67def3 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -938,8 +938,8 @@ class X86AsmParser : public MCTargetAsmParser {
// 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,
diff --git a/llvm/test/CodeGen/X86/lvi-hardening-inline-asm.ll b/llvm/test/CodeGen/X86/lvi-hardening-inline-asm.ll
index 2b3ba2b30d4b..f88976ec841b 100644
--- a/llvm/test/CodeGen/X86/lvi-hardening-inline-asm.ll
+++ b/llvm/test/CodeGen/X86/lvi-hardening-inline-asm.ll
@@ -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
More information about the llvm-commits
mailing list