diff options
author | mortimer <mortimer@cvs.openbsd.org> | 2018-04-28 23:00:29 +0000 |
---|---|---|
committer | mortimer <mortimer@cvs.openbsd.org> | 2018-04-28 23:00:29 +0000 |
commit | 04704196a7d4cacd952a9bb054e4d8b1ac265ae9 (patch) | |
tree | 9c20186ce2ffba69831e46ca0d66da3596e75584 /gnu | |
parent | 4539bdec23a59b9e899286daad9e6d68c07f79ee (diff) |
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.
ok deraadt@
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/llvm/lib/Target/X86/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gnu/llvm/lib/Target/X86/X86.h | 4 | ||||
-rw-r--r-- | gnu/llvm/lib/Target/X86/X86FixupGadgets.cpp | 267 | ||||
-rw-r--r-- | gnu/llvm/lib/Target/X86/X86TargetMachine.cpp | 1 | ||||
-rw-r--r-- | gnu/usr.bin/clang/libLLVMX86CodeGen/Makefile | 3 |
5 files changed, 275 insertions, 1 deletions
diff --git a/gnu/llvm/lib/Target/X86/CMakeLists.txt b/gnu/llvm/lib/Target/X86/CMakeLists.txt index 23ac9d9936a..2c52e128ddd 100644 --- a/gnu/llvm/lib/Target/X86/CMakeLists.txt +++ b/gnu/llvm/lib/Target/X86/CMakeLists.txt @@ -29,6 +29,7 @@ set(sources X86ExpandPseudo.cpp X86FastISel.cpp X86FixupBWInsts.cpp + X86FixupGadgets.cpp X86FixupLEAs.cpp X86FixupSetCC.cpp X86FloatingPoint.cpp diff --git a/gnu/llvm/lib/Target/X86/X86.h b/gnu/llvm/lib/Target/X86/X86.h index 36132682429..db7930a265a 100644 --- a/gnu/llvm/lib/Target/X86/X86.h +++ b/gnu/llvm/lib/Target/X86/X86.h @@ -99,6 +99,10 @@ FunctionPass *createX86DomainReassignmentPass(); void initializeFixupBWInstPassPass(PassRegistry &); +/// Return a Machine Function pass that attempts to replace +/// ROP friendly instructions with alternatives. +FunctionPass *createX86FixupGadgetsPass(); + /// This pass replaces EVEX encoded of AVX-512 instructiosn by VEX /// encoding when possible in order to reduce code size. FunctionPass *createX86EvexToVexInsts(); diff --git a/gnu/llvm/lib/Target/X86/X86FixupGadgets.cpp b/gnu/llvm/lib/Target/X86/X86FixupGadgets.cpp new file mode 100644 index 00000000000..5f6b351648d --- /dev/null +++ b/gnu/llvm/lib/Target/X86/X86FixupGadgets.cpp @@ -0,0 +1,267 @@ +//===-- X86FixupGadgets.cpp - Fixup Instructions that make ROP Gadgets ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file defines a function pass that checks instructions for sequences +/// that will lower to a potentially useful ROP gadget, and attempts to +/// replace those sequences with alternatives that are not useful for ROP. +/// +//===----------------------------------------------------------------------===// + +#include "X86.h" +#include "X86InstrBuilder.h" +#include "X86InstrInfo.h" +#include "X86MachineFunctionInfo.h" +#include "X86Subtarget.h" +#include "X86TargetMachine.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define FIXUPGADGETS_DESC "X86 ROP Gadget Fixup" +#define FIXUPGADGETS_NAME "x86-fixup-gadgets" + +#define DEBUG_TYPE FIXUPGADGETS_NAME + +// Toggle with cc1 option: -backend-option -x86-fixup-gadgets=<true|false> +static cl::opt<bool> FixupGadgets( + "x86-fixup-gadgets", + cl::desc("Replace ROP friendly instructions with alternatives"), + cl::init(true)); + +namespace { +class FixupGadgetsPass : public MachineFunctionPass { + +public: + static char ID; + + StringRef getPassName() const override { return FIXUPGADGETS_DESC; } + + FixupGadgetsPass() + : MachineFunctionPass(ID), STI(nullptr), TII(nullptr), TRI(nullptr) {} + + /// Loop over all the instructions and replace ROP friendly + /// seuqences with less ROP friendly alternatives + bool runOnMachineFunction(MachineFunction &MF) override; + + MachineFunctionProperties getRequiredProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::NoVRegs); + } + +private: + const X86Subtarget *STI; + 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; + + /// Helper functions for various kinds of instructions + bool isOneGPRegC3(MachineInstr &MI) const; + bool isTwoGPRegC3(MachineInstr &MI) const; + bool isThreeGPRegC3(MachineInstr &MI) const; + + /// Replace ROP friendly instructions with safe alternatives + bool fixupInstruction(MachineFunction &MF, MachineBasicBlock &MBB, + MachineInstr &MI, InstrType type); +}; +char FixupGadgetsPass::ID = 0; +} // namespace + +FunctionPass *llvm::createX86FixupGadgetsPass() { + 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; +} + +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; + + unsigned dstReg = MO0.getReg(); + if (dstReg == X86::RBX || dstReg == X86::EBX || dstReg == X86::BX || + dstReg == X86::BL) + DestSet = true; + + if (!DestSet) + return false; + + unsigned srcReg = MO1.getReg(); + if (srcReg == X86::RAX || srcReg == X86::EAX || srcReg == X86::AX || + srcReg == X86::AL) + SrcSet = true; + + if (!SrcSet) + return false; + + if ((MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg) + OpcodeSet = true; + + return DestSet && SrcSet && OpcodeSet; +} + +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; + + unsigned dstReg = MO0.getReg(); + if (dstReg == X86::RBX || dstReg == X86::EBX || dstReg == X86::BX || + dstReg == X86::BL) + DestSet = true; + + if (!DestSet) + return false; + + unsigned srcReg = MO2.getReg(); + if (srcReg == X86::RAX || srcReg == X86::EAX || srcReg == X86::AX || + srcReg == X86::AL) + SrcSet = true; + + if (!SrcSet) + return false; + + if ((MI.getDesc().TSFlags & X86II::FormMask) == X86II::MRMDestReg) + OpcodeSet = true; + + return DestSet && SrcSet && OpcodeSet; +} + +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; + } + return NoType; +} + +bool FixupGadgetsPass::fixupInstruction(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineInstr &MI, InstrType type) { + + if (type == NoType) + return false; + + MachineOperand *MO0, *MO1, *MO2; + DebugLoc DL = MI.getDebugLoc(); + unsigned XCHG = Is64Bit ? X86::XCHG64rr : X86::XCHG32rr; + unsigned SREG = Is64Bit ? X86::RAX : X86::EAX; + unsigned DREG = Is64Bit ? X86::RBX : X86::EBX; + unsigned tmpReg; + + // Swap the two registers to start + BuildMI(MBB, MI, DL, TII->get(XCHG), DREG).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"); + } + + // And swap them back to finish + BuildMI(MBB, MI, DL, TII->get(XCHG), DREG).addReg(DREG).addReg(SREG); + // Erase original instruction + MI.eraseFromParent(); + + return true; +} + +bool FixupGadgetsPass::runOnMachineFunction(MachineFunction &MF) { + if (!FixupGadgets) + return false; + + STI = &MF.getSubtarget<X86Subtarget>(); + TII = STI->getInstrInfo(); + TRI = STI->getRegisterInfo(); + Is64Bit = STI->is64Bit(); + std::vector<std::pair<MachineInstr *, InstrType>> fixups; + InstrType type; + + 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)); + } + for (auto &fixup : fixups) + modified |= fixupInstruction(MF, MBB, *fixup.first, fixup.second); + } + + return modified; +} diff --git a/gnu/llvm/lib/Target/X86/X86TargetMachine.cpp b/gnu/llvm/lib/Target/X86/X86TargetMachine.cpp index ac242e1c00e..1d40c347efa 100644 --- a/gnu/llvm/lib/Target/X86/X86TargetMachine.cpp +++ b/gnu/llvm/lib/Target/X86/X86TargetMachine.cpp @@ -441,6 +441,7 @@ void X86PassConfig::addPreEmitPass() { addPass(createX86FixupLEAs()); addPass(createX86EvexToVexInsts()); } + addPass(createX86FixupGadgetsPass()); } void X86PassConfig::addPreEmitPass2() { diff --git a/gnu/usr.bin/clang/libLLVMX86CodeGen/Makefile b/gnu/usr.bin/clang/libLLVMX86CodeGen/Makefile index eb31fe9e472..3ec6619e347 100644 --- a/gnu/usr.bin/clang/libLLVMX86CodeGen/Makefile +++ b/gnu/usr.bin/clang/libLLVMX86CodeGen/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.8 2018/04/20 21:12:50 naddy Exp $ +# $OpenBSD: Makefile,v 1.9 2018/04/28 23:00:28 mortimer Exp $ LIB= LLVMX86CodeGen NOPIC= @@ -17,6 +17,7 @@ SRCS= X86AsmPrinter.cpp \ X86ExpandPseudo.cpp \ X86FastISel.cpp \ X86FixupBWInsts.cpp \ + X86FixupGadgets.cpp \ X86FixupLEAs.cpp \ X86FixupSetCC.cpp \ X86FloatingPoint.cpp \ |