llvm.org GIT mirror llvm / 7f0cbb5
Revert "Insert random noops to increase security against ROP attacks (llvm)" This reverts commit: http://reviews.llvm.org/D3392 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225948 91177308-0d34-0410-b5e6-96231b3b80d8 JF Bastien 4 years ago
17 changed file(s) with 4 addition(s) and 432 deletion(s). Raw diff Collapse all Expand all
205205 FunctionSections("function-sections",
206206 cl::desc("Emit functions into separate sections"),
207207 cl::init(false));
208
209 cl::opt
210 NoopInsertion("noop-insertion",
211 cl::desc("Randomly add Noop instructions to create fine-grained "
212 "code layout diversity."),
213 cl::init(false));
214208
215209 cl::opt
216210 JTableType("jump-table-type",
289283 Options.UseInitArray = !UseCtors;
290284 Options.DataSections = DataSections;
291285 Options.FunctionSections = FunctionSections;
292 Options.NoopInsertion = NoopInsertion;
293286
294287 Options.MCOptions = InitMCTargetOptionsFromFlags();
295288 Options.JTType = JTableType;
+0
-44
include/llvm/CodeGen/NoopInsertion.h less more
None //===-- NoopInsertion.h - Noop Insertion ------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass adds fine-grained diversity by displacing code using randomly
10 // placed (optionally target supplied) Noop instructions.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_CODEGEN_NOOPINSERTION_H
15 #define LLVM_CODEGEN_NOOPINSERTION_H
16
17 #include "llvm/CodeGen/MachineFunctionPass.h"
18 #include
19
20 namespace llvm {
21
22 class RandomNumberGenerator;
23
24 class NoopInsertion : public MachineFunctionPass {
25 public:
26 static char ID;
27
28 NoopInsertion();
29
30 private:
31 bool runOnMachineFunction(MachineFunction &MF) override;
32
33 void getAnalysisUsage(AnalysisUsage &AU) const override;
34
35 std::unique_ptr RNG;
36
37 // Uniform real distribution from 0 to 100
38 std::uniform_real_distribution Distribution =
39 std::uniform_real_distribution(0, 100);
40 };
41 }
42
43 #endif // LLVM_CODEGEN_NOOPINSERTION_H
602602 /// the intrinsic for later emission to the StackMap.
603603 extern char &StackMapLivenessID;
604604
605 /// NoopInsertion - This pass adds fine-grained diversity by displacing code
606 /// using randomly placed (optionally target supplied) Noop instructions.
607 extern char &NoopInsertionID;
608
609605 /// createJumpInstrTables - This pass creates jump-instruction tables.
610606 ModulePass *createJumpInstrTablesPass();
611607
204204 void initializeMergeFunctionsPass(PassRegistry&);
205205 void initializeModuleDebugInfoPrinterPass(PassRegistry&);
206206 void initializeNoAAPass(PassRegistry&);
207 void initializeNoopInsertionPass(PassRegistry&);
208207 void initializeObjCARCAliasAnalysisPass(PassRegistry&);
209208 void initializeObjCARCAPElimPass(PassRegistry&);
210209 void initializeObjCARCExpandPass(PassRegistry&);
3030 /// module.
3131 class RandomNumberGenerator {
3232 public:
33 typedef std::mt19937_64 RNG;
34 typedef RNG::result_type result_type;
35
3633 /// Returns a random number in the range [0, Max).
37 result_type operator()();
38
39 // Must define min and max to be compatible with URNG as used by
40 // std::uniform_*_distribution
41 static LLVM_CONSTEXPR result_type min() {
42 return RNG::min();
43 }
44 static LLVM_CONSTEXPR result_type max() {
45 return RNG::max();
46 }
34 uint_fast64_t operator()();
4735
4836 private:
4937 /// Seeds and salts the underlying RNG engine.
5644 // http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine
5745 // This RNG is deterministically portable across C++11
5846 // implementations.
59 RNG Generator;
47 std::mt19937_64 Generator;
6048
6149 // Noncopyable.
6250 RandomNumberGenerator(const RandomNumberGenerator &other)
3131 class MCInst;
3232 struct MCSchedModel;
3333 class MCSymbolRefExpr;
34 class RandomNumberGenerator;
3534 class SDNode;
3635 class ScheduleHazardRecognizer;
3736 class SelectionDAG;
875874 virtual void insertNoop(MachineBasicBlock &MBB,
876875 MachineBasicBlock::iterator MI) const;
877876
878 /// insertNoop - Insert a type of noop into the instruction stream at the
879 /// specified point to introduce fine-grained diversity. A target may randomly
880 /// choose from a pool of valid noops using the provided RNG.
881 virtual void insertNoop(MachineBasicBlock &MBB,
882 MachineBasicBlock::iterator MI,
883 RandomNumberGenerator&) const {
884 insertNoop(MBB, MI);
885 }
886877
887878 /// Return the noop instruction to use for a noop.
888879 virtual void getNoopForMachoTarget(MCInst &NopInst) const;
7777 EnableFastISel(false), PositionIndependentExecutable(false),
7878 UseInitArray(false), DisableIntegratedAS(false),
7979 CompressDebugSections(false), FunctionSections(false),
80 DataSections(false), NoopInsertion(false), TrapUnreachable(false),
81 TrapFuncName(), FloatABIType(FloatABI::Default),
80 DataSections(false), TrapUnreachable(false), TrapFuncName(),
81 FloatABIType(FloatABI::Default),
8282 AllowFPOpFusion(FPOpFusion::Standard), JTType(JumpTable::Single),
8383 FCFI(false), ThreadModel(ThreadModel::POSIX),
8484 CFIType(CFIntegrity::Sub), CFIEnforcing(false), CFIFuncName() {}
196196
197197 /// Emit data into separate sections.
198198 unsigned DataSections : 1;
199
200 /// Randomly insert noop instructions to create fine-grained code
201 /// layout diversity.
202 unsigned NoopInsertion : 1;
203199
204200 /// Emit target-specific trap instruction for 'unreachable' IR instructions.
205201 unsigned TrapUnreachable : 1;
7070 MachineSink.cpp
7171 MachineTraceMetrics.cpp
7272 MachineVerifier.cpp
73 NoopInsertion.cpp
7473 OcamlGC.cpp
7574 OptimizePHIs.cpp
7675 PHIElimination.cpp
5050 initializeMachineSchedulerPass(Registry);
5151 initializeMachineSinkingPass(Registry);
5252 initializeMachineVerifierPassPass(Registry);
53 initializeNoopInsertionPass(Registry);
5453 initializeOptimizePHIsPass(Registry);
5554 initializePHIEliminationPass(Registry);
5655 initializePeepholeOptimizerPass(Registry);
+0
-101
lib/CodeGen/NoopInsertion.cpp less more
None //===- NoopInsertion.cpp - Noop Insertion ---------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass adds fine-grained diversity by displacing code using randomly
10 // placed (optionally target supplied) Noop instructions.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/CodeGen/NoopInsertion.h"
15 #include "llvm/ADT/Statistic.h"
16 #include "llvm/CodeGen/MachineInstrBuilder.h"
17 #include "llvm/CodeGen/MachineModuleInfo.h"
18 #include "llvm/CodeGen/MachineRegisterInfo.h"
19 #include "llvm/CodeGen/Passes.h"
20 #include "llvm/IR/BasicBlock.h"
21 #include "llvm/IR/Function.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/Support/Allocator.h"
24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/Support/RandomNumberGenerator.h"
26 #include "llvm/Target/TargetInstrInfo.h"
27 using namespace llvm;
28
29 #define DEBUG_TYPE "noop-insertion"
30
31 static cl::opt NoopInsertionPercentage(
32 "noop-insertion-percentage",
33 cl::desc("Percentage of instructions that have Noops prepended"),
34 cl::init(25)); // Default is a good balance between entropy and
35 // performance impact
36
37 static cl::opt MaxNoopsPerInstruction(
38 "max-noops-per-instruction",
39 llvm::cl::desc("Maximum number of Noops per instruction"),
40 llvm::cl::init(1));
41
42 STATISTIC(InsertedNoops,
43 "Total number of noop type instructions inserted for diversity");
44
45 char NoopInsertion::ID = 0;
46 char &llvm::NoopInsertionID = NoopInsertion::ID;
47 INITIALIZE_PASS(NoopInsertion, "noop-insertion",
48 "Noop Insertion for fine-grained code randomization", false,
49 false)
50
51 NoopInsertion::NoopInsertion() : MachineFunctionPass(ID) {
52 initializeNoopInsertionPass(*PassRegistry::getPassRegistry());
53
54 // clamp percentage to 100
55 if (NoopInsertionPercentage > 100)
56 NoopInsertionPercentage = 100;
57 }
58
59 void NoopInsertion::getAnalysisUsage(AnalysisUsage &AU) const {
60 AU.setPreservesCFG();
61 MachineFunctionPass::getAnalysisUsage(AU);
62 }
63
64 bool NoopInsertion::runOnMachineFunction(MachineFunction &Fn) {
65 // The RNG must be initialized on first use so we have a Module to
66 // construct it from
67 if (!RNG)
68 RNG.reset(Fn.getFunction()->getParent()->createRNG(this));
69
70 const TargetInstrInfo *TII = Fn.getSubtarget().getInstrInfo();
71
72 unsigned FnInsertedNoopCount = 0;
73
74 for (auto &BB : Fn) {
75 MachineBasicBlock::iterator FirstTerm = BB.getFirstTerminator();
76
77 for (MachineBasicBlock::iterator I = BB.begin(), E = BB.end(); I != E;
78 ++I) {
79 if (I->isPseudo())
80 continue;
81
82 // Insert random number of Noop-like instructions.
83 for (unsigned i = 0; i < MaxNoopsPerInstruction; i++) {
84 if (Distribution(*RNG) >= NoopInsertionPercentage)
85 continue;
86
87 TII->insertNoop(BB, I, *RNG);
88
89 ++FnInsertedNoopCount;
90 }
91
92 if (I == FirstTerm)
93 break;
94 }
95 }
96
97 InsertedNoops += FnInsertedNoopCount;
98
99 return FnInsertedNoopCount > 0;
100 }
582582 addPass(createGCInfoPrinter(dbgs()), false, false);
583583 }
584584
585 if (TM->Options.NoopInsertion)
586 addPass(&NoopInsertionID);
587
588585 // Basic block placement.
589586 if (getOptLevel() != CodeGenOpt::None)
590587 addBlockPlacement();
3333 #include "llvm/Support/CommandLine.h"
3434 #include "llvm/Support/Debug.h"
3535 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/RandomNumberGenerator.h"
3736 #include "llvm/Support/raw_ostream.h"
3837 #include "llvm/Target/TargetOptions.h"
3938 #include
56205619 MI->setDesc(get(table[Domain-1]));
56215620 }
56225621
5623 /// insertNoop - Insert a noop into the instruction stream at the specified
5624 /// point.
5625 void X86InstrInfo::insertNoop(MachineBasicBlock &MBB,
5626 MachineBasicBlock::iterator MI) const {
5627 DebugLoc DL;
5628 BuildMI(MBB, MI, DL, get(X86::NOOP));
5629 }
5630
5631 /// insertNoop - Insert a randomly chosen type of noop into the instruction
5632 /// stream at the specified point to introduce fine-grained diversity.
5633 void X86InstrInfo::insertNoop(MachineBasicBlock &MBB,
5634 MachineBasicBlock::iterator MI,
5635 RandomNumberGenerator &RNG) const {
5636 // This set of Noop instructions was carefully chosen so that
5637 // misaligned parses of these instructions do not introduce new,
5638 // useful ROP gadgets. The ASM instructions noted are for misaligned
5639 // parses of the noop in 32 and 64 bits.
5640 enum {
5641 NOP, // 90
5642 MOV_BP, // 89 ed, 48 89 ed -- IN EAX, IN AL (privileged)
5643 MOV_SP, // 89 e4, 48 89 e4 -- IN AL, IN EAX (privileged)
5644 LEA_SI, // 8d 36, 48 8d 36 -- SS segment override, NULL
5645 // prefix (does not add new gadget)
5646 LEA_DI, // 8d 3f, 48 8d 3f -- AAS (bcd->hex), invalid
5647 MAX_NOPS
5648 };
5649
5650 static const unsigned NopRegs[MAX_NOPS][2] = {
5651 {0, 0},
5652 {X86::EBP, X86::RBP},
5653 {X86::ESP, X86::RSP},
5654 {X86::ESI, X86::RSI},
5655 {X86::EDI, X86::RDI},
5656 };
5657
5658 std::uniform_int_distribution Distribution(0, MAX_NOPS - 1);
5659
5660 unsigned Type = Distribution(RNG);
5661
5662 DebugLoc DL;
5663 bool is64Bit = Subtarget.is64Bit();
5664 unsigned Reg = NopRegs[Type][is64Bit];
5665
5666 switch (Type) {
5667 case NOP:
5668 BuildMI(MBB, MI, DL, get(X86::NOOP));
5669 break;
5670 case MOV_BP:
5671 case MOV_SP:
5672 copyPhysReg(MBB, MI, DL, Reg, Reg, false);
5673 break;
5674 case LEA_SI:
5675 case LEA_DI: {
5676 unsigned opc = is64Bit ? X86::LEA64r : X86::LEA32r;
5677 addRegOffset(BuildMI(MBB, MI, DL, get(opc), Reg), Reg, false, 0);
5678 break;
5679 }
5680 }
5681 }
5682
56835622 /// getNoopForMachoTarget - Return the noop instruction to use for a noop.
56845623 void X86InstrInfo::getNoopForMachoTarget(MCInst &NopInst) const {
56855624 NopInst.setOpcode(X86::NOOP);
360360 bool shouldScheduleAdjacent(MachineInstr* First,
361361 MachineInstr *Second) const override;
362362
363 void insertNoop(MachineBasicBlock &MBB,
364 MachineBasicBlock::iterator MI) const override;
365
366 void insertNoop(MachineBasicBlock &MBB,
367 MachineBasicBlock::iterator MI,
368 RandomNumberGenerator &RNG) const override;
369
370363 void getNoopForMachoTarget(MCInst &NopInst) const override;
371364
372365 bool
+0
-26
test/CodeGen/Mips/noop-insert.ll less more
None ; RUN: llc < %s -march=mips -noop-insertion | FileCheck %s
1 ; RUN: llc < %s -march=mips -noop-insertion -rng-seed=1 | FileCheck %s --check-prefix=SEED1
2 ; RUN: llc < %s -march=mips -noop-insertion -noop-insertion-percentage=100 | FileCheck %s --check-prefix=100PERCENT
3
4 ; This test case checks that NOOPs are inserted correctly for MIPS.
5
6 ; It just happens that with a default percentage of 25% and seed=0,
7 ; no NOOPs are inserted.
8 ; CHECK: mul
9 ; CHECK-NEXT: jr
10
11 ; SEED1: nop
12 ; SEED1-NEXT: mul
13 ; SEED1-NEXT: jr
14
15 ; 100PERCENT: nop
16 ; 100PERCENT-NEXT: mul
17 ; 100PERCENT-NEXT: nop
18 ; 100PERCENT-NEXT: jr
19
20 define i32 @test1(i32 %x, i32 %y, i32 %z) {
21 entry:
22 %tmp = mul i32 %x, %y
23 %tmp2 = add i32 %tmp, %z
24 ret i32 %tmp2
25 }
+0
-31
test/CodeGen/PowerPC/noop-insert.ll less more
None ; RUN: llc < %s -march=ppc32 -mcpu=g4 -noop-insertion | FileCheck %s
1 ; RUN: llc < %s -march=ppc32 -mcpu=g4 -noop-insertion -rng-seed=1 | FileCheck %s --check-prefix=SEED1
2 ; RUN: llc < %s -march=ppc32 -mcpu=g4 -noop-insertion -noop-insertion-percentage=100 | FileCheck %s --check-prefix=100PERCENT
3
4 ; This test case checks that NOOPs are inserted correctly for PowerPC.
5
6 ; It just happens that with a default percentage of 25% and seed=0,
7 ; no NOOPs are inserted.
8 ; CHECK: mullw
9 ; CHECK-NEXT: add
10 ; CHECK-NEXT: blr
11
12 ; SEED1: nop
13 ; SEED1-NEXT: mullw
14 ; SEED1-NEXT: add
15 ; SEED1-NEXT: nop
16 ; SEED1-NEXT: blr
17
18 ; 100PERCENT: nop
19 ; 100PERCENT-NEXT: mullw
20 ; 100PERCENT-NEXT: nop
21 ; 100PERCENT-NEXT: add
22 ; 100PERCENT-NEXT: nop
23 ; 100PERCENT-NEXT: blr
24
25 define i32 @test1(i32 %x, i32 %y, i32 %z) {
26 entry:
27 %tmp = mul i32 %x, %y
28 %tmp2 = add i32 %tmp, %z
29 ret i32 %tmp2
30 }
+0
-68
test/CodeGen/X86/noop-insert-percentage.ll less more
None ; REQUIRES: disabled
1
2 ; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -noop-insertion -noop-insertion-percentage=10 \
3 ; RUN: | FileCheck %s --check-prefix=PERCENT10
4 ; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -noop-insertion -noop-insertion-percentage=50 \
5 ; RUN: | FileCheck %s --check-prefix=PERCENT50
6 ; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -noop-insertion -noop-insertion-percentage=100 \
7 ; RUN: | FileCheck %s --check-prefix=PERCENT100
8
9 ; RUN: llc < %s -march=x86 -rng-seed=5 -noop-insertion -noop-insertion-percentage=100 \
10 ; RUN: | FileCheck %s --check-prefix=X86-PERCENT100
11
12 ; This test case tests NOOP insertion at varying percentage levels.
13
14 define i32 @test(i32 %x, i32 %y, i32 %z) {
15 entry:
16 %t1 = add i32 %x, %y
17 %t2 = mul i32 %t1, %z
18 %t3 = add i32 %t2, %x
19 %t4 = mul i32 %t3, %z
20 %t5 = add i32 %t4, %x
21 %t6 = mul i32 %t5, %z
22 %t7 = add i32 %t6, %x
23 %t8 = mul i32 %t7, %z
24 %t9 = add i32 %t8, %x
25 %t10 = mul i32 %t9, %z
26 %t11 = add i32 %t10, %x
27 ret i32 %t11
28 }
29
30 ; PERCENT10: movq %rbp, %rbp
31 ; PERCENT10: retq
32
33 ; PERCENT50: leaq (%rdi), %rdi
34 ; PERCENT50: nop
35 ; PERCENT50: movq %rbp, %rbp
36 ; PERCENT50: movq %rsp, %rsp
37 ; PERCENT50: leaq (%rsi), %rsi
38 ; PERCENT50: nop
39 ; PERCENT50: retq
40
41 ; PERCENT100: leaq (%rdi), %rdi
42 ; PERCENT100: leaq (%rdi), %rdi
43 ; PERCENT100: nop
44 ; PERCENT100: movq %rbp, %rbp
45 ; PERCENT100: movq %rsp, %rsp
46 ; PERCENT100: nop
47 ; PERCENT100: nop
48 ; PERCENT100: leaq (%rsi), %rsi
49 ; PERCENT100: nop
50 ; PERCENT100: leaq (%rdi), %rdi
51 ; PERCENT100: leaq (%rdi), %rdi
52 ; PERCENT100: leaq (%rsi), %rsi
53 ; PERCENT100: retq
54
55
56 ; X86-PERCENT100: leal (%edi), %edi
57 ; X86-PERCENT100: leal (%edi), %edi
58 ; X86-PERCENT100: nop
59 ; X86-PERCENT100: movl %ebp, %ebp
60 ; X86-PERCENT100: movl %esp, %esp
61 ; X86-PERCENT100: nop
62 ; X86-PERCENT100: nop
63 ; X86-PERCENT100: leal (%esi), %esi
64 ; X86-PERCENT100: nop
65 ; X86-PERCENT100: leal (%edi), %edi
66 ; X86-PERCENT100: leal (%edi), %edi
67 ; X86-PERCENT100: leal (%esi), %esi
+0
-48
test/CodeGen/X86/noop-insert.ll less more
None ; REQUIRES: disabled
1
2 ; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion | FileCheck %s
3 ; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion -rng-seed=1 | FileCheck %s --check-prefix=SEED1
4 ; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion -rng-seed=20 | FileCheck %s --check-prefix=SEED2
5 ; RUN: llc < %s -mtriple=x86_64-linux -noop-insertion -rng-seed=500 | FileCheck %s --check-prefix=SEED3
6
7 ; RUN: llc < %s -march=x86 -noop-insertion | FileCheck %s --check-prefix=x86_32
8
9 ; This test case checks that NOOPs are inserted, and that the RNG seed
10 ; affects both the placement (position of imull) and choice of these NOOPs.
11
12 ; It just happens that with a default percentage of 25% and seed=0,
13 ; no NOOPs are inserted.
14 ; CHECK: imull
15 ; CHECK-NEXT: leal
16 ; CHECK-NEXT: retq
17 ; CHECK-NOT: nop
18
19 ; SEED1: leaq (%rsi), %rsi
20 ; SEED1-NEXT: imull
21 ; SEED1-NEXT: leal
22 ; SEED1-NEXT: retq
23
24 ; SEED2: imull
25 ; SEED2-NEXT: movq %rsp, %rsp
26 ; SEED2-NEXT: leal
27 ; SEED2-NEXT: retq
28
29 ; SEED3: imull
30 ; SEED3-NEXT: movq %rsp, %rsp
31 ; SEED3-NEXT: leal
32 ; SEED3-NEXT: leaq (%rdi), %rdi
33 ; SEED3-NEXT: retq
34
35 ; The operand of the following is used to distinguish from a movl NOOP
36 ; x86_32: movl 4(%esp),
37 ; x86_32-NEXT: imull
38 ; x86_32-NEXT: addl
39 ; x86_32-NEXT: movl %esp, %esp
40 ; x86_32-NEXT: retl
41
42 define i32 @test1(i32 %x, i32 %y, i32 %z) {
43 entry:
44 %tmp = mul i32 %x, %y
45 %tmp2 = add i32 %tmp, %z
46 ret i32 %tmp2
47 }