mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
a41660d2e7
commit
c348a161dc
@ -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));
|
||||
|
@ -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();
|
||||
|
@ -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); }
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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 */
|
||||
|
@ -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); \
|
||||
|
@ -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
|
||||
|
@ -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; \
|
||||
|
@ -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
|
||||
|
@ -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); \
|
||||
|
@ -3234,5 +3234,10 @@ namespace nanojit
|
||||
JMP(pc, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::asm_insert_random_nop() {
|
||||
NanoAssert(0); // not supported
|
||||
}
|
||||
|
||||
}
|
||||
#endif // FEATURE_NANOJIT && FEATURE_SH4
|
||||
|
@ -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); \
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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); \
|
||||
|
@ -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
|
||||
|
@ -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*);\
|
||||
|
@ -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();
|
||||
|
@ -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);\
|
||||
|
@ -93,6 +93,7 @@ namespace nanojit
|
||||
i386_fixed_esp = false;
|
||||
#endif
|
||||
harden_function_alignment = false;
|
||||
harden_nop_insertion = false;
|
||||
|
||||
#if defined(NANOJIT_ARM)
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user