x86_table: Mark state-altering instructions as JIT block boundaries

These instructions, if included within a compiled JIT block, may alter the
state_flags of a block entry (such as whether flat segmentation is used or not),
which may invalidate the block that is running - this caused bugs in OpenBSD
because of a block like this being compiled:

0xF81F2: 8E DB                mov ds, bx
0xF81F4: 8E D3                mov ss, bx
0xF81F6: 66 8B 26 B8 F5       mov esp, dword ptr [0xf5b8] <--
0xF81FB: 66 89 36 B8 F5       mov dword ptr [0xf5b8], esi <--

The memory accesses implicitly use DS. If we include flat-segmenetation as a
flag within state_flags and optimize calls to get_seg based on it, this behavior
would cause issues (and did, in OpenBSD).

By marking these instructions as block boundaries, we remediate that issue.
This commit is contained in:
Amaan Cheval 2018-04-02 13:40:06 +05:30 committed by Fabian
parent 4d87bebee9
commit 41c8241d5e
3 changed files with 14 additions and 5 deletions

View file

@ -19,9 +19,9 @@ const encodings = [
{ opcode: 0x0E, os: 1, skip: 1, },
{ opcode: 0x0F, os: 1, prefix: 1, },
{ opcode: 0x16, os: 1, skip: 1, },
{ opcode: 0x17, os: 1, skip: 1, },
{ opcode: 0x17, block_boundary: 1, os: 1, skip: 1, },
{ opcode: 0x1E, os: 1, skip: 1, },
{ opcode: 0x1F, os: 1, skip: 1, },
{ opcode: 0x1F, block_boundary: 1, os: 1, skip: 1, },
{ opcode: 0x26, prefix: 1, },
{ opcode: 0x27, nonfaulting: 1, mask_flags: of, },
{ opcode: 0x2E, prefix: 1, },
@ -97,7 +97,7 @@ const encodings = [
{ opcode: 0x8C, os: 1, e: 1, skip: 1, },
{ opcode: 0x8D, nonfaulting: 1, os: 1, e: 1, only_mem: 1, requires_prefix_call: 1, custom: 1, }, // lea
{ opcode: 0x8E, e: 1, skip: 1, },
{ opcode: 0x8E, block_boundary: 1, e: 1, skip: 1, },
{ opcode: 0x8F, os: 1, e: 1, fixed_g: 0, requires_prefix_call: 1, }, // pop r/m
{ opcode: 0x90, nonfaulting: 1, },
@ -144,7 +144,7 @@ const encodings = [
{ opcode: 0xC3, block_boundary: 1, os: 1, skip: 1, },
{ opcode: 0xC4, os: 1, e: 1, skip: 1, },
{ opcode: 0xC5, os: 1, e: 1, skip: 1, },
{ opcode: 0xC5, block_boundary: 1, os: 1, e: 1, skip: 1, },
{ opcode: 0xC6, e: 1, fixed_g: 0, nonfaulting: 1, imm8: 1, },
{ opcode: 0xC7, os: 1, e: 1, fixed_g: 0, nonfaulting: 1, imm1632: 1, },
@ -367,7 +367,7 @@ const encodings = [
{ opcode: 0x0FC7, e: 1, fixed_g: 1, only_mem: 1, }, // cmpxchg8b (memory)
{ opcode: 0x0FC7, e: 1, fixed_g: 6, only_reg: 1, skip: 1, }, // rdrand
{ opcode: 0x0FB2, os: 1, e: 1, skip: 1, }, // lss, lfs, lgs
{ opcode: 0x0FB2, block_boundary: 1, os: 1, e: 1, skip: 1, }, // lss, lfs, lgs
{ opcode: 0x0FB4, os: 1, e: 1, skip: 1, },
{ opcode: 0x0FB5, os: 1, e: 1, skip: 1, },

View file

@ -89,12 +89,14 @@ void instr16_17() {
adjust_stack_reg(2);
//clear_prefixes();
//cycle_internal();
altered_state();
}
void instr32_17() {
switch_seg(SS, safe_read32s(get_stack_pointer(0)) & 0xFFFF);
adjust_stack_reg(4);
//clear_prefixes();
//cycle_internal();
altered_state();
}
DEFINE_MODRM_INSTR_READ_WRITE_8(instr_18, sbb8(___, read_reg8(r)))
@ -113,10 +115,12 @@ void instr32_1E() { push32(sreg[DS]); }
void instr16_1F() {
switch_seg(DS, safe_read16(get_stack_pointer(0)));
adjust_stack_reg(2);
altered_state();
}
void instr32_1F() {
switch_seg(DS, safe_read32s(get_stack_pointer(0)) & 0xFFFF);
adjust_stack_reg(4);
altered_state();
}
DEFINE_MODRM_INSTR_READ_WRITE_8(instr_20, and8(___, read_reg8(r)))
@ -567,6 +571,7 @@ void instr_8E_helper(int32_t data, int32_t mod)
{
dbg_log("mov sreg #ud");
}
altered_state();
}
DEFINE_MODRM_INSTR_READ16(instr_8E, instr_8E_helper(___, r))
@ -899,10 +904,12 @@ void instr32_C4_mem(int32_t addr, int32_t r) {
void instr16_C5_reg(int32_t _unused1, int32_t _unused2) { trigger_ud(); }
void instr16_C5_mem(int32_t addr, int32_t r) {
lss16(addr, get_reg16_index(r), DS);
altered_state();
}
void instr32_C5_reg(int32_t _unused1, int32_t _unused2) { trigger_ud(); }
void instr32_C5_mem(int32_t addr, int32_t r) {
lss32(addr, r, DS);
altered_state();
}
void instr_C6_0_reg(int32_t r, int32_t imm) { write_reg8(r, imm); }

View file

@ -2241,10 +2241,12 @@ void instr32_0FB1_mem(int32_t addr, int32_t r) {
void instr16_0FB2_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
void instr16_0FB2_mem(int32_t addr, int32_t r) {
lss16(addr, get_reg16_index(r), SS);
altered_state();
}
void instr32_0FB2_reg(int32_t unused, int32_t unused2) { trigger_ud(); }
void instr32_0FB2_mem(int32_t addr, int32_t r) {
lss32(addr, r, SS);
altered_state();
}
void instr16_0FB3_reg(int32_t r1, int32_t r2) { write_reg16(r1, btr_reg(read_reg16(r1), read_reg16(r2) & 15)); }