[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