| From 91e5ed49fca09c2b83b262b9757d1376ee2b46c3 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@amacapital.net> |
| Date: Tue, 27 Jan 2015 16:06:02 -0800 |
| Subject: x86/asm/decoder: Fix and enforce max instruction size in the insn decoder |
| |
| From: Andy Lutomirski <luto@amacapital.net> |
| |
| commit 91e5ed49fca09c2b83b262b9757d1376ee2b46c3 upstream. |
| |
| x86 instructions cannot exceed 15 bytes, and the instruction |
| decoder should enforce that. Prior to 6ba48ff46f76, the |
| instruction length limit was implicitly set to 16, which was an |
| approximation of 15, but there is currently no limit at all. |
| |
| Fix MAX_INSN_SIZE (it should be 15, not 16), and fix the decoder |
| to reject instructions that exceed MAX_INSN_SIZE. |
| |
| Other than potentially confusing some of the decoder sanity |
| checks, I'm not aware of any actual problems that omitting this |
| check would cause, nor am I aware of any practical problems |
| caused by the MAX_INSN_SIZE error. |
| |
| Signed-off-by: Andy Lutomirski <luto@amacapital.net> |
| Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> |
| Cc: Dave Hansen <dave.hansen@linux.intel.com> |
| Fixes: 6ba48ff46f76 ("x86: Remove arbitrary instruction size limit ... |
| Link: http://lkml.kernel.org/r/f8f0bc9b8c58cfd6830f7d88400bf1396cbdcd0f.1422403511.git.luto@amacapital.net |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/include/asm/insn.h | 2 +- |
| arch/x86/lib/insn.c | 7 +++++++ |
| 2 files changed, 8 insertions(+), 1 deletion(-) |
| |
| --- a/arch/x86/include/asm/insn.h |
| +++ b/arch/x86/include/asm/insn.h |
| @@ -69,7 +69,7 @@ struct insn { |
| const insn_byte_t *next_byte; |
| }; |
| |
| -#define MAX_INSN_SIZE 16 |
| +#define MAX_INSN_SIZE 15 |
| |
| #define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) |
| #define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) |
| --- a/arch/x86/lib/insn.c |
| +++ b/arch/x86/lib/insn.c |
| @@ -52,6 +52,13 @@ |
| */ |
| void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) |
| { |
| + /* |
| + * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid |
| + * even if the input buffer is long enough to hold them. |
| + */ |
| + if (buf_len > MAX_INSN_SIZE) |
| + buf_len = MAX_INSN_SIZE; |
| + |
| memset(insn, 0, sizeof(*insn)); |
| insn->kaddr = kaddr; |
| insn->end_kaddr = kaddr + buf_len; |