aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Hansen <dave.hansen@linux.intel.com>2014-11-14 10:18:28 -0500
committerThomas Gleixner <tglx@linutronix.de>2014-11-17 18:58:53 -0500
commitfcc7ffd67991b63029ca54925644753d534ddc5f (patch)
tree52888ddf57f603b98884264c53f7327bdd10750b
parent57319d80e1d328e34cb24868a4f4405661485e30 (diff)
x86, mpx: Decode MPX instruction to get bound violation information
This patch sets bound violation fields of siginfo struct in #BR exception handler by decoding the user instruction and constructing the faulting pointer. We have to be very careful when decoding these instructions. They are completely controlled by userspace and may be changed at any time up to and including the point where we try to copy them in to the kernel. They may or may not be MPX instructions and could be completely invalid for all we know. Note: This code is based on Qiaowei Ren's specialized MPX decoder, but uses the generic decoder whenever possible. It was tested for robustness by generating a completely random data stream and trying to decode that stream. I also unmapped random pages inside the stream to test the "partial instruction" short read code. We kzalloc() the siginfo instead of stack allocating it because we need to memset() it anyway, and doing this makes it much more clear when it got initialized by the MPX instruction decoder. Changes from the old decoder: * Use the generic decoder instead of custom functions. Saved ~70 lines of code overall. * Remove insn->addr_bytes code (never used??) * Make sure never to possibly overflow the regoff[] array, plus check the register range correctly in 32 and 64-bit modes. * Allow get_reg() to return an error and have mpx_get_addr_ref() handle when it sees errors. * Only call insn_get_*() near where we actually use the values instead if trying to call them all at once. * Handle short reads from copy_from_user() and check the actual number of read bytes against what we expect from insn_get_length(). If a read stops in the middle of an instruction, we error out. * Actually check the opcodes intead of ignoring them. * Dynamically kzalloc() siginfo_t so we don't leak any stack data. * Detect and handle decoder failures instead of ignoring them. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Based-on-patch-by: Qiaowei Ren <qiaowei.ren@intel.com> Cc: linux-mm@kvack.org Cc: linux-mips@linux-mips.org Cc: Dave Hansen <dave@sr71.net> Link: http://lkml.kernel.org/r/20141114151828.5BDD0915@viggo.jf.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/include/asm/mpx.h12
-rw-r--r--arch/x86/mm/mpx.c237
2 files changed, 249 insertions, 0 deletions
diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h
index 7d7c5f54cc5f..35bcb1cddf40 100644
--- a/arch/x86/include/asm/mpx.h
+++ b/arch/x86/include/asm/mpx.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <asm/ptrace.h> 5#include <asm/ptrace.h>
6#include <asm/insn.h>
6 7
7#ifdef CONFIG_X86_64 8#ifdef CONFIG_X86_64
8 9
@@ -33,4 +34,15 @@
33 34
34#define MPX_BNDSTA_ERROR_CODE 0x3 35#define MPX_BNDSTA_ERROR_CODE 0x3
35 36
37#ifdef CONFIG_X86_INTEL_MPX
38siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
39 struct xsave_struct *xsave_buf);
40#else
41static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
42 struct xsave_struct *xsave_buf)
43{
44 return NULL;
45}
46#endif /* CONFIG_X86_INTEL_MPX */
47
36#endif /* _ASM_X86_MPX_H */ 48#endif /* _ASM_X86_MPX_H */
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
index 72d13b0779a2..9009e094d686 100644
--- a/arch/x86/mm/mpx.c
+++ b/arch/x86/mm/mpx.c
@@ -6,6 +6,7 @@
6 * Dave Hansen <dave.hansen@intel.com> 6 * Dave Hansen <dave.hansen@intel.com>
7 */ 7 */
8#include <linux/kernel.h> 8#include <linux/kernel.h>
9#include <linux/slab.h>
9#include <linux/syscalls.h> 10#include <linux/syscalls.h>
10#include <linux/sched/sysctl.h> 11#include <linux/sched/sysctl.h>
11 12
@@ -84,3 +85,239 @@ out:
84 up_write(&mm->mmap_sem); 85 up_write(&mm->mmap_sem);
85 return ret; 86 return ret;
86} 87}
88
89enum reg_type {
90 REG_TYPE_RM = 0,
91 REG_TYPE_INDEX,
92 REG_TYPE_BASE,
93};
94
95static unsigned long get_reg_offset(struct insn *insn, struct pt_regs *regs,
96 enum reg_type type)
97{
98 int regno = 0;
99
100 static const int regoff[] = {
101 offsetof(struct pt_regs, ax),
102 offsetof(struct pt_regs, cx),
103 offsetof(struct pt_regs, dx),
104 offsetof(struct pt_regs, bx),
105 offsetof(struct pt_regs, sp),
106 offsetof(struct pt_regs, bp),
107 offsetof(struct pt_regs, si),
108 offsetof(struct pt_regs, di),
109#ifdef CONFIG_X86_64
110 offsetof(struct pt_regs, r8),
111 offsetof(struct pt_regs, r9),
112 offsetof(struct pt_regs, r10),
113 offsetof(struct pt_regs, r11),
114 offsetof(struct pt_regs, r12),
115 offsetof(struct pt_regs, r13),
116 offsetof(struct pt_regs, r14),
117 offsetof(struct pt_regs, r15),
118#endif
119 };
120 int nr_registers = ARRAY_SIZE(regoff);
121 /*
122 * Don't possibly decode a 32-bit instructions as
123 * reading a 64-bit-only register.
124 */
125 if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
126 nr_registers -= 8;
127
128 switch (type) {
129 case REG_TYPE_RM:
130 regno = X86_MODRM_RM(insn->modrm.value);
131 if (X86_REX_B(insn->rex_prefix.value) == 1)
132 regno += 8;
133 break;
134
135 case REG_TYPE_INDEX:
136 regno = X86_SIB_INDEX(insn->sib.value);
137 if (X86_REX_X(insn->rex_prefix.value) == 1)
138 regno += 8;
139 break;
140
141 case REG_TYPE_BASE:
142 regno = X86_SIB_BASE(insn->sib.value);
143 if (X86_REX_B(insn->rex_prefix.value) == 1)
144 regno += 8;
145 break;
146
147 default:
148 pr_err("invalid register type");
149 BUG();
150 break;
151 }
152
153 if (regno > nr_registers) {
154 WARN_ONCE(1, "decoded an instruction with an invalid register");
155 return -EINVAL;
156 }
157 return regoff[regno];
158}
159
160/*
161 * return the address being referenced be instruction
162 * for rm=3 returning the content of the rm reg
163 * for rm!=3 calculates the address using SIB and Disp
164 */
165static void __user *mpx_get_addr_ref(struct insn *insn, struct pt_regs *regs)
166{
167 unsigned long addr, addr_offset;
168 unsigned long base, base_offset;
169 unsigned long indx, indx_offset;
170 insn_byte_t sib;
171
172 insn_get_modrm(insn);
173 insn_get_sib(insn);
174 sib = insn->sib.value;
175
176 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
177 addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
178 if (addr_offset < 0)
179 goto out_err;
180 addr = regs_get_register(regs, addr_offset);
181 } else {
182 if (insn->sib.nbytes) {
183 base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
184 if (base_offset < 0)
185 goto out_err;
186
187 indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
188 if (indx_offset < 0)
189 goto out_err;
190
191 base = regs_get_register(regs, base_offset);
192 indx = regs_get_register(regs, indx_offset);
193 addr = base + indx * (1 << X86_SIB_SCALE(sib));
194 } else {
195 addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
196 if (addr_offset < 0)
197 goto out_err;
198 addr = regs_get_register(regs, addr_offset);
199 }
200 addr += insn->displacement.value;
201 }
202 return (void __user *)addr;
203out_err:
204 return (void __user *)-1;
205}
206
207static int mpx_insn_decode(struct insn *insn,
208 struct pt_regs *regs)
209{
210 unsigned char buf[MAX_INSN_SIZE];
211 int x86_64 = !test_thread_flag(TIF_IA32);
212 int not_copied;
213 int nr_copied;
214
215 not_copied = copy_from_user(buf, (void __user *)regs->ip, sizeof(buf));
216 nr_copied = sizeof(buf) - not_copied;
217 /*
218 * The decoder _should_ fail nicely if we pass it a short buffer.
219 * But, let's not depend on that implementation detail. If we
220 * did not get anything, just error out now.
221 */
222 if (!nr_copied)
223 return -EFAULT;
224 insn_init(insn, buf, nr_copied, x86_64);
225 insn_get_length(insn);
226 /*
227 * copy_from_user() tries to get as many bytes as we could see in
228 * the largest possible instruction. If the instruction we are
229 * after is shorter than that _and_ we attempt to copy from
230 * something unreadable, we might get a short read. This is OK
231 * as long as the read did not stop in the middle of the
232 * instruction. Check to see if we got a partial instruction.
233 */
234 if (nr_copied < insn->length)
235 return -EFAULT;
236
237 insn_get_opcode(insn);
238 /*
239 * We only _really_ need to decode bndcl/bndcn/bndcu
240 * Error out on anything else.
241 */
242 if (insn->opcode.bytes[0] != 0x0f)
243 goto bad_opcode;
244 if ((insn->opcode.bytes[1] != 0x1a) &&
245 (insn->opcode.bytes[1] != 0x1b))
246 goto bad_opcode;
247
248 return 0;
249bad_opcode:
250 return -EINVAL;
251}
252
253/*
254 * If a bounds overflow occurs then a #BR is generated. This
255 * function decodes MPX instructions to get violation address
256 * and set this address into extended struct siginfo.
257 *
258 * Note that this is not a super precise way of doing this.
259 * Userspace could have, by the time we get here, written
260 * anything it wants in to the instructions. We can not
261 * trust anything about it. They might not be valid
262 * instructions or might encode invalid registers, etc...
263 *
264 * The caller is expected to kfree() the returned siginfo_t.
265 */
266siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
267 struct xsave_struct *xsave_buf)
268{
269 struct insn insn;
270 uint8_t bndregno;
271 int err;
272 siginfo_t *info;
273
274 err = mpx_insn_decode(&insn, regs);
275 if (err)
276 goto err_out;
277
278 /*
279 * We know at this point that we are only dealing with
280 * MPX instructions.
281 */
282 insn_get_modrm(&insn);
283 bndregno = X86_MODRM_REG(insn.modrm.value);
284 if (bndregno > 3) {
285 err = -EINVAL;
286 goto err_out;
287 }
288 info = kzalloc(sizeof(*info), GFP_KERNEL);
289 if (!info) {
290 err = -ENOMEM;
291 goto err_out;
292 }
293 /*
294 * The registers are always 64-bit, but the upper 32
295 * bits are ignored in 32-bit mode. Also, note that the
296 * upper bounds are architecturally represented in 1's
297 * complement form.
298 *
299 * The 'unsigned long' cast is because the compiler
300 * complains when casting from integers to different-size
301 * pointers.
302 */
303 info->si_lower = (void __user *)(unsigned long)
304 (xsave_buf->bndreg[bndregno].lower_bound);
305 info->si_upper = (void __user *)(unsigned long)
306 (~xsave_buf->bndreg[bndregno].upper_bound);
307 info->si_addr_lsb = 0;
308 info->si_signo = SIGSEGV;
309 info->si_errno = 0;
310 info->si_code = SEGV_BNDERR;
311 info->si_addr = mpx_get_addr_ref(&insn, regs);
312 /*
313 * We were not able to extract an address from the instruction,
314 * probably because there was something invalid in it.
315 */
316 if (info->si_addr == (void *)-1) {
317 err = -EINVAL;
318 goto err_out;
319 }
320 return info;
321err_out:
322 return ERR_PTR(err);
323}