ports/devel/llvm/patches/patch-lib_Target_X86_X86MCInstLower_cpp

87 lines
4 KiB
Text

- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Use int3 trap padding between functions instead of trapsleds with a leading jump.
- Emit variable length trap padding in retguard epilogue.
This adds more trap padding before the return while ensuring that the
return is still in the same cache line.
Index: lib/Target/X86/X86MCInstLower.cpp
--- lib/Target/X86/X86MCInstLower.cpp.orig
+++ lib/Target/X86/X86MCInstLower.cpp
@@ -2570,6 +2570,50 @@ void X86AsmPrinter::emitInstruction(const MachineInstr
MCInstBuilder(X86::MOV64rr).addReg(X86::R10).addReg(X86::RAX));
return;
+ case X86::RETGUARD_JMP_TRAP: {
+ // Make a symbol for the end of the trapsled and emit a jump to it
+ MCSymbol *RGSuccSym = OutContext.createTempSymbol();
+ const MCExpr *RGSuccExpr = MCSymbolRefExpr::create(RGSuccSym, OutContext);
+ EmitAndCountInstruction(MCInstBuilder(X86::JCC_1)
+ .addExpr(RGSuccExpr)
+ .addImm(X86::COND_E));
+
+ // Emit at least two trap instructions
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+
+ // Now .fill up to 0xe byte, so the ret happens on 0xf
+ MCSymbol *Dot = OutContext.createTempSymbol();
+ OutStreamer->emitLabel(Dot);
+ const MCExpr *DotE = MCSymbolRefExpr::create(Dot, OutContext);
+ const MCExpr *BaseE = MCSymbolRefExpr::create(
+ TM.getSymbol(&MF->getFunction()), OutContext);
+ // .fill (0xf - ((DotE - BaseE) & 0xf)), 1, 0xcc
+ const MCExpr *FillE = MCBinaryExpr::createSub(
+ MCConstantExpr::create(0xf, OutContext),
+ MCBinaryExpr::createAnd(
+ MCBinaryExpr::createSub(DotE, BaseE, OutContext),
+ MCConstantExpr::create(0xf, OutContext),
+ OutContext),
+ OutContext);
+ OutStreamer->emitFill(*FillE, 0xCC);
+
+ // And finally emit the jump target symbol
+ OutStreamer->emitLabel(RGSuccSym);
+ return;
+ }
+
+ case X86::JMP_TRAP: {
+ MCSymbol *RGSuccSym = OutContext.createTempSymbol();
+ const MCExpr *RGSuccExpr = MCSymbolRefExpr::create(RGSuccSym, OutContext);
+ EmitAndCountInstruction(MCInstBuilder(X86::JMP_1).addExpr(RGSuccExpr));
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+ OutStreamer->emitValueToAlignment(8, 0xCC, 1);
+ OutStreamer->emitLabel(RGSuccSym);
+ return;
+ }
+
case X86::SEH_PushReg:
case X86::SEH_SaveReg:
case X86::SEH_SaveXMM:
@@ -2628,4 +2672,10 @@ void X86AsmPrinter::emitInstruction(const MachineInstr
}
EmitAndCountInstruction(TmpInst);
+}
+
+/// Emit Trap bytes to the specified power of two alignment
+void X86AsmPrinter::emitTrapToAlignment(Align Alignment) const {
+ if (Alignment == Align(1)) return;
+ OutStreamer->emitValueToAlignment(Alignment.value(), 0xCC, 1);
}