87 lines
4 KiB
Text
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);
|
|
}
|