Revert "Insert random noops to increase security against ROP attacks (llvm)"

This reverts commit:
http://reviews.llvm.org/D3392

llvm-svn: 225948
This commit is contained in:
JF Bastien 2015-01-14 05:24:33 +00:00
parent c7af264486
commit eeea8970b4
17 changed files with 4 additions and 432 deletions

View File

@ -207,12 +207,6 @@ FunctionSections("function-sections",
cl::desc("Emit functions into separate sections"), cl::desc("Emit functions into separate sections"),
cl::init(false)); cl::init(false));
cl::opt<bool>
NoopInsertion("noop-insertion",
cl::desc("Randomly add Noop instructions to create fine-grained "
"code layout diversity."),
cl::init(false));
cl::opt<llvm::JumpTable::JumpTableType> cl::opt<llvm::JumpTable::JumpTableType>
JTableType("jump-table-type", JTableType("jump-table-type",
cl::desc("Choose the type of Jump-Instruction Table for jumptable."), cl::desc("Choose the type of Jump-Instruction Table for jumptable."),
@ -290,7 +284,6 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
Options.UseInitArray = !UseCtors; Options.UseInitArray = !UseCtors;
Options.DataSections = DataSections; Options.DataSections = DataSections;
Options.FunctionSections = FunctionSections; Options.FunctionSections = FunctionSections;
Options.NoopInsertion = NoopInsertion;
Options.MCOptions = InitMCTargetOptionsFromFlags(); Options.MCOptions = InitMCTargetOptionsFromFlags();
Options.JTType = JTableType; Options.JTType = JTableType;

View File

@ -1,44 +0,0 @@
//===-- NoopInsertion.h - Noop Insertion ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass adds fine-grained diversity by displacing code using randomly
// placed (optionally target supplied) Noop instructions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_NOOPINSERTION_H
#define LLVM_CODEGEN_NOOPINSERTION_H
#include "llvm/CodeGen/MachineFunctionPass.h"
#include <random>
namespace llvm {
class RandomNumberGenerator;
class NoopInsertion : public MachineFunctionPass {
public:
static char ID;
NoopInsertion();
private:
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
std::unique_ptr<RandomNumberGenerator> RNG;
// Uniform real distribution from 0 to 100
std::uniform_real_distribution<double> Distribution =
std::uniform_real_distribution<double>(0, 100);
};
}
#endif // LLVM_CODEGEN_NOOPINSERTION_H

View File

@ -603,10 +603,6 @@ namespace llvm {
/// the intrinsic for later emission to the StackMap. /// the intrinsic for later emission to the StackMap.
extern char &StackMapLivenessID; extern char &StackMapLivenessID;
/// NoopInsertion - This pass adds fine-grained diversity by displacing code
/// using randomly placed (optionally target supplied) Noop instructions.
extern char &NoopInsertionID;
/// createJumpInstrTables - This pass creates jump-instruction tables. /// createJumpInstrTables - This pass creates jump-instruction tables.
ModulePass *createJumpInstrTablesPass(); ModulePass *createJumpInstrTablesPass();

View File

@ -205,7 +205,6 @@ void initializeMetaRenamerPass(PassRegistry&);
void initializeMergeFunctionsPass(PassRegistry&); void initializeMergeFunctionsPass(PassRegistry&);
void initializeModuleDebugInfoPrinterPass(PassRegistry&); void initializeModuleDebugInfoPrinterPass(PassRegistry&);
void initializeNoAAPass(PassRegistry&); void initializeNoAAPass(PassRegistry&);
void initializeNoopInsertionPass(PassRegistry&);
void initializeObjCARCAliasAnalysisPass(PassRegistry&); void initializeObjCARCAliasAnalysisPass(PassRegistry&);
void initializeObjCARCAPElimPass(PassRegistry&); void initializeObjCARCAPElimPass(PassRegistry&);
void initializeObjCARCExpandPass(PassRegistry&); void initializeObjCARCExpandPass(PassRegistry&);

View File

@ -31,20 +31,8 @@ namespace llvm {
/// module. /// module.
class RandomNumberGenerator { class RandomNumberGenerator {
public: public:
typedef std::mt19937_64 RNG;
typedef RNG::result_type result_type;
/// Returns a random number in the range [0, Max). /// Returns a random number in the range [0, Max).
result_type operator()(); uint_fast64_t operator()();
// Must define min and max to be compatible with URNG as used by
// std::uniform_*_distribution
static LLVM_CONSTEXPR result_type min() {
return RNG::min();
}
static LLVM_CONSTEXPR result_type max() {
return RNG::max();
}
private: private:
/// Seeds and salts the underlying RNG engine. /// Seeds and salts the underlying RNG engine.
@ -57,7 +45,7 @@ private:
// http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine // http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine
// This RNG is deterministically portable across C++11 // This RNG is deterministically portable across C++11
// implementations. // implementations.
RNG Generator; std::mt19937_64 Generator;
// Noncopyable. // Noncopyable.
RandomNumberGenerator(const RandomNumberGenerator &other) RandomNumberGenerator(const RandomNumberGenerator &other)

View File

@ -32,7 +32,6 @@ class MDNode;
class MCInst; class MCInst;
struct MCSchedModel; struct MCSchedModel;
class MCSymbolRefExpr; class MCSymbolRefExpr;
class RandomNumberGenerator;
class SDNode; class SDNode;
class ScheduleHazardRecognizer; class ScheduleHazardRecognizer;
class SelectionDAG; class SelectionDAG;
@ -876,14 +875,6 @@ public:
virtual void insertNoop(MachineBasicBlock &MBB, virtual void insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const; MachineBasicBlock::iterator MI) const;
/// insertNoop - Insert a type of noop into the instruction stream at the
/// specified point to introduce fine-grained diversity. A target may randomly
/// choose from a pool of valid noops using the provided RNG.
virtual void insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
RandomNumberGenerator&) const {
insertNoop(MBB, MI);
}
/// Return the noop instruction to use for a noop. /// Return the noop instruction to use for a noop.
virtual void getNoopForMachoTarget(MCInst &NopInst) const; virtual void getNoopForMachoTarget(MCInst &NopInst) const;

View File

@ -78,8 +78,8 @@ namespace llvm {
EnableFastISel(false), PositionIndependentExecutable(false), EnableFastISel(false), PositionIndependentExecutable(false),
UseInitArray(false), DisableIntegratedAS(false), UseInitArray(false), DisableIntegratedAS(false),
CompressDebugSections(false), FunctionSections(false), CompressDebugSections(false), FunctionSections(false),
DataSections(false), NoopInsertion(false), TrapUnreachable(false), DataSections(false), TrapUnreachable(false), TrapFuncName(),
TrapFuncName(), FloatABIType(FloatABI::Default), FloatABIType(FloatABI::Default),
AllowFPOpFusion(FPOpFusion::Standard), JTType(JumpTable::Single), AllowFPOpFusion(FPOpFusion::Standard), JTType(JumpTable::Single),
FCFI(false), ThreadModel(ThreadModel::POSIX), FCFI(false), ThreadModel(ThreadModel::POSIX),
CFIType(CFIntegrity::Sub), CFIEnforcing(false), CFIFuncName() {} CFIType(CFIntegrity::Sub), CFIEnforcing(false), CFIFuncName() {}
@ -198,10 +198,6 @@ namespace llvm {
/// Emit data into separate sections. /// Emit data into separate sections.
unsigned DataSections : 1; unsigned DataSections : 1;
/// Randomly insert noop instructions to create fine-grained code
/// layout diversity.
unsigned NoopInsertion : 1;
/// Emit target-specific trap instruction for 'unreachable' IR instructions. /// Emit target-specific trap instruction for 'unreachable' IR instructions.
unsigned TrapUnreachable : 1; unsigned TrapUnreachable : 1;

View File

@ -71,7 +71,6 @@ add_llvm_library(LLVMCodeGen
MachineSink.cpp MachineSink.cpp
MachineTraceMetrics.cpp MachineTraceMetrics.cpp
MachineVerifier.cpp MachineVerifier.cpp
NoopInsertion.cpp
OcamlGC.cpp OcamlGC.cpp
OptimizePHIs.cpp OptimizePHIs.cpp
PHIElimination.cpp PHIElimination.cpp

View File

@ -51,7 +51,6 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializeMachineSchedulerPass(Registry); initializeMachineSchedulerPass(Registry);
initializeMachineSinkingPass(Registry); initializeMachineSinkingPass(Registry);
initializeMachineVerifierPassPass(Registry); initializeMachineVerifierPassPass(Registry);
initializeNoopInsertionPass(Registry);
initializeOptimizePHIsPass(Registry); initializeOptimizePHIsPass(Registry);
initializePHIEliminationPass(Registry); initializePHIEliminationPass(Registry);
initializePeepholeOptimizerPass(Registry); initializePeepholeOptimizerPass(Registry);

View File

@ -1,101 +0,0 @@
//===- NoopInsertion.cpp - Noop Insertion ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass adds fine-grained diversity by displacing code using randomly
// placed (optionally target supplied) Noop instructions.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/NoopInsertion.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;
#define DEBUG_TYPE "noop-insertion"
static cl::opt<unsigned> NoopInsertionPercentage(
"noop-insertion-percentage",
cl::desc("Percentage of instructions that have Noops prepended"),
cl::init(25)); // Default is a good balance between entropy and
// performance impact
static cl::opt<unsigned> MaxNoopsPerInstruction(
"max-noops-per-instruction",
llvm::cl::desc("Maximum number of Noops per instruction"),
llvm::cl::init(1));
STATISTIC(InsertedNoops,
"Total number of noop type instructions inserted for diversity");
char NoopInsertion::ID = 0;
char &llvm::NoopInsertionID = NoopInsertion::ID;
INITIALIZE_PASS(NoopInsertion, "noop-insertion",
"Noop Insertion for fine-grained code randomization", false,
false)
NoopInsertion::NoopInsertion() : MachineFunctionPass(ID) {
initializeNoopInsertionPass(*PassRegistry::getPassRegistry());
// clamp percentage to 100
if (NoopInsertionPercentage > 100)
NoopInsertionPercentage = 100;
}
void NoopInsertion::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
bool NoopInsertion::runOnMachineFunction(MachineFunction &Fn) {
// The RNG must be initialized on first use so we have a Module to
// construct it from
if (!RNG)
RNG.reset(Fn.getFunction()->getParent()->createRNG(this));
const TargetInstrInfo *TII = Fn.getSubtarget().getInstrInfo();
unsigned FnInsertedNoopCount = 0;
for (auto &BB : Fn) {
MachineBasicBlock::iterator FirstTerm = BB.getFirstTerminator();
for (MachineBasicBlock::iterator I = BB.begin(), E = BB.end(); I != E;
++I) {
if (I->isPseudo())
continue;
// Insert random number of Noop-like instructions.
for (unsigned i = 0; i < MaxNoopsPerInstruction; i++) {
if (Distribution(*RNG) >= NoopInsertionPercentage)
continue;
TII->insertNoop(BB, I, *RNG);
++FnInsertedNoopCount;
}
if (I == FirstTerm)
break;
}
}
InsertedNoops += FnInsertedNoopCount;
return FnInsertedNoopCount > 0;
}

View File

@ -583,9 +583,6 @@ void TargetPassConfig::addMachinePasses() {
addPass(createGCInfoPrinter(dbgs()), false, false); addPass(createGCInfoPrinter(dbgs()), false, false);
} }
if (TM->Options.NoopInsertion)
addPass(&NoopInsertionID);
// Basic block placement. // Basic block placement.
if (getOptLevel() != CodeGenOpt::None) if (getOptLevel() != CodeGenOpt::None)
addBlockPlacement(); addBlockPlacement();

View File

@ -34,7 +34,6 @@
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetOptions.h"
#include <limits> #include <limits>
@ -5621,66 +5620,6 @@ void X86InstrInfo::setExecutionDomain(MachineInstr *MI, unsigned Domain) const {
MI->setDesc(get(table[Domain-1])); MI->setDesc(get(table[Domain-1]));
} }
/// insertNoop - Insert a noop into the instruction stream at the specified
/// point.
void X86InstrInfo::insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const {
DebugLoc DL;
BuildMI(MBB, MI, DL, get(X86::NOOP));
}
/// insertNoop - Insert a randomly chosen type of noop into the instruction
/// stream at the specified point to introduce fine-grained diversity.
void X86InstrInfo::insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
RandomNumberGenerator &RNG) const {
// This set of Noop instructions was carefully chosen so that
// misaligned parses of these instructions do not introduce new,
// useful ROP gadgets. The ASM instructions noted are for misaligned
// parses of the noop in 32 and 64 bits.
enum {
NOP, // 90
MOV_BP, // 89 ed, 48 89 ed -- IN EAX, IN AL (privileged)
MOV_SP, // 89 e4, 48 89 e4 -- IN AL, IN EAX (privileged)
LEA_SI, // 8d 36, 48 8d 36 -- SS segment override, NULL
// prefix (does not add new gadget)
LEA_DI, // 8d 3f, 48 8d 3f -- AAS (bcd->hex), invalid
MAX_NOPS
};
static const unsigned NopRegs[MAX_NOPS][2] = {
{0, 0},
{X86::EBP, X86::RBP},
{X86::ESP, X86::RSP},
{X86::ESI, X86::RSI},
{X86::EDI, X86::RDI},
};
std::uniform_int_distribution<unsigned> Distribution(0, MAX_NOPS - 1);
unsigned Type = Distribution(RNG);
DebugLoc DL;
bool is64Bit = Subtarget.is64Bit();
unsigned Reg = NopRegs[Type][is64Bit];
switch (Type) {
case NOP:
BuildMI(MBB, MI, DL, get(X86::NOOP));
break;
case MOV_BP:
case MOV_SP:
copyPhysReg(MBB, MI, DL, Reg, Reg, false);
break;
case LEA_SI:
case LEA_DI: {
unsigned opc = is64Bit ? X86::LEA64r : X86::LEA32r;
addRegOffset(BuildMI(MBB, MI, DL, get(opc), Reg), Reg, false, 0);
break;
}
}
}
/// getNoopForMachoTarget - Return the noop instruction to use for a noop. /// getNoopForMachoTarget - Return the noop instruction to use for a noop.
void X86InstrInfo::getNoopForMachoTarget(MCInst &NopInst) const { void X86InstrInfo::getNoopForMachoTarget(MCInst &NopInst) const {
NopInst.setOpcode(X86::NOOP); NopInst.setOpcode(X86::NOOP);

View File

@ -361,13 +361,6 @@ public:
bool shouldScheduleAdjacent(MachineInstr* First, bool shouldScheduleAdjacent(MachineInstr* First,
MachineInstr *Second) const override; MachineInstr *Second) const override;
void insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const override;
void insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
RandomNumberGenerator &RNG) const override;
void getNoopForMachoTarget(MCInst &NopInst) const override; void getNoopForMachoTarget(MCInst &NopInst) const override;
bool bool

View File

@ -1,26 +0,0 @@
; RUN: llc < %s -march=mips -noop-insertion | FileCheck %s
; RUN: llc < %s -march=mips -noop-insertion -rng-seed=1 | FileCheck %s --check-prefix=SEED1
; RUN: llc < %s -march=mips -noop-insertion -noop-insertion-percentage=100 | FileCheck %s --check-prefix=100PERCENT
; This test case checks that NOOPs are inserted correctly for MIPS.
; It just happens that with a default percentage of 25% and seed=0,
; no NOOPs are inserted.
; CHECK: mul
; CHECK-NEXT: jr
; SEED1: nop
; SEED1-NEXT: mul
; SEED1-NEXT: jr
; 100PERCENT: nop
; 100PERCENT-NEXT: mul
; 100PERCENT-NEXT: nop
; 100PERCENT-NEXT: jr
define i32 @test1(i32 %x, i32 %y, i32 %z) {
entry:
%tmp = mul i32 %x, %y
%tmp2 = add i32 %tmp, %z
ret i32 %tmp2
}

View File

@ -1,31 +0,0 @@
; RUN: llc < %s -march=ppc32 -mcpu=g4 -noop-insertion | FileCheck %s
; RUN: llc < %s -march=ppc32 -mcpu=g4 -noop-insertion -rng-seed=1 | FileCheck %s --check-prefix=SEED1
; RUN: llc < %s -march=ppc32 -mcpu=g4 -noop-insertion -noop-insertion-percentage=100 | FileCheck %s --check-prefix=100PERCENT
; This test case checks that NOOPs are inserted correctly for PowerPC.
; It just happens that with a default percentage of 25% and seed=0,
; no NOOPs are inserted.
; CHECK: mullw
; CHECK-NEXT: add
; CHECK-NEXT: blr
; SEED1: nop
; SEED1-NEXT: mullw
; SEED1-NEXT: add
; SEED1-NEXT: nop
; SEED1-NEXT: blr
; 100PERCENT: nop
; 100PERCENT-NEXT: mullw
; 100PERCENT-NEXT: nop
; 100PERCENT-NEXT: add
; 100PERCENT-NEXT: nop
; 100PERCENT-NEXT: blr
define i32 @test1(i32 %x, i32 %y, i32 %z) {
entry:
%tmp = mul i32 %x, %y
%tmp2 = add i32 %tmp, %z
ret i32 %tmp2
}

View File

@ -1,68 +0,0 @@
; REQUIRES: disabled
; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -noop-insertion -noop-insertion-percentage=10 \
; RUN: | FileCheck %s --check-prefix=PERCENT10
; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -noop-insertion -noop-insertion-percentage=50 \
; RUN: | FileCheck %s --check-prefix=PERCENT50
; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -noop-insertion -noop-insertion-percentage=100 \
; RUN: | FileCheck %s --check-prefix=PERCENT100
; RUN: llc < %s -march=x86 -rng-seed=5 -noop-insertion -noop-insertion-percentage=100 \
; RUN: | FileCheck %s --check-prefix=X86-PERCENT100
; This test case tests NOOP insertion at varying percentage levels.
define i32 @test(i32 %x, i32 %y, i32 %z) {
entry:
%t1 = add i32 %x, %y
%t2 = mul i32 %t1, %z
%t3 = add i32 %t2, %x
%t4 = mul i32 %t3, %z
%t5 = add i32 %t4, %x
%t6 = mul i32 %t5, %z
%t7 = add i32 %t6, %x
%t8 = mul i32 %t7, %z
%t9 = add i32 %t8, %x
%t10 = mul i32 %t9, %z
%t11 = add i32 %t10, %x
ret i32 %t11
}
; PERCENT10: movq %rbp, %rbp
; PERCENT10: retq
; PERCENT50: leaq (%rdi), %rdi
; PERCENT50: nop
; PERCENT50: movq %rbp, %rbp
; PERCENT50: movq %rsp, %rsp
; PERCENT50: leaq (%rsi), %rsi
; PERCENT50: nop
; PERCENT50: retq
; PERCENT100: leaq (%rdi), %rdi
; PERCENT100: leaq (%rdi), %rdi
; PERCENT100: nop
; PERCENT100: movq %rbp, %rbp
; PERCENT100: movq %rsp, %rsp
; PERCENT100: nop
; PERCENT100: nop
; PERCENT100: leaq (%rsi), %rsi
; PERCENT100: nop
; PERCENT100: leaq (%rdi), %rdi
; PERCENT100: leaq (%rdi), %rdi
; PERCENT100: leaq (%rsi), %rsi
; PERCENT100: retq
; X86-PERCENT100: leal (%edi), %edi
; X86-PERCENT100: leal (%edi), %edi
; X86-PERCENT100: nop
; X86-PERCENT100: movl %ebp, %ebp
; X86-PERCENT100: movl %esp, %esp
; X86-PERCENT100: nop
; X86-PERCENT100: nop
; X86-PERCENT100: leal (%esi), %esi
; X86-PERCENT100: nop
; X86-PERCENT100: leal (%edi), %edi
; X86-PERCENT100: leal (%edi), %edi
; X86-PERCENT100: leal (%esi), %esi

View File

@ -1,48 +0,0 @@
; REQUIRES: disabled
; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion | FileCheck %s
; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion -rng-seed=1 | FileCheck %s --check-prefix=SEED1
; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion -rng-seed=20 | FileCheck %s --check-prefix=SEED2
; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion -rng-seed=500 | FileCheck %s --check-prefix=SEED3
; RUN: llc < %s -march=x86 -noop-insertion | FileCheck %s --check-prefix=x86_32
; This test case checks that NOOPs are inserted, and that the RNG seed
; affects both the placement (position of imull) and choice of these NOOPs.
; It just happens that with a default percentage of 25% and seed=0,
; no NOOPs are inserted.
; CHECK: imull
; CHECK-NEXT: leal
; CHECK-NEXT: retq
; CHECK-NOT: nop
; SEED1: leaq (%rsi), %rsi
; SEED1-NEXT: imull
; SEED1-NEXT: leal
; SEED1-NEXT: retq
; SEED2: imull
; SEED2-NEXT: movq %rsp, %rsp
; SEED2-NEXT: leal
; SEED2-NEXT: retq
; SEED3: imull
; SEED3-NEXT: movq %rsp, %rsp
; SEED3-NEXT: leal
; SEED3-NEXT: leaq (%rdi), %rdi
; SEED3-NEXT: retq
; The operand of the following is used to distinguish from a movl NOOP
; x86_32: movl 4(%esp),
; x86_32-NEXT: imull
; x86_32-NEXT: addl
; x86_32-NEXT: movl %esp, %esp
; x86_32-NEXT: retl
define i32 @test1(i32 %x, i32 %y, i32 %z) {
entry:
%tmp = mul i32 %x, %y
%tmp2 = add i32 %tmp, %z
ret i32 %tmp2
}