--- b/arch/x86/include/asm/insn.h | 1 b/arch/x86/include/asm/mpx.h | 14 --- b/arch/x86/kernel/mpx.c | 183 ++---------------------------------------- b/arch/x86/lib/insn.c | 43 +++++++++ 4 files changed, 56 insertions(+), 185 deletions(-) diff -puN arch/x86/kernel/mpx.c~consolidate-instruction-decoding arch/x86/kernel/mpx.c --- a/arch/x86/kernel/mpx.c~consolidate-instruction-decoding 2014-06-19 09:53:53.894441788 -0700 +++ b/arch/x86/kernel/mpx.c 2014-06-19 09:53:53.909442460 -0700 @@ -3,6 +3,7 @@ #include #include #include +#include #include /* @@ -59,7 +60,7 @@ int mpx_unregister(struct task_struct *t } typedef enum {REG_TYPE_RM, REG_TYPE_INDEX, REG_TYPE_BASE} reg_type_t; -static unsigned long get_reg(struct mpx_insn *insn, struct pt_regs *regs, +static unsigned long get_reg(struct insn *insn, struct pt_regs *regs, reg_type_t type) { int regno = 0; @@ -118,7 +119,7 @@ static unsigned long get_reg(struct mpx_ * for rm=3 returning the content of the rm reg * for rm!=3 calculates the address using SIB and Disp */ -static unsigned long get_addr_ref(struct mpx_insn *insn, struct pt_regs *regs) +static unsigned long get_addr_ref(struct insn *insn, struct pt_regs *regs) { unsigned long addr; unsigned long base; @@ -142,182 +143,22 @@ static unsigned long get_addr_ref(struct return addr; } -/* Verify next sizeof(t) bytes can be on the same instruction */ -#define validate_next(t, insn, n) \ - ((insn)->next_byte + sizeof(t) + n - (insn)->kaddr <= (insn)->limit) - -#define __get_next(t, insn) \ -({ \ - t r = *(t *)insn->next_byte; \ - insn->next_byte += sizeof(t); \ - r; \ -}) - -#define __peek_next(t, insn) \ -({ \ - t r = *(t *)insn->next_byte; \ - r; \ -}) - -#define get_next(t, insn) \ -({ \ - if (unlikely(!validate_next(t, insn, 0))) \ - goto err_out; \ - __get_next(t, insn); \ -}) - -#define peek_next(t, insn) \ -({ \ - if (unlikely(!validate_next(t, insn, 0))) \ - goto err_out; \ - __peek_next(t, insn); \ -}) - -static void mpx_insn_get_prefixes(struct mpx_insn *insn) -{ - unsigned char b; - - /* Decode legacy prefix and REX prefix */ - b = peek_next(unsigned char, insn); - while (b != 0x0f) { - /* - * look for a rex prefix - * a REX prefix cannot be followed by a legacy prefix. - */ - if (insn->x86_64 && ((b&0xf0) == 0x40)) { - insn->rex_prefix.value = b; - insn->rex_prefix.nbytes = 1; - insn->next_byte++; - break; - } - - /* check the other legacy prefixes */ - switch (b) { - case 0xf2: - case 0xf3: - case 0xf0: - case 0x64: - case 0x65: - case 0x2e: - case 0x3e: - case 0x26: - case 0x36: - case 0x66: - case 0x67: - insn->next_byte++; - break; - default: /* everything else is garbage */ - goto err_out; - } - b = peek_next(unsigned char, insn); - } - -err_out: - return; -} - -static void mpx_insn_get_modrm(struct mpx_insn *insn) -{ - insn->modrm.value = get_next(unsigned char, insn); - insn->modrm.nbytes = 1; - -err_out: - return; -} - -static void mpx_insn_get_sib(struct mpx_insn *insn) -{ - unsigned char modrm = (unsigned char)insn->modrm.value; - - if (X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { - insn->sib.value = get_next(unsigned char, insn); - insn->sib.nbytes = 1; - } - -err_out: - return; -} - -static void mpx_insn_get_displacement(struct mpx_insn *insn) -{ - unsigned char mod, rm, base; - - /* - * Interpreting the modrm byte: - * mod = 00 - no displacement fields (exceptions below) - * mod = 01 - 1-byte displacement field - * mod = 10 - displacement field is 4 bytes - * mod = 11 - no memory operand - * - * mod != 11, r/m = 100 - SIB byte exists - * mod = 00, SIB base = 101 - displacement field is 4 bytes - * mod = 00, r/m = 101 - rip-relative addressing, displacement - * field is 4 bytes - */ - mod = X86_MODRM_MOD(insn->modrm.value); - rm = X86_MODRM_RM(insn->modrm.value); - base = X86_SIB_BASE(insn->sib.value); - if (mod == 3) - return; - if (mod == 1) { - insn->displacement.value = get_next(unsigned char, insn); - insn->displacement.nbytes = 1; - } else if ((mod == 0 && rm == 5) || mod == 2 || - (mod == 0 && base == 5)) { - insn->displacement.value = get_next(int, insn); - insn->displacement.nbytes = 4; - } - -err_out: - return; -} - -static void mpx_insn_init(struct mpx_insn *insn, struct pt_regs *regs) -{ - unsigned char buf[MAX_MPX_INSN_SIZE]; - int bytes; - - memset(insn, 0, sizeof(*insn)); - - bytes = copy_from_user(buf, (void __user *)regs->ip, MAX_MPX_INSN_SIZE); - insn->limit = MAX_MPX_INSN_SIZE - bytes; - insn->kaddr = buf; - insn->next_byte = buf; - - /* - * In 64-bit Mode, all Intel MPX instructions use 64-bit - * operands for bounds and 64 bit addressing, i.e. REX.W & - * 67H have no effect on data or address size. - * - * In compatibility and legacy modes (including 16-bit code - * segments, real and virtual 8086 modes) all Intel MPX - * instructions use 32-bit operands for bounds and 32 bit - * addressing. - */ -#ifdef CONFIG_X86_64 - insn->x86_64 = 1; - insn->addr_bytes = 8; -#else - insn->x86_64 = 0; - insn->addr_bytes = 4; -#endif -} - -static unsigned long mpx_insn_decode(struct mpx_insn *insn, +static unsigned long insn_decode(struct insn *insn, struct pt_regs *regs) { - mpx_insn_init(insn, regs); + int is_64bit = IS_ENABLED(CONFIG_X86_64) && !test_thread_flag(TIF_IA32); + insn_init(insn, regs, is_64bit); /* * In this case, we only need decode bndcl/bndcn/bndcu, * so we can use private diassembly interfaces to get * prefixes, modrm, sib, displacement, etc.. */ - mpx_insn_get_prefixes(insn); + insn_get_prefixes(insn); insn->next_byte += 2; /* ignore opcode */ - mpx_insn_get_modrm(insn); - mpx_insn_get_sib(insn); - mpx_insn_get_displacement(insn); + insn_get_modrm(insn); + insn_get_sib(insn); + insn_get_displacement(insn); return get_addr_ref(insn, regs); } @@ -390,11 +231,11 @@ int do_mpx_bt_fault(struct xsave_struct void do_mpx_bounds(struct pt_regs *regs, siginfo_t *info, struct xsave_struct *xsave_buf) { - struct mpx_insn insn; + struct insn insn; uint8_t bndregno; unsigned long addr_vio; - addr_vio = mpx_insn_decode(&insn, regs); + addr_vio = insn_decode(&insn, regs); bndregno = X86_MODRM_REG(insn.modrm.value); if (bndregno > 3) diff -puN arch/x86/include/asm/mpx.h~consolidate-instruction-decoding arch/x86/include/asm/mpx.h --- a/arch/x86/include/asm/mpx.h~consolidate-instruction-decoding 2014-06-19 09:53:53.895441833 -0700 +++ b/arch/x86/include/asm/mpx.h 2014-06-19 09:53:53.909442460 -0700 @@ -53,20 +53,6 @@ #define MPX_BNDCFG_ENABLE_FLAG 0x1 #define MPX_BD_ENTRY_VALID_FLAG 0x1 -struct mpx_insn { - struct insn_field rex_prefix; /* REX prefix */ - struct insn_field modrm; - struct insn_field sib; - struct insn_field displacement; - - unsigned char addr_bytes; /* effective address size */ - unsigned char limit; - unsigned char x86_64; - - const unsigned char *kaddr; /* kernel address of insn to analyze */ - const unsigned char *next_byte; -}; - #define MAX_MPX_INSN_SIZE 15 unsigned long mpx_mmap(unsigned long len); diff -puN arch/x86/include/asm/insn.h~consolidate-instruction-decoding arch/x86/include/asm/insn.h --- a/arch/x86/include/asm/insn.h~consolidate-instruction-decoding 2014-06-19 09:53:53.897441922 -0700 +++ b/arch/x86/include/asm/insn.h 2014-06-19 09:53:53.910442505 -0700 @@ -98,6 +98,7 @@ struct insn { extern void insn_init(struct insn *insn, const void *kaddr, int x86_64); extern void insn_get_prefixes(struct insn *insn); +extern void mpx_insn_get_prefixes(struct insn *insn); extern void insn_get_opcode(struct insn *insn); extern void insn_get_modrm(struct insn *insn); extern void insn_get_sib(struct insn *insn); diff -puN arch/x86/lib/insn.c~consolidate-instruction-decoding arch/x86/lib/insn.c --- a/arch/x86/lib/insn.c~consolidate-instruction-decoding 2014-06-19 09:53:53.899442011 -0700 +++ b/arch/x86/lib/insn.c 2014-06-19 09:53:53.910442505 -0700 @@ -63,6 +63,49 @@ void insn_init(struct insn *insn, const insn->addr_bytes = 4; } +void mpx_insn_get_prefixes(struct insn *insn) +{ + unsigned char b; + + /* Decode legacy prefix and REX prefix */ + b = peek_next(unsigned char, insn); + while (b != 0x0f) { + /* + * look for a rex prefix + * a REX prefix cannot be followed by a legacy prefix. + */ + if (insn->x86_64 && ((b&0xf0) == 0x40)) { + insn->prefixes.value = b; + insn->prefixes.nbytes = 1; + insn->next_byte++; + break; + } + + /* check the other legacy prefixes */ + switch (b) { + case 0xf2: + case 0xf3: + case 0xf0: + case 0x64: + case 0x65: + case 0x2e: + case 0x3e: + case 0x26: + case 0x36: + case 0x66: + case 0x67: + insn->next_byte++; + break; + default: /* everything else is garbage */ + goto err_out; + } + b = peek_next(unsigned char, insn); + } + +err_out: + return; +} + /** * insn_get_prefixes - scan x86 instruction prefix bytes * @insn: &struct insn containing instruction _