Merge in a diff from base:
Improve the X86FixupGadgets pass
Merge in a bug fix from upstream:
[MC] Make symbol version errors non-fatal
Index: Makefile
===================================================================
RCS file: /home/cvs/ports/devel/llvm/Makefile,v
retrieving revision 1.213
diff -u -p -u -p -r1.213 Makefile
--- Makefile 20 Feb 2019 00:24:11 -0000 1.213
+++ Makefile 22 Feb 2019 14:33:44 -0000
@@ -20,7 +20,7 @@ PKGSPEC-main = llvm-=${LLVM_V}
PKGNAME-main = llvm-${LLVM_V}
PKGNAME-python = py-llvm-${LLVM_V}
PKGNAME-lldb = lldb-${LLVM_V}
-REVISION-main = 6
+REVISION-main = 7
REVISION-lldb = 0
CATEGORIES = devel
DISTFILES = llvm-${LLVM_V}.src${EXTRACT_SUFX} \
Index: patches/patch-lib_MC_ELFObjectWriter_cpp
===================================================================
RCS file: patches/patch-lib_MC_ELFObjectWriter_cpp
diff -N patches/patch-lib_MC_ELFObjectWriter_cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_MC_ELFObjectWriter_cpp 22 Feb 2019 14:36:33 -0000
@@ -0,0 +1,34 @@
+$OpenBSD$
+
+[MC] Make symbol version errors non-fatal
+
+Index: lib/MC/ELFObjectWriter.cpp
+--- lib/MC/ELFObjectWriter.cpp.orig
++++ lib/MC/ELFObjectWriter.cpp
+@@ -1258,14 +1258,20 @@ void ELFObjectWriter::executePostLayoutBinding(MCAssem
+ if (!Symbol.isUndefined() && !Rest.startswith("@@@"))
+ continue;
+
+- // FIXME: produce a better error message.
++ // FIXME: Get source locations for these errors or diagnose them earlier.
+ if (Symbol.isUndefined() && Rest.startswith("@@") &&
+- !Rest.startswith("@@@"))
+- report_fatal_error("A @@ version cannot be undefined");
++ !Rest.startswith("@@@")) {
++ Asm.getContext().reportError(SMLoc(), "versioned symbol " + AliasName +
++ " must be defined");
++ continue;
++ }
+
+- if (Renames.count(&Symbol) && Renames[&Symbol] != Alias)
+- report_fatal_error(llvm::Twine("Multiple symbol versions defined for ")
+
+- Symbol.getName());
++ if (Renames.count(&Symbol) && Renames[&Symbol] != Alias) {
++ Asm.getContext().reportError(
++ SMLoc(), llvm::Twine("multiple symbol versions defined for ") +
++ Symbol.getName());
++ continue;
++ }
+
+ Renames.insert(std::make_pair(&Symbol, Alias));
+ }
Index: patches/patch-lib_Target_X86_X86FixupGadgets_cpp
===================================================================
RCS file:
/home/cvs/ports/devel/llvm/patches/patch-lib_Target_X86_X86FixupGadgets_cpp,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 patch-lib_Target_X86_X86FixupGadgets_cpp
--- patches/patch-lib_Target_X86_X86FixupGadgets_cpp 28 Jan 2019 06:27:28
-0000 1.2
+++ patches/patch-lib_Target_X86_X86FixupGadgets_cpp 22 Feb 2019 19:20:40
-0000
@@ -1,15 +1,16 @@
$OpenBSD: patch-lib_Target_X86_X86FixupGadgets_cpp,v 1.2 2019/01/28 06:27:28
jca Exp $
-Add a clang pass that identifies potential ROP gadgets and replaces ROP
-friendly instructions with safe alternatives. This initial commit fixes
-3 instruction forms that will lower to include a c3 (return) byte.
-Additional problematic instructions can be fixed incrementally using
-this framework.
+- Add a clang pass that identifies potential ROP gadgets and replaces ROP
+ friendly instructions with safe alternatives. This initial commit fixes
+ 3 instruction forms that will lower to include a c3 (return) byte.
+ Additional problematic instructions can be fixed incrementally using
+ this framework.
+- Improve the X86FixupGadgets pass
Index: lib/Target/X86/X86FixupGadgets.cpp
--- lib/Target/X86/X86FixupGadgets.cpp.orig
+++ lib/Target/X86/X86FixupGadgets.cpp
-@@ -0,0 +1,273 @@
+@@ -0,0 +1,720 @@
+//===-- X86FixupGadgets.cpp - Fixup Instructions that make ROP Gadgets
----===//
+//
+// The LLVM Compiler Infrastructure
@@ -47,10 +48,10 @@ Index: lib/Target/X86/X86FixupGadgets.cp
+
+#define DEBUG_TYPE FIXUPGADGETS_NAME
+
-+// Toggle with cc1 option: -backend-option -x86-fixup-gadgets=<true|false>
++// Toggle with cc1 option: -mllvm -x86-fixup-gadgets=<true|false>
+static cl::opt<bool> FixupGadgets(
-+ "x86-fixup-gadgets",
-+ cl::desc("Replace ROP friendly instructions with alternatives"),
++ "x86-fixup-gadgets", cl::Hidden,
++ cl::desc("Replace ROP friendly instructions with safe alternatives"),
+ cl::init(true));
+
+namespace {
@@ -78,24 +79,33 @@ Index: lib/Target/X86/X86FixupGadgets.cp
+ const X86InstrInfo *TII;
+ const X86RegisterInfo *TRI;
+ bool Is64Bit;
-+ enum InstrType {
-+ NoType = 0,
-+ OneGPRegC3,
-+ TwoGPRegC3,
-+ ThreeGPRegC3,
-+ };
+
-+ /// If an Instr has a ROP friendly construct, return it
-+ InstrType isROPFriendly(MachineInstr &MI) const;
++ struct FixupInfo {
++ unsigned op1;
++ unsigned op2;
++ bool fixup;
++ bool align;
++ };
+
-+ /// Helper functions for various kinds of instructions
-+ bool isOneGPRegC3(MachineInstr &MI) const;
-+ bool isTwoGPRegC3(MachineInstr &MI) const;
-+ bool isThreeGPRegC3(MachineInstr &MI) const;
++ uint8_t getRegNum(const MachineOperand &MO) const;
++ uint8_t getRegNum(unsigned reg) const;
++ struct FixupInfo isROPFriendly(MachineInstr &MI) const;
++ bool isROPFriendlyImm(const MachineOperand &MO) const;
++ bool isROPFriendlyRegPair(const MachineOperand &Dst,
++ const MachineOperand &Src) const;
++ bool isROPFriendlyReg(const MachineOperand &Dst, uint8_t RegOpcode) const;
++ bool badModRM(uint8_t Mod, uint8_t RegOpcode, uint8_t RM) const;
++ void checkSIB(const MachineInstr &MI, unsigned CurOp,
++ struct FixupInfo &info) const;
++ bool needsFixup(struct FixupInfo &fi) const;
++ bool needsAlign(struct FixupInfo &fi) const;
++ unsigned getWidestRegForReg(unsigned reg) const;
++ unsigned getEquivalentRegForReg(unsigned oreg, unsigned nreg) const;
++ bool hasImplicitUseOrDef(const MachineInstr &MI, unsigned Reg1,
++ unsigned Reg2) const;
+
-+ /// Replace ROP friendly instructions with safe alternatives
+ bool fixupInstruction(MachineFunction &MF, MachineBasicBlock &MBB,
-+ MachineInstr &MI, InstrType type);
++ MachineInstr &MI, struct FixupInfo Info);
+};
+char FixupGadgetsPass::ID = 0;
+} // namespace
@@ -104,155 +114,593 @@ Index: lib/Target/X86/X86FixupGadgets.cp
+ return new FixupGadgetsPass();
+}
+
-+bool FixupGadgetsPass::isOneGPRegC3(MachineInstr &MI) const {
-+ MachineOperand &MO = MI.getOperand(0);
-+ return MO.isReg() && MO.getReg() == X86::EBX &&
-+ (MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg;
++uint8_t FixupGadgetsPass::getRegNum(const MachineOperand &MO) const {
++ return TRI->getEncodingValue(MO.getReg()) & 0x7;
+}
+
-+bool FixupGadgetsPass::isTwoGPRegC3(MachineInstr &MI) const {
-+ bool DestSet = false;
-+ bool SrcSet = false;
-+ bool OpcodeSet = false;
-+ MachineOperand &MO0 = MI.getOperand(0);
-+ MachineOperand &MO1 = MI.getOperand(1);
-+ if (!(MO0.isReg() && MO1.isReg()))
-+ return false;
++uint8_t FixupGadgetsPass::getRegNum(unsigned reg) const {
++ return TRI->getEncodingValue(reg) & 0x7;
++}
++
++bool FixupGadgetsPass::isROPFriendlyImm(const MachineOperand &MO) const {
++ int64_t imm = MO.getImm();
++ for (int i = 0; i < 8; ++i) {
++ uint8_t byte = (imm & 0xff);
++ if (byte == 0xc2 || byte == 0xc3 || byte == 0xca || byte == 0xcb) {
++ return true;
++ }
++ imm = imm >> 8;
++ }
++ return false;
++}
+
-+ unsigned dstReg = MO0.getReg();
-+ if (dstReg == X86::RBX || dstReg == X86::EBX || dstReg == X86::BX ||
-+ dstReg == X86::BL)
-+ DestSet = true;
++bool FixupGadgetsPass::isROPFriendlyRegPair(const MachineOperand &Dst,
++ const MachineOperand &Src) const {
+
-+ if (!DestSet)
-+ return false;
++ if (!Dst.isReg() || !Src.isReg())
++ llvm_unreachable("Testing non registers for bad reg pair!");
+
-+ unsigned srcReg = MO1.getReg();
-+ if (srcReg == X86::RAX || srcReg == X86::EAX || srcReg == X86::AX ||
-+ srcReg == X86::AL)
-+ SrcSet = true;
++ uint8_t Mod = 3;
++ uint8_t RegOpcode = getRegNum(Src);
++ uint8_t RM = getRegNum(Dst);
++ return badModRM(Mod, RegOpcode, RM);
++}
+
-+ if (!SrcSet)
-+ return false;
++bool FixupGadgetsPass::isROPFriendlyReg(const MachineOperand &Dst, uint8_t
RegOpcode) const {
+
-+ if ((MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg)
-+ OpcodeSet = true;
++ if (!Dst.isReg())
++ llvm_unreachable("Testing non register for bad reg!");
+
-+ return DestSet && SrcSet && OpcodeSet;
++ uint8_t Mod = 3;
++ uint8_t RM = getRegNum(Dst);
++ return badModRM(Mod, RegOpcode, RM);
+}
+
-+bool FixupGadgetsPass::isThreeGPRegC3(MachineInstr &MI) const {
-+ bool DestSet = false;
-+ bool SrcSet = false;
-+ bool OpcodeSet = false;
-+
-+ MachineOperand &MO0 = MI.getOperand(0);
-+ MachineOperand &MO1 = MI.getOperand(1);
-+ MachineOperand &MO2 = MI.getOperand(2);
-+ if (!(MO0.isReg() && MO1.isReg() && MO2.isReg() &&
-+ MO0.getReg() == MO1.getReg()))
-+ return false;
++bool FixupGadgetsPass::badModRM(uint8_t Mod, uint8_t RegOpcode,
++ uint8_t RM) const {
++ uint8_t ModRM = ((Mod << 6) | (RegOpcode << 3) | RM);
++ if (ModRM == 0xc2 || ModRM == 0xc3 || ModRM == 0xca || ModRM == 0xcb)
++ return true;
++ return false;
++}
+
-+ unsigned dstReg = MO0.getReg();
-+ if (dstReg == X86::RBX || dstReg == X86::EBX || dstReg == X86::BX ||
-+ dstReg == X86::BL)
-+ DestSet = true;
++void FixupGadgetsPass::checkSIB(const MachineInstr &MI, unsigned CurOp,
++ struct FixupInfo &info) const {
+
-+ if (!DestSet)
-+ return false;
++ const MachineOperand &Base = MI.getOperand(CurOp + X86::AddrBaseReg);
++ const MachineOperand &Scale = MI.getOperand(CurOp + X86::AddrScaleAmt);
++ const MachineOperand &Index = MI.getOperand(CurOp + X86::AddrIndexReg);
++
++ if (!Scale.isImm() || !Base.isReg() || !Index.isReg())
++ llvm_unreachable("Wrong type operands");
++
++ if (Scale.getImm() != 8 || Base.getReg() == 0 || Index.getReg() == 0)
++ return;
++
++ if (badModRM(3, getRegNum(Index), getRegNum(Base))) {
++ info.op1 = CurOp + X86::AddrBaseReg;
++ info.op2 = CurOp + X86::AddrIndexReg;
++ info.fixup = true;
++ }
++}
+
-+ unsigned srcReg = MO2.getReg();
-+ if (srcReg == X86::RAX || srcReg == X86::EAX || srcReg == X86::AX ||
-+ srcReg == X86::AL)
-+ SrcSet = true;
++struct FixupGadgetsPass::FixupInfo
++FixupGadgetsPass::isROPFriendly(MachineInstr &MI) const {
+
-+ if (!SrcSet)
-+ return false;
++ const MCInstrDesc &Desc = MI.getDesc();
++ unsigned CurOp = X86II::getOperandBias(Desc);
++ uint64_t TSFlags = Desc.TSFlags;
++ uint64_t Form = TSFlags & X86II::FormMask;
++ bool HasVEX_4V = TSFlags & X86II::VEX_4V;
++ bool HasEVEX_K = TSFlags & X86II::EVEX_K;
++
++ struct FixupInfo info = {0, 0, false, false};
++
++ // Look for constants with c3 in them
++ for (const auto &MO : MI.operands()) {
++ if (MO.isImm() && isROPFriendlyImm(MO)) {
++ info.align = true;
++ break;
++ }
++ }
+
-+ if ((MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg)
-+ OpcodeSet = true;
++ switch (Form) {
++ case X86II::Pseudo: {
++ // Pesudos that are replaced with real instructions later
++ switch (MI.getOpcode()) {
++ case X86::ADD64rr_DB:
++ case X86::ADD32rr_DB:
++ case X86::ADD16rr_DB:
++ goto Handle_MRMDestReg;
++ case X86::ACQUIRE_MOV8rm:
++ case X86::ACQUIRE_MOV16rm:
++ case X86::ACQUIRE_MOV32rm:
++ case X86::ACQUIRE_MOV64rm:
++ goto Handle_MRMSrcMem;
++ case X86::RELEASE_MOV8mr:
++ case X86::RELEASE_MOV16mr:
++ case X86::RELEASE_MOV32mr:
++ case X86::RELEASE_MOV64mr:
++ case X86::RELEASE_ADD8mr:
++ case X86::RELEASE_ADD32mr:
++ case X86::RELEASE_ADD64mr:
++ case X86::RELEASE_AND8mr:
++ case X86::RELEASE_AND32mr:
++ case X86::RELEASE_AND64mr:
++ case X86::RELEASE_OR8mr:
++ case X86::RELEASE_OR32mr:
++ case X86::RELEASE_OR64mr:
++ case X86::RELEASE_XOR8mr:
++ case X86::RELEASE_XOR32mr:
++ case X86::RELEASE_XOR64mr:
++ goto Handle_MRMDestMem;
++ case X86::RELEASE_MOV8mi:
++ case X86::RELEASE_MOV16mi:
++ case X86::RELEASE_MOV32mi:
++ case X86::RELEASE_ADD8mi:
++ case X86::RELEASE_MOV64mi32:
++ case X86::RELEASE_ADD32mi:
++ case X86::RELEASE_ADD64mi32:
++ case X86::RELEASE_AND8mi:
++ case X86::RELEASE_AND32mi:
++ case X86::RELEASE_AND64mi32:
++ case X86::RELEASE_OR8mi:
++ case X86::RELEASE_OR32mi:
++ case X86::RELEASE_OR64mi32:
++ case X86::RELEASE_XOR8mi:
++ case X86::RELEASE_XOR32mi:
++ case X86::RELEASE_XOR64mi32:
++ case X86::RELEASE_INC8m:
++ case X86::RELEASE_INC16m:
++ case X86::RELEASE_INC32m:
++ case X86::RELEASE_INC64m:
++ case X86::RELEASE_DEC8m:
++ case X86::RELEASE_DEC16m:
++ case X86::RELEASE_DEC32m:
++ case X86::RELEASE_DEC64m:
++ goto Handle_MRMXm;
++ case X86::ADD16ri_DB:
++ case X86::ADD32ri_DB:
++ case X86::ADD64ri32_DB:
++ case X86::ADD16ri8_DB:
++ case X86::ADD32ri8_DB:
++ case X86::ADD64ri8_DB:
++ goto Handle_MRMXr;
++ default:
++ break;
++ }
++ break;
++ }
++ case X86II::AddRegFrm: {
++ uint8_t BaseOpcode = X86II::getBaseOpcodeFor(TSFlags);
++ uint8_t Opcode = BaseOpcode + getRegNum(MI.getOperand(CurOp));
++ if (Opcode == 0xc2 || Opcode == 0xc3 || Opcode == 0xca || Opcode == 0xcb)
{
++ info.op1 = CurOp;
++ info.fixup = true;
++ }
++ break;
++ }
++ case X86II::MRMDestMem: {
++ Handle_MRMDestMem:
++ checkSIB(MI, CurOp, info);
++ unsigned opcode = MI.getOpcode();
++ if (opcode == X86::MOVNTImr || opcode == X86::MOVNTI_64mr)
++ info.align = true;
++ break;
++ }
++ case X86II::MRMSrcMem: {
++ Handle_MRMSrcMem:
++ CurOp += 1;
++ if (HasVEX_4V)
++ CurOp += 1;
++ if (HasEVEX_K)
++ CurOp += 1;
++ checkSIB(MI, CurOp, info);
++ break;
++ }
++ case X86II::MRMSrcMem4VOp3: {
++ CurOp += 1;
++ checkSIB(MI, CurOp, info);
++ break;
++ }
++ case X86II::MRMSrcMemOp4: {
++ CurOp += 3;
++ checkSIB(MI, CurOp, info);
++ break;
++ }
++ case X86II::MRMXm:
++ case X86II::MRM0m:
++ case X86II::MRM1m:
++ case X86II::MRM2m:
++ case X86II::MRM3m:
++ case X86II::MRM4m:
++ case X86II::MRM5m:
++ case X86II::MRM6m:
++ case X86II::MRM7m: {
++ Handle_MRMXm:
++ if (HasVEX_4V)
++ CurOp += 1;
++ if (HasEVEX_K)
++ CurOp += 1;
++ checkSIB(MI, CurOp, info);
++ break;
++ }
++ case X86II::MRMDestReg: {
++ Handle_MRMDestReg:
++ const MachineOperand &DstReg = MI.getOperand(CurOp);
++ info.op1 = CurOp;
++ CurOp += 1;
++ if (HasVEX_4V)
++ CurOp += 1;
++ if (HasEVEX_K)
++ CurOp += 1;
++ const MachineOperand &SrcReg = MI.getOperand(CurOp);
++ info.op2 = CurOp;
++ if (isROPFriendlyRegPair(DstReg, SrcReg))
++ info.fixup = true;
++ break;
++ }
++ case X86II::MRMSrcReg: {
++ const MachineOperand &DstReg = MI.getOperand(CurOp);
++ info.op1 = CurOp;
++ CurOp += 1;
++ if (HasVEX_4V)
++ CurOp += 1;
++ if (HasEVEX_K)
++ CurOp += 1;
++ const MachineOperand &SrcReg = MI.getOperand(CurOp);
++ info.op2 = CurOp;
++ if (isROPFriendlyRegPair(SrcReg, DstReg))
++ info.fixup = true;
++ break;
++ }
++ case X86II::MRMSrcReg4VOp3: {
++ const MachineOperand &DstReg = MI.getOperand(CurOp);
++ info.op1 = CurOp;
++ CurOp += 1;
++ const MachineOperand &SrcReg = MI.getOperand(CurOp);
++ info.op2 = CurOp;
++ if (isROPFriendlyRegPair(SrcReg, DstReg))
++ info.fixup = true;
++ break;
++ }
++ case X86II::MRMSrcRegOp4: {
++ const MachineOperand &DstReg = MI.getOperand(CurOp);
++ info.op1 = CurOp;
++ CurOp += 3;
++ const MachineOperand &SrcReg = MI.getOperand(CurOp);
++ info.op2 = CurOp;
++ if (isROPFriendlyRegPair(SrcReg, DstReg))
++ info.fixup = true;
++ break;
++ }
++ case X86II::MRMXr:
++ case X86II::MRM0r:
++ case X86II::MRM1r: {
++Handle_MRMXr:
++ if (HasVEX_4V)
++ CurOp += 1;
++ if (HasEVEX_K)
++ CurOp += 1;
++ const MachineOperand &DstReg = MI.getOperand(CurOp);
++ info.op1 = CurOp;
++ if (isROPFriendlyReg(DstReg, Form == X86II::MRM1r ? 1 : 0))
++ info.fixup = true;
++ break;
++ }
++ case X86II::MRM_C2:
++ case X86II::MRM_C3:
++ case X86II::MRM_CA:
++ case X86II::MRM_CB: {
++ info.align = true;
++ break;
++ }
++ default:
++ break;
++ }
++ return info;
++}
+
-+ return DestSet && SrcSet && OpcodeSet;
++bool FixupGadgetsPass::needsFixup(struct FixupInfo &fi) const {
++ return (fi.fixup == true);
+}
+
-+FixupGadgetsPass::InstrType
-+FixupGadgetsPass::isROPFriendly(MachineInstr &MI) const {
-+ switch (MI.getNumExplicitOperands()) {
-+ case 1:
-+ return isOneGPRegC3(MI) ? OneGPRegC3 : NoType;
-+ case 2:
-+ return isTwoGPRegC3(MI) ? TwoGPRegC3 : NoType;
-+ case 3:
-+ return isThreeGPRegC3(MI) ? ThreeGPRegC3 : NoType;
++bool FixupGadgetsPass::needsAlign(struct FixupInfo &fi) const {
++ return (fi.align == true);
++}
++
++unsigned FixupGadgetsPass::getWidestRegForReg(unsigned reg) const {
++
++ switch (reg) {
++ case X86::AL:
++ case X86::AH:
++ case X86::AX:
++ case X86::EAX:
++ case X86::RAX:
++ return Is64Bit ? X86::RAX : X86::EAX;
++ case X86::BL:
++ case X86::BH:
++ case X86::BX:
++ case X86::EBX:
++ case X86::RBX:
++ return Is64Bit ? X86::RBX : X86::EBX;
++ case X86::CL:
++ case X86::CH:
++ case X86::CX:
++ case X86::ECX:
++ case X86::RCX:
++ return Is64Bit ? X86::RCX : X86::ECX;
++ case X86::DL:
++ case X86::DH:
++ case X86::DX:
++ case X86::EDX:
++ case X86::RDX:
++ return Is64Bit ? X86::RDX : X86::EDX;
++ case X86::R8B:
++ case X86::R8W:
++ case X86::R8D:
++ case X86::R8:
++ return X86::R8;
++ case X86::R9B:
++ case X86::R9W:
++ case X86::R9D:
++ case X86::R9:
++ return X86::R9;
++ case X86::R10B:
++ case X86::R10W:
++ case X86::R10D:
++ case X86::R10:
++ return X86::R10;
++ case X86::R11B:
++ case X86::R11W:
++ case X86::R11D:
++ case X86::R11:
++ return X86::R11;
++ default:
++ return X86::NoRegister; // Non-GP Reg
++ }
++ return 0;
++}
++
++// For given register oreg return the equivalent size register
++// from the nreg register set. Eg. For oreg ebx and nreg ax, return eax.
++unsigned FixupGadgetsPass::getEquivalentRegForReg(unsigned oreg,
++ unsigned nreg) const {
++ unsigned compreg = getWidestRegForReg(nreg);
++
++ switch (oreg) {
++ case X86::AL:
++ case X86::BL:
++ case X86::CL:
++ case X86::DL:
++ case X86::R8B:
++ case X86::R9B:
++ case X86::R10B:
++ case X86::R11B:
++ switch (compreg) {
++ case X86::EAX:
++ case X86::RAX:
++ return X86::AL;
++ case X86::EBX:
++ case X86::RBX:
++ return X86::BL;
++ case X86::ECX:
++ case X86::RCX:
++ return X86::CL;
++ case X86::EDX:
++ case X86::RDX:
++ return X86::DL;
++ case X86::R8:
++ return X86::R8B;
++ case X86::R9:
++ return X86::R9B;
++ case X86::R10:
++ return X86::R10B;
++ case X86::R11:
++ return X86::R11B;
++ default:
++ llvm_unreachable("Unknown 8 bit register");
++ }
++ break;
++ case X86::AH:
++ case X86::BH:
++ case X86::CH:
++ case X86::DH:
++ switch (compreg) {
++ case X86::EAX:
++ return X86::AH;
++ case X86::EBX:
++ return X86::BH;
++ case X86::ECX:
++ return X86::CH;
++ case X86::EDX:
++ return X86::DH;
++ default:
++ llvm_unreachable("Using H registers in REX mode");
++ }
++ break;
++ case X86::AX:
++ case X86::BX:
++ case X86::CX:
++ case X86::DX:
++ case X86::R8W:
++ case X86::R9W:
++ case X86::R10W:
++ case X86::R11W:
++ switch (compreg) {
++ case X86::EAX:
++ case X86::RAX:
++ return X86::AX;
++ case X86::EBX:
++ case X86::RBX:
++ return X86::BX;
++ case X86::ECX:
++ case X86::RCX:
++ return X86::CX;
++ case X86::EDX:
++ case X86::RDX:
++ return X86::DX;
++ case X86::R8:
++ return X86::R8W;
++ case X86::R9:
++ return X86::R9W;
++ case X86::R10:
++ return X86::R10W;
++ case X86::R11:
++ return X86::R11W;
++ default:
++ llvm_unreachable("Unknown 16 bit register");
++ }
++ break;
++ case X86::EAX:
++ case X86::EBX:
++ case X86::ECX:
++ case X86::EDX:
++ case X86::R8D:
++ case X86::R9D:
++ case X86::R10D:
++ case X86::R11D:
++ switch (compreg) {
++ case X86::EAX:
++ case X86::RAX:
++ return X86::EAX;
++ case X86::EBX:
++ case X86::RBX:
++ return X86::EBX;
++ case X86::ECX:
++ case X86::RCX:
++ return X86::ECX;
++ case X86::EDX:
++ case X86::RDX:
++ return X86::EDX;
++ case X86::R8:
++ return X86::R8D;
++ case X86::R9:
++ return X86::R9D;
++ case X86::R10:
++ return X86::R10D;
++ case X86::R11:
++ return X86::R11D;
++ default:
++ llvm_unreachable("Unknown 32 bit register");
++ }
++ break;
++ case X86::RAX:
++ case X86::RBX:
++ case X86::RCX:
++ case X86::RDX:
++ case X86::R8:
++ case X86::R9:
++ case X86::R10:
++ case X86::R11:
++ return compreg;
++ default:
++ llvm_unreachable("Unknown input register!");
+ }
-+ return NoType;
++}
++
++bool FixupGadgetsPass::hasImplicitUseOrDef(const MachineInstr &MI,
++ unsigned Reg1, unsigned Reg2)
const {
++
++ const MCInstrDesc &Desc = MI.getDesc();
++
++ const MCPhysReg *ImpDefs = Desc.getImplicitDefs();
++ if (ImpDefs) {
++ for (; *ImpDefs; ++ImpDefs) {
++ unsigned w = getWidestRegForReg(*ImpDefs);
++ if (w == Reg1 || w == Reg2) {
++ return true;
++ }
++ }
++ }
++
++ const MCPhysReg *ImpUses = Desc.getImplicitUses();
++ if (ImpUses) {
++ for (; *ImpUses; ++ImpUses) {
++ unsigned w = getWidestRegForReg(*ImpUses);
++ if (w == Reg1 || w == Reg2) {
++ return true;
++ }
++ }
++ }
++ return false;
+}
+
+bool FixupGadgetsPass::fixupInstruction(MachineFunction &MF,
+ MachineBasicBlock &MBB,
-+ MachineInstr &MI, InstrType type) {
++ MachineInstr &MI, FixupInfo Info) {
+
-+ if (type == NoType)
++ if (!needsAlign(Info) && !needsFixup(Info))
+ return false;
+
-+ MachineOperand *MO0, *MO1, *MO2;
+ DebugLoc DL = MI.getDebugLoc();
++
++ // Check for only needs alignment
++ if (needsAlign(Info) && !needsFixup(Info)) {
++ BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
++ return true;
++ }
++
+ unsigned XCHG = Is64Bit ? X86::XCHG64rr : X86::XCHG32rr;
-+ unsigned SREG = Is64Bit ? X86::RAX : X86::EAX;
-+ unsigned DREG = Is64Bit ? X86::RBX : X86::EBX;
-+ unsigned tmpReg;
++
++ unsigned OrigReg1 = MI.getOperand(Info.op1).getReg();
++ // Swap with RAX/EAX unless we have a second register to swap with
++ unsigned OrigReg2 = Is64Bit ? X86::RAX : X86::EAX;
++ if (Info.op2)
++ OrigReg2 = MI.getOperand(Info.op2).getReg();
++
++ unsigned SwapReg1 = getWidestRegForReg(OrigReg1);
++ unsigned SwapReg2 = getWidestRegForReg(OrigReg2);
++ unsigned CompReg1 = SwapReg1;
++ unsigned CompReg2 = SwapReg2;
++
++ // Just align if:
++ // - we have a non-GP reg to swap with
++ // - the instruction implicitly uses one of the registers we are swapping
++ // - if we are fixing an instruction that skips the xchg back
++ if (SwapReg1 == X86::NoRegister || SwapReg2 == X86::NoRegister ||
++ hasImplicitUseOrDef(MI, CompReg1, CompReg2) || MI.isCall() ||
++ MI.isReturn() || MI.isBranch() || MI.isIndirectBranch() ||
++ MI.isBarrier()) {
++ BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
++ return true;
++ }
++
++ // Make sure our XCHG doesn't make a gadget
++ if (badModRM(3, getRegNum(SwapReg1), getRegNum(SwapReg2))) {
++ unsigned treg = SwapReg1;
++ SwapReg1 = SwapReg2;
++ SwapReg2 = treg;
++ }
+
+ // Swap the two registers to start
+ BuildMI(MBB, MI, DL, TII->get(XCHG))
-+ .addReg(DREG, RegState::Define)
-+ .addReg(SREG, RegState::Define)
-+ .addReg(DREG).addReg(SREG);
-+
-+ switch (type) {
-+ case OneGPRegC3:
-+ MO0 = &MI.getOperand(0);
-+ switch (MO0->getReg()) {
-+ case X86::RBX:
-+ tmpReg = X86::RAX;
-+ break;
-+ case X86::EBX:
-+ tmpReg = X86::EAX;
-+ break;
-+ case X86::BX:
-+ tmpReg = X86::AX;
-+ break;
-+ case X86::BL:
-+ tmpReg = X86::AL;
-+ break;
-+ default:
-+ llvm_unreachable("Unknown DestReg in OneGPRegC3 fixup");
-+ }
-+ BuildMI(MBB, MI, DL, MI.getDesc(), tmpReg);
-+ break;
-+ case TwoGPRegC3:
-+ MO0 = &MI.getOperand(0);
-+ MO1 = &MI.getOperand(1);
-+ BuildMI(MBB, MI, DL, MI.getDesc(), MO1->getReg()).addReg(MO0->getReg());
-+ break;
-+ case ThreeGPRegC3:
-+ // Swap args around and set new dest reg
-+ MO0 = &MI.getOperand(0); // Destination
-+ MO2 = &MI.getOperand(2); // Source 2 == Other
-+ BuildMI(MBB, MI, DL, MI.getDesc(), MO2->getReg())
-+ .addReg(MO2->getReg())
-+ .addReg(MO0->getReg());
-+ break;
-+ default:
-+ llvm_unreachable("Unknown FixupGadgets Instruction Type");
++ .addReg(SwapReg1, RegState::Define)
++ .addReg(SwapReg2, RegState::Define)
++ .addReg(SwapReg1).addReg(SwapReg2);
++
++ // Check for needs alignment
++ if (needsAlign(Info))
++ BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
++
++ // Swap the registers inside the instruction
++ for (MachineOperand &MO : MI.operands()) {
++ if (!MO.isReg())
++ continue;
++
++ unsigned reg = MO.getReg();
++ unsigned match = getWidestRegForReg(reg);
++ if (match == CompReg1)
++ MO.setReg(getEquivalentRegForReg(reg, OrigReg2));
++ else if (match == CompReg2)
++ MO.setReg(getEquivalentRegForReg(reg, OrigReg1));
+ }
+
-+ // And swap them back to finish
-+ BuildMI(MBB, MI, DL, TII->get(XCHG))
-+ .addReg(DREG, RegState::Define)
-+ .addReg(SREG, RegState::Define)
-+ .addReg(DREG).addReg(SREG);
-+ // Erase original instruction
-+ MI.eraseFromParent();
++ // And swap the two registers back
++ BuildMI(MBB, ++MachineBasicBlock::instr_iterator(MI), DL, TII->get(XCHG))
++ .addReg(SwapReg1, RegState::Define)
++ .addReg(SwapReg2, RegState::Define)
++ .addReg(SwapReg1).addReg(SwapReg2);
+
+ return true;
+}
@@ -265,17 +713,17 @@ Index: lib/Target/X86/X86FixupGadgets.cp
+ TII = STI->getInstrInfo();
+ TRI = STI->getRegisterInfo();
+ Is64Bit = STI->is64Bit();
-+ std::vector<std::pair<MachineInstr *, InstrType>> fixups;
-+ InstrType type;
++ std::vector<std::pair<MachineInstr *, FixupInfo>> fixups;
++ FixupInfo info;
+
+ bool modified = false;
+
+ for (auto &MBB : MF) {
+ fixups.clear();
+ for (auto &MI : MBB) {
-+ type = isROPFriendly(MI);
-+ if (type != NoType)
-+ fixups.push_back(std::make_pair(&MI, type));
++ info = isROPFriendly(MI);
++ if (needsAlign(info) || needsFixup(info))
++ fixups.push_back(std::make_pair(&MI, info));
+ }
+ for (auto &fixup : fixups)
+ modified |= fixupInstruction(MF, MBB, *fixup.first, fixup.second);
Index: patches/patch-lib_Target_X86_X86InstrCompiler_td
===================================================================
RCS file:
/home/cvs/ports/devel/llvm/patches/patch-lib_Target_X86_X86InstrCompiler_td,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 patch-lib_Target_X86_X86InstrCompiler_td
--- patches/patch-lib_Target_X86_X86InstrCompiler_td 6 Jul 2018 06:55:10
-0000 1.1
+++ patches/patch-lib_Target_X86_X86InstrCompiler_td 22 Feb 2019 19:22:37
-0000
@@ -1,27 +1,28 @@
$OpenBSD: patch-lib_Target_X86_X86InstrCompiler_td,v 1.1 2018/07/06 06:55:10
ajacoutot Exp $
-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.
+- 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.
+- Improve the X86FixupGadgets pass
Index: lib/Target/X86/X86InstrCompiler.td
--- lib/Target/X86/X86InstrCompiler.td.orig
+++ lib/Target/X86/X86InstrCompiler.td
-@@ -267,6 +267,21 @@ def MORESTACK_RET_RESTORE_R10 : I<0, Pseudo, (outs), (
+@@ -267,6 +267,25 @@ def MORESTACK_RET_RESTORE_R10 : I<0, Pseudo, (outs), (
}
//===----------------------------------------------------------------------===//
@@ -37,6 +38,10 @@ Index: lib/Target/X86/X86InstrCompiler.t
+// the return value (ie mov %ecx, %eax instead of mov %cl, %al).
+let isCodeGenOnly = 1, Uses = [EFLAGS] in {
+def RETGUARD_JMP_TRAP: I<0, Pseudo, (outs), (ins), "", []>;
++}
++
++let isCodeGenOnly = 1 in {
++def JMP_TRAP: I<0, Pseudo, (outs), (ins), "", []>;
+}
+
+//===----------------------------------------------------------------------===//
Index: patches/patch-lib_Target_X86_X86MCInstLower_cpp
===================================================================
RCS file:
/home/cvs/ports/devel/llvm/patches/patch-lib_Target_X86_X86MCInstLower_cpp,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 patch-lib_Target_X86_X86MCInstLower_cpp
--- patches/patch-lib_Target_X86_X86MCInstLower_cpp 28 Jan 2019 06:27:28
-0000 1.5
+++ patches/patch-lib_Target_X86_X86MCInstLower_cpp 22 Feb 2019 19:12:52
-0000
@@ -22,7 +22,7 @@ $OpenBSD: patch-lib_Target_X86_X86MCInst
Index: lib/Target/X86/X86MCInstLower.cpp
--- lib/Target/X86/X86MCInstLower.cpp.orig
+++ lib/Target/X86/X86MCInstLower.cpp
-@@ -1831,6 +1831,16 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
+@@ -1831,6 +1831,27 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
MCInstBuilder(X86::MOV64rr).addReg(X86::R10).addReg(X86::RAX));
return;
@@ -36,10 +36,21 @@ Index: lib/Target/X86/X86MCInstLower.cpp
+ 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:
-@@ -2257,4 +2267,10 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
+@@ -2257,4 +2278,10 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr
}
EmitAndCountInstruction(TmpInst);
Index: patches/patch-tools_clang_include_clang_Driver_Options_td
===================================================================
RCS file:
/home/cvs/ports/devel/llvm/patches/patch-tools_clang_include_clang_Driver_Options_td,v
retrieving revision 1.17
diff -u -p -u -p -r1.17 patch-tools_clang_include_clang_Driver_Options_td
--- patches/patch-tools_clang_include_clang_Driver_Options_td 11 Feb 2019
05:24:16 -0000 1.17
+++ patches/patch-tools_clang_include_clang_Driver_Options_td 22 Feb 2019
19:24:34 -0000
@@ -1,13 +1,14 @@
$OpenBSD: patch-tools_clang_include_clang_Driver_Options_td,v 1.17 2019/02/11
05:24:16 jca Exp $
- Add ret protctor options as no-ops.
+- Improve the X86FixupGadgets pass
- Alias the command line parameter -p to -pg.
- implement -msave-args in clang/llvm, like the sun did for gcc
Index: tools/clang/include/clang/Driver/Options.td
--- tools/clang/include/clang/Driver/Options.td.orig
+++ tools/clang/include/clang/Driver/Options.td
-@@ -1595,6 +1595,10 @@ def fstack_protector_strong : Flag<["-"], "fstack-prot
+@@ -1595,6 +1595,14 @@ def fstack_protector_strong : Flag<["-"], "fstack-prot
HelpText<"Use a strong heuristic to apply stack protectors to functions">;
def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>,
HelpText<"Enable stack protectors for functions potentially vulnerable to
stack smashing">;
@@ -15,10 +16,14 @@ Index: tools/clang/include/clang/Driver/
+ HelpText<"Disable return protector">;
+def fret_protector : Flag<["-"], "fret-protector">, Group<f_Group>,
+ HelpText<"Enable return protector">;
++def fno_fixup_gadgets : Flag<["-"], "fno-fixup-gadgets">, Group<f_Group>,
++ HelpText<"Disable FixupGadgets pass (x86 only)">;
++def ffixup_gadgets : Flag<["-"], "ffixup-gadgets">, Group<f_Group>,
++ HelpText<"Replace ROP friendly instructions with safe alternatives (x86
only)">;
def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>,
Flags<[CoreOption]>,
HelpText<"Emit full debug info for all types used by the program">;
def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">,
Group<f_Group>, Flags<[CoreOption]>,
-@@ -2359,7 +2363,7 @@ def pthreads : Flag<["-"], "pthreads">;
+@@ -2359,7 +2367,7 @@ def pthreads : Flag<["-"], "pthreads">;
def pthread : Flag<["-"], "pthread">, Flags<[CC1Option]>,
HelpText<"Support POSIX threads in generated code">;
def no_pthread : Flag<["-"], "no-pthread">, Flags<[CC1Option]>;
@@ -27,7 +32,7 @@ Index: tools/clang/include/clang/Driver/
def pie : Flag<["-"], "pie">;
def read__only__relocs : Separate<["-"], "read_only_relocs">;
def remap : Flag<["-"], "remap">;
-@@ -2810,6 +2814,8 @@ def mretpoline : Flag<["-"], "mretpoline">, Group<m_x8
+@@ -2810,6 +2818,8 @@ def mretpoline : Flag<["-"], "mretpoline">, Group<m_x8
def mno_retpoline : Flag<["-"], "mno-retpoline">, Group<m_x86_Features_Group>;
def mretpoline_external_thunk : Flag<["-"], "mretpoline-external-thunk">,
Group<m_x86_Features_Group>;
def mno_retpoline_external_thunk : Flag<["-"],
"mno-retpoline-external-thunk">, Group<m_x86_Features_Group>;
Index: patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp
===================================================================
RCS file:
/home/cvs/ports/devel/llvm/patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp,v
retrieving revision 1.7
diff -u -p -u -p -r1.7 patch-tools_clang_lib_Driver_ToolChains_Clang_cpp
--- patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp 28 Jan 2019
06:27:28 -0000 1.7
+++ patches/patch-tools_clang_lib_Driver_ToolChains_Clang_cpp 22 Feb 2019
19:28:40 -0000
@@ -22,6 +22,7 @@ $OpenBSD: patch-tools_clang_lib_Driver_T
jumping into the instruction stream partway through other instructions. Work
to
remove these gadgets will continue through other mechanisms.
- Add retguard for arm64.
+- Improve the X86FixupGadgets pass
- On OpenBSD disable the malloc/calloc/realloc/free/str*dup builtins, since
they can perform strange transforms and optimizations. Some of those could
gain a slight advantage, but would avoid the variety of important runtime
@@ -65,7 +66,7 @@ Index: tools/clang/lib/Driver/ToolChains
if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
options::OPT_fno_reroll_loops))
-@@ -4101,6 +4105,24 @@ void Clang::ConstructJob(Compilation &C, const JobActi
+@@ -4101,6 +4105,34 @@ void Clang::ConstructJob(Compilation &C, const JobActi
RenderSSPOptions(getToolChain(), Args, CmdArgs, KernelOrKext);
@@ -87,10 +88,20 @@ Index: tools/clang/lib/Driver/ToolChains
+ CmdArgs.push_back(Args.MakeArgString(Twine("-ret-protector")));
+ }
+
++ // -fixup-gadgets
++ if (Arg *A = Args.getLastArg(options::OPT_fno_fixup_gadgets,
++ options::OPT_ffixup_gadgets)) {
++ CmdArgs.push_back(Args.MakeArgString(Twine("-mllvm")));
++ if (A->getOption().matches(options::OPT_fno_fixup_gadgets))
++
CmdArgs.push_back(Args.MakeArgString(Twine("-x86-fixup-gadgets=false")));
++ else if (A->getOption().matches(options::OPT_ffixup_gadgets))
++ CmdArgs.push_back(Args.MakeArgString(Twine("-x86-fixup-gadgets=true")));
++ }
++
// Translate -mstackrealign
if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
false))
-@@ -4579,6 +4601,18 @@ void Clang::ConstructJob(Compilation &C, const JobActi
+@@ -4579,6 +4611,18 @@ void Clang::ConstructJob(Compilation &C, const JobActi
llvm::sys::path::replace_extension(F, "opt.yaml");
CmdArgs.push_back(Args.MakeArgString(F));
}