aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/insn.h
diff options
context:
space:
mode:
authorDave Hansen <dave.hansen@linux.intel.com>2014-11-14 10:39:57 -0500
committerThomas Gleixner <tglx@linutronix.de>2014-11-17 18:58:52 -0500
commit6ba48ff46f764414f979d2eacb23c4e6296bcc95 (patch)
treec1e1ea9fd3e1ef9c396e36c5d446fa6f74d97224 /arch/x86/include/asm/insn.h
parent206c5f60a3d902bc4b56dab2de3e88de5eb06108 (diff)
x86: Remove arbitrary instruction size limit in instruction decoder
The current x86 instruction decoder steps along through the instruction stream but always ensures that it never steps farther than the largest possible instruction size (MAX_INSN_SIZE). The MPX code is now going to be doing some decoding of userspace instructions. We copy those from userspace in to the kernel and they're obviously completely untrusted coming from userspace. In addition to the constraint that instructions can only be so long, we also have to be aware of how long the buffer is that came in from userspace. This _looks_ to be similar to what the perf and kprobes is doing, but it's unclear to me whether they are affected. The whole reason we need this is that it is perfectly valid to be executing an instruction within MAX_INSN_SIZE bytes of an unreadable page. We should be able to gracefully handle short reads in those cases. This adds support to the decoder to record how long the buffer being decoded is and to refuse to "validate" the instruction if we would have gone over the end of the buffer to decode it. The kprobes code probably needs to be looked at here a bit more carefully. This patch still respects the MAX_INSN_SIZE limit there but the kprobes code does look like it might be able to be a bit more strict than it currently is. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Acked-by: Jim Keniston <jkenisto@us.ibm.com> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: x86@kernel.org Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Cc: "David S. Miller" <davem@davemloft.net> Link: http://lkml.kernel.org/r/20141114153957.E6B01535@viggo.jf.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/include/asm/insn.h')
-rw-r--r--arch/x86/include/asm/insn.h10
1 files changed, 6 insertions, 4 deletions
diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
index 48eb30a86062..47f29b1d1846 100644
--- a/arch/x86/include/asm/insn.h
+++ b/arch/x86/include/asm/insn.h
@@ -65,6 +65,7 @@ struct insn {
65 unsigned char x86_64; 65 unsigned char x86_64;
66 66
67 const insn_byte_t *kaddr; /* kernel address of insn to analyze */ 67 const insn_byte_t *kaddr; /* kernel address of insn to analyze */
68 const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */
68 const insn_byte_t *next_byte; 69 const insn_byte_t *next_byte;
69}; 70};
70 71
@@ -96,7 +97,7 @@ struct insn {
96#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ 97#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */
97#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ 98#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */
98 99
99extern void insn_init(struct insn *insn, const void *kaddr, int x86_64); 100extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64);
100extern void insn_get_prefixes(struct insn *insn); 101extern void insn_get_prefixes(struct insn *insn);
101extern void insn_get_opcode(struct insn *insn); 102extern void insn_get_opcode(struct insn *insn);
102extern void insn_get_modrm(struct insn *insn); 103extern void insn_get_modrm(struct insn *insn);
@@ -115,12 +116,13 @@ static inline void insn_get_attribute(struct insn *insn)
115extern int insn_rip_relative(struct insn *insn); 116extern int insn_rip_relative(struct insn *insn);
116 117
117/* Init insn for kernel text */ 118/* Init insn for kernel text */
118static inline void kernel_insn_init(struct insn *insn, const void *kaddr) 119static inline void kernel_insn_init(struct insn *insn,
120 const void *kaddr, int buf_len)
119{ 121{
120#ifdef CONFIG_X86_64 122#ifdef CONFIG_X86_64
121 insn_init(insn, kaddr, 1); 123 insn_init(insn, kaddr, buf_len, 1);
122#else /* CONFIG_X86_32 */ 124#else /* CONFIG_X86_32 */
123 insn_init(insn, kaddr, 0); 125 insn_init(insn, kaddr, buf_len, 0);
124#endif 126#endif
125} 127}
126 128