Bug 595034 - nanojit: harden via random no-op instruction insertion (r+nnethercote,wmaddox,edwsmith)

Insert no-op instructions when JIT'ing with the intention of making exploitable
patterns within the generated code less predicable.

--HG--
extra : convert_revision : d3116f2abd879b0b79a6cfb2f7817e36645cf915
This commit is contained in:
Rick Reitmaier 2010-11-01 14:02:18 -07:00
parent a41660d2e7
commit c348a161dc
19 changed files with 97 additions and 8 deletions

View File

@ -1402,6 +1402,12 @@ namespace nanojit
asm_branch(ins->opcode() == LIR_xf, cond, exit);
}
// helper function for nop insertion feature that results in no more
// than 1 no-op instruction insertion every 128-1151 Bytes
static inline uint32_t noiseForNopInsertion(Noise* n) {
return n->getValue(1023) + 128;
}
void Assembler::gen(LirFilter* reader)
{
NanoAssert(_thisfrag->nStaticExits == 0);
@ -1410,6 +1416,10 @@ namespace nanojit
NanoAssert(!error());
// compiler hardening setup
NIns* priorIns = _nIns;
int32_t nopInsertTrigger = hardenNopInsertion(_config) ? noiseForNopInsertion(_noise): 0;
// What's going on here: we're visiting all the LIR instructions in
// the buffer, working strictly backwards in buffer-order, and
// generating machine instructions for them as we go.
@ -1473,6 +1483,28 @@ namespace nanojit
printRegState();
#endif
// compiler hardening technique that inserts no-op instructions in the compiled method when nopInsertTrigger < 0
if (hardenNopInsertion(_config))
{
size_t delta = (uintptr_t)priorIns - (uintptr_t)_nIns; // # bytes that have been emitted since last go-around
if (codeList) {
codeList = codeList;
}
// if no codeList then we know priorIns and _nIns are on same page, otherwise make sure priorIns was not in the previous code block
if (!codeList || !codeList->isInBlock(priorIns)) {
NanoAssert(delta < VMPI_getVMPageSize()); // sanity check
nopInsertTrigger -= delta;
if (nopInsertTrigger < 0)
{
nopInsertTrigger = noiseForNopInsertion(_noise);
asm_insert_random_nop();
PERFM_NVPROF("hardening:nop-insert", 1);
}
}
priorIns = _nIns;
}
LOpcode op = ins->opcode();
switch (op)
{
@ -2033,7 +2065,7 @@ namespace nanojit
}
#endif // VMCFG_VTUNE
case LIR_comment:
case LIR_comment:
// Do nothing.
break;
}
@ -2048,7 +2080,7 @@ namespace nanojit
if (_logc->lcbits & LC_AfterDCE) {
InsBuf b;
LInsPrinter* printer = _thisfrag->lirbuf->printer;
if (ins->isop(LIR_comment))
if (ins->isop(LIR_comment))
outputf("%s", printer->formatIns(&b, ins));
else
outputf(" %s", printer->formatIns(&b, ins));

View File

@ -487,6 +487,7 @@ namespace nanojit
NIns* asm_branch_ov(LOpcode op, NIns* targ);
void asm_switch(LIns* ins, NIns* target);
void asm_jtbl(LIns* ins, NIns** table);
void asm_insert_random_nop();
void emitJumpTable(SwitchInfo* si, NIns* target);
void assignSavedRegs();
void reserveSavedRegs();

View File

@ -88,6 +88,10 @@ namespace nanojit
/** return the whole size of this block including overhead */
size_t blockSize() const { return uintptr_t(end) - uintptr_t(this); }
public:
/** true is the given NIns is contained within this block */
bool isInBlock(NIns* n) { return (n >= this->start() && n < this->end); }
};
/**

View File

@ -2920,5 +2920,9 @@ void Assembler::swapCodeChunks() {
verbose_only( SWAP(size_t, codeBytes, exitBytes); )
}
void Assembler::asm_insert_random_nop() {
NanoAssert(0); // not supported
}
}
#endif /* FEATURE_NANOJIT */

View File

@ -271,6 +271,7 @@ verbose_only( extern const char* shiftNames[]; )
void underrunProtect(int bytes); \
void nativePageReset(); \
void nativePageSetup(); \
bool hardenNopInsertion(const Config& c) { return false; } \
void asm_immd_nochk(Register, int32_t, int32_t); \
void asm_regarg(ArgType, LIns*, Register); \
void asm_stkarg(LIns* p, int stkd); \

View File

@ -2062,6 +2062,12 @@ namespace nanojit
SWAP(NIns*, codeEnd, exitEnd);
verbose_only( SWAP(size_t, codeBytes, exitBytes); )
}
void
Assembler::asm_insert_random_nop() {
NanoAssert(0); // not supported
}
}
#endif // FEATURE_NANOJIT && NANOJIT_MIPS

View File

@ -242,6 +242,7 @@ namespace nanojit {
void nativePageSetup(void); \
void nativePageReset(void); \
void underrunProtect(int bytes); \
bool hardenNopInsertion(const Config& c) { return false; } \
NIns *_nSlot; \
NIns *_nExitSlot; \
int max_out_args; \

View File

@ -1449,6 +1449,10 @@ namespace nanojit
verbose_only( SWAP(size_t, codeBytes, exitBytes); )
}
void Assembler::asm_insert_random_nop() {
NanoAssert(0); // not supported
}
} // namespace nanojit
#endif // FEATURE_NANOJIT && NANOJIT_PPC

View File

@ -295,6 +295,7 @@ namespace nanojit
void underrunProtect(int bytes); \
void nativePageReset(); \
void nativePageSetup(); \
bool hardenNopInsertion(const Config& c) { return false; } \
void br(NIns *addr, int link); \
void br_far(NIns *addr, int link); \
void asm_regarg(ArgType, LIns*, Register); \

View File

@ -3234,5 +3234,10 @@ namespace nanojit
JMP(pc, true);
}
}
void Assembler::asm_insert_random_nop() {
NanoAssert(0); // not supported
}
}
#endif // FEATURE_NANOJIT && FEATURE_SH4

View File

@ -167,6 +167,7 @@ namespace nanojit
void nativePageReset(); \
void nativePageSetup(); \
void underrunProtect(int); \
bool hardenNopInsertion(const Config& c) { return false; } \
bool simplifyOpcode(LOpcode &); \
\
NIns *asm_immi(int, Register, bool force = false); \

View File

@ -1574,5 +1574,9 @@ namespace nanojit
verbose_only( SWAP(size_t, codeBytes, exitBytes); )
}
void Assembler::asm_insert_random_nop() {
NanoAssert(0); // not supported
}
#endif /* FEATURE_NANOJIT */
}

View File

@ -208,6 +208,7 @@ namespace nanojit
void nativePageReset(); \
void nativePageSetup(); \
void underrunProtect(int bytes); \
bool hardenNopInsertion(const Config& c) { return false; } \
void asm_align_code(); \
void asm_cmp(LIns *cond); \
void asm_cmpd(LIns *cond); \

View File

@ -2182,6 +2182,10 @@ namespace nanojit
verbose_only( SWAP(size_t, codeBytes, exitBytes); )
}
void Assembler::asm_insert_random_nop() {
NanoAssert(0); // not supported
}
} // namespace nanojit
#endif // FEATURE_NANOJIT && NANOJIT_X64

View File

@ -373,6 +373,7 @@ namespace nanojit
void underrunProtect(ptrdiff_t bytes); \
void nativePageReset(); \
void nativePageSetup(); \
bool hardenNopInsertion(const Config& c) { return false; } \
void asm_qbinop(LIns*); \
void MR(Register, Register);\
void JMP(NIns*);\

View File

@ -617,8 +617,8 @@ namespace nanojit
inline void Assembler::JMP_indexed(Register x, I32 ss, NIns** addr) {
underrunProtect(7);
IMM32(int32_t(addr));
SIB(ss, REGNUM(x), 5);
IMM32(int32_t(addr));
SIB(ss, REGNUM(x), 5);
MODRM(0, 4, 4); // amode == addr(table + x<<ss)
*(--_nIns) = uint8_t(0xff); // jmp
asm_output("jmp *(%s*%d+%p)", gpn(x), 1 << ss, (void*)addr);
@ -1685,7 +1685,7 @@ namespace nanojit
// asm_cmpd() converts LIR_ltd(a,b) to LIR_gtd(b,a). Likewise
// for LIR_led/LIR_ged.
switch (opcode) {
case LIR_eqd:
case LIR_eqd:
if (ins->oprnd1() == ins->oprnd2()) {
SETNP(r);
} else {
@ -2651,7 +2651,7 @@ namespace nanojit
// skip: ...
underrunProtect(16); // underrun of 7 needed but we write 2 instr --> 16
NIns *skip = _nIns;
JE(targ);
JE(targ);
at = _nIns;
JP(skip);
}
@ -2671,7 +2671,7 @@ namespace nanojit
}
if (!at)
at = _nIns;
at = _nIns;
asm_cmpd(cond);
return at;
@ -2706,7 +2706,7 @@ namespace nanojit
// EQUAL 100 SETNP/JNP succeeds
//
// LIR_eqd, if lsh != rhs;
// ucomisd ZPC outcome (SETP/JP succeeds if P==0,
// ucomisd ZPC outcome (SETP/JP succeeds if P==0,
// SETE/JE succeeds if Z==0)
// ------- --- -------
// UNORDERED 111 SETP/JP succeeds (and skips to fail target)
@ -2864,6 +2864,20 @@ namespace nanojit
}
}
void Assembler::asm_insert_random_nop()
{
// one of a random nop instructions
uint32_t r = _noise->getValue(5);
switch(r)
{
case 0: MR(rEAX,rEAX); break;
case 1: MR(rEDI,rEDI); break;
case 2: MR(rECX,rECX); break;
case 3: LEA(rECX,0,rECX); break;
case 4: LEA(rESP,0,rESP); break;
}
}
void Assembler::asm_ret(LIns* ins)
{
genEpilogue();

View File

@ -193,6 +193,7 @@ namespace nanojit
void nativePageReset();\
void nativePageSetup();\
void underrunProtect(int);\
bool hardenNopInsertion(const Config& c) { return c.harden_nop_insertion; } \
void asm_immi(Register r, int32_t val, bool canClobberCCs);\
void asm_stkarg(LIns* p, int32_t& stkd);\
void asm_farg(LIns*, int32_t& stkd);\

View File

@ -93,6 +93,7 @@ namespace nanojit
i386_fixed_esp = false;
#endif
harden_function_alignment = false;
harden_nop_insertion = false;
#if defined(NANOJIT_ARM)

View File

@ -97,6 +97,9 @@ namespace nanojit
// If true, compiler will insert a random amount of space in between functions (x86-32 only)
uint32_t harden_function_alignment:1;
// If true, compiler will insert randomly choosen no-op instructions at random locations within a compiled method (x86-32 only)
uint32_t harden_nop_insertion:1;
};
}