This repository has been archived by the owner on Apr 23, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[mips] Implement NaCl sandboxing of indirect jumps:
* Align targets of indirect jumps to instruction bundle boundaries (in MI layer). * Add masking instructions before indirect jumps (in MC layer). Differential Revision: http://llvm-reviews.chandlerc.com/D2847 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202479 91177308-0d34-0410-b5e6-96231b3b80d8
- Loading branch information
Sasa Stankovic
authored and
Sasa Stankovic
committed
Feb 28, 2014
1 parent
72c42d9
commit 068a8c1
Showing
8 changed files
with
298 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
//===-- MipsMCNaCl.h - NaCl-related declarations --------------------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef MIPSMCNACL_H | ||
#define MIPSMCNACL_H | ||
|
||
#include "llvm/MC/MCELFStreamer.h" | ||
|
||
namespace llvm { | ||
|
||
// Log2 of the NaCl MIPS sandbox's instruction bundle size. | ||
static const unsigned MIPS_NACL_BUNDLE_ALIGN = 4u; | ||
|
||
// This function creates an MCELFStreamer for Mips NaCl. | ||
MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, | ||
raw_ostream &OS, | ||
MCCodeEmitter *Emitter, | ||
bool RelaxAll, bool NoExecStack); | ||
|
||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
//===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file implements MCELFStreamer for Mips NaCl. It emits .o object files | ||
// as required by NaCl's SFI sandbox. It inserts address-masking instructions | ||
// before dangerous control-flow instructions. It aligns on bundle size all | ||
// functions and all targets of indirect branches. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#define DEBUG_TYPE "mips-mc-nacl" | ||
|
||
#include "Mips.h" | ||
#include "MipsMCNaCl.h" | ||
#include "llvm/MC/MCELFStreamer.h" | ||
|
||
using namespace llvm; | ||
|
||
namespace { | ||
|
||
const unsigned IndirectBranchMaskReg = Mips::T6; | ||
|
||
/// Extend the generic MCELFStreamer class so that it can mask dangerous | ||
/// instructions. | ||
|
||
class MipsNaClELFStreamer : public MCELFStreamer { | ||
public: | ||
MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, | ||
MCCodeEmitter *Emitter) | ||
: MCELFStreamer(Context, TAB, OS, Emitter) {} | ||
|
||
~MipsNaClELFStreamer() {} | ||
|
||
private: | ||
bool isIndirectJump(const MCInst &MI) { | ||
return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET; | ||
} | ||
|
||
void emitMask(unsigned AddrReg, unsigned MaskReg, | ||
const MCSubtargetInfo &STI) { | ||
MCInst MaskInst; | ||
MaskInst.setOpcode(Mips::AND); | ||
MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); | ||
MaskInst.addOperand(MCOperand::CreateReg(AddrReg)); | ||
MaskInst.addOperand(MCOperand::CreateReg(MaskReg)); | ||
MCELFStreamer::EmitInstruction(MaskInst, STI); | ||
} | ||
|
||
// Sandbox indirect branch or return instruction by inserting mask operation | ||
// before it. | ||
void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) { | ||
unsigned AddrReg = MI.getOperand(0).getReg(); | ||
|
||
EmitBundleLock(false); | ||
emitMask(AddrReg, IndirectBranchMaskReg, STI); | ||
MCELFStreamer::EmitInstruction(MI, STI); | ||
EmitBundleUnlock(); | ||
} | ||
|
||
public: | ||
/// This function is the one used to emit instruction data into the ELF | ||
/// streamer. We override it to mask dangerous instructions. | ||
virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) { | ||
if (isIndirectJump(Inst)) | ||
sandboxIndirectJump(Inst, STI); | ||
else | ||
MCELFStreamer::EmitInstruction(Inst, STI); | ||
} | ||
}; | ||
|
||
} // end anonymous namespace | ||
|
||
namespace llvm { | ||
|
||
MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, | ||
raw_ostream &OS, | ||
MCCodeEmitter *Emitter, bool RelaxAll, | ||
bool NoExecStack) { | ||
MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter); | ||
if (RelaxAll) | ||
S->getAssembler().setRelaxAll(true); | ||
if (NoExecStack) | ||
S->getAssembler().setNoExecStack(true); | ||
|
||
// Set bundle-alignment as required by the NaCl ABI for the target. | ||
S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN); | ||
|
||
return S; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
; RUN: llc -filetype=asm -mtriple=mipsel-none-nacl -relocation-model=static \ | ||
; RUN: -O3 < %s | ||
|
||
|
||
; This test tests that NaCl functions are bundle-aligned. | ||
|
||
define void @test0() { | ||
ret void | ||
|
||
; CHECK: .align 4 | ||
; CHECK-NOT: .align | ||
; CHECK-LABEL: test0: | ||
|
||
} | ||
|
||
|
||
; This test tests that blocks that are jumped to through jump table are | ||
; bundle-aligned. | ||
|
||
define i32 @test1(i32 %i) { | ||
entry: | ||
switch i32 %i, label %default [ | ||
i32 0, label %bb1 | ||
i32 1, label %bb2 | ||
i32 2, label %bb3 | ||
i32 3, label %bb4 | ||
] | ||
|
||
bb1: | ||
ret i32 111 | ||
bb2: | ||
ret i32 222 | ||
bb3: | ||
ret i32 333 | ||
bb4: | ||
ret i32 444 | ||
default: | ||
ret i32 555 | ||
|
||
|
||
; CHECK-LABEL: test1: | ||
|
||
; CHECK: .align 4 | ||
; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}: | ||
; CHECK-NEXT: jr $ra | ||
; CHECK-NEXT: addiu $2, $zero, 111 | ||
; CHECK-NEXT: .align 4 | ||
; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}: | ||
; CHECK-NEXT: jr $ra | ||
; CHECK-NEXT: addiu $2, $zero, 222 | ||
; CHECK-NEXT: .align 4 | ||
; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}: | ||
; CHECK-NEXT: jr $ra | ||
; CHECK-NEXT: addiu $2, $zero, 333 | ||
; CHECK-NEXT: .align 4 | ||
; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}: | ||
; CHECK-NEXT: jr $ra | ||
; CHECK-NEXT: addiu $2, $zero, 444 | ||
|
||
} | ||
|
||
|
||
; This test tests that a block whose address is taken is bundle-aligned in NaCl. | ||
|
||
@bb_array = constant [2 x i8*] [i8* blockaddress(@test2, %bb1), | ||
i8* blockaddress(@test2, %bb2)], align 4 | ||
|
||
define i32 @test2(i32 %i) { | ||
entry: | ||
%elementptr = getelementptr inbounds [2 x i8*]* @bb_array, i32 0, i32 %i | ||
%0 = load i8** %elementptr, align 4 | ||
indirectbr i8* %0, [label %bb1, label %bb2] | ||
|
||
bb1: | ||
ret i32 111 | ||
bb2: | ||
ret i32 222 | ||
|
||
|
||
; CHECK-LABEL: test2: | ||
|
||
; Note that there are two consecutive labels - one temporary and one for | ||
; basic block. | ||
|
||
; CHECK: .align 4 | ||
; CHECK-NEXT: ${{[a-zA-Z0-9]+}}: | ||
; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}: | ||
; CHECK-NEXT: jr $ra | ||
; CHECK-NEXT: addiu $2, $zero, 111 | ||
; CHECK-NEXT: .align 4 | ||
; CHECK-NEXT: ${{[a-zA-Z0-9]+}}: | ||
; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}: | ||
; CHECK-NEXT: jr $ra | ||
; CHECK-NEXT: addiu $2, $zero, 222 | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-nacl %s \ | ||
# RUN: | llvm-objdump -triple mipsel -disassemble -no-show-raw-insn - \ | ||
# RUN: | FileCheck %s | ||
|
||
# This test tests that address-masking sandboxing is added when given assembly | ||
# input. | ||
|
||
test1: | ||
.set noreorder | ||
|
||
jr $a0 | ||
nop | ||
jr $ra | ||
nop | ||
|
||
# CHECK-LABEL: test1: | ||
|
||
# CHECK: and $4, $4, $14 | ||
# CHECK-NEXT: jr $4 | ||
|
||
# Check that additional nop is inserted, to align mask and jr to the next | ||
# bundle. | ||
|
||
# CHECK-NEXT: nop | ||
# CHECK-NEXT: nop | ||
|
||
# CHECK: and $ra, $ra, $14 | ||
# CHECK-NEXT: jr $ra |