aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Hansen <dave.hansen@linux.intel.com>2015-06-07 14:37:01 -0400
committerIngo Molnar <mingo@kernel.org>2015-06-09 06:24:30 -0400
commita84eeaa96b36a03188e1423349669c108d3a4bd7 (patch)
tree13f38f8a3859b26458b21cce4cf5ee22851313fb
parent04cd027bcba1ead7bfe39e7f1c6f4d993c4c3323 (diff)
x86/mpx: Use the new get_xsave_field_ptr()API
The MPX registers (bndcsr/bndcfgu/bndstatus) are not directly accessible via normal instructions. They essentially act as if they were floating point registers and are saved/restored along with those registers. There are two main paths in the MPX code where we care about the contents of these registers: 1. #BR (bounds) faults 2. the prctl() code where we are setting MPX up Both of those paths _might_ be called without the FPU having been used. That means that 'tsk->thread.fpu.state' might never be allocated. Also, fpu_save_init() is not preempt-safe. It was a bug to call it without disabling preemption. The new get_xsave_addr() calls unlazy_fpu() instead and properly disables preemption. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Dave Hansen <dave@sr71.net> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rik van Riel <riel@redhat.com> Cc: Suresh Siddha <sbsiddha@gmail.com> Cc: bp@alien8.de Link: http://lkml.kernel.org/r/20150607183701.BC0D37CF@viggo.jf.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/mpx.h8
-rw-r--r--arch/x86/kernel/traps.c17
-rw-r--r--arch/x86/mm/mpx.c30
3 files changed, 27 insertions, 28 deletions
diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h
index f3c1b71d4fae..39f2d0ffe1e2 100644
--- a/arch/x86/include/asm/mpx.h
+++ b/arch/x86/include/asm/mpx.h
@@ -60,8 +60,8 @@
60 60
61#ifdef CONFIG_X86_INTEL_MPX 61#ifdef CONFIG_X86_INTEL_MPX
62siginfo_t *mpx_generate_siginfo(struct pt_regs *regs, 62siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
63 struct xregs_state *xsave_buf); 63 struct task_struct *tsk);
64int mpx_handle_bd_fault(struct xregs_state *xsave_buf); 64int mpx_handle_bd_fault(struct task_struct *tsk);
65static inline int kernel_managing_mpx_tables(struct mm_struct *mm) 65static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
66{ 66{
67 return (mm->bd_addr != MPX_INVALID_BOUNDS_DIR); 67 return (mm->bd_addr != MPX_INVALID_BOUNDS_DIR);
@@ -78,11 +78,11 @@ void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
78 unsigned long start, unsigned long end); 78 unsigned long start, unsigned long end);
79#else 79#else
80static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs, 80static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
81 struct xregs_state *xsave_buf) 81 struct task_struct *tsk)
82{ 82{
83 return NULL; 83 return NULL;
84} 84}
85static inline int mpx_handle_bd_fault(struct xregs_state *xsave_buf) 85static inline int mpx_handle_bd_fault(struct task_struct *tsk)
86{ 86{
87 return -EINVAL; 87 return -EINVAL;
88} 88}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index a2510f230195..42f15314b361 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -59,6 +59,7 @@
59#include <asm/fixmap.h> 59#include <asm/fixmap.h>
60#include <asm/mach_traps.h> 60#include <asm/mach_traps.h>
61#include <asm/alternative.h> 61#include <asm/alternative.h>
62#include <asm/fpu/xstate.h>
62#include <asm/mpx.h> 63#include <asm/mpx.h>
63 64
64#ifdef CONFIG_X86_64 65#ifdef CONFIG_X86_64
@@ -371,9 +372,8 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
371dotraplinkage void do_bounds(struct pt_regs *regs, long error_code) 372dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
372{ 373{
373 struct task_struct *tsk = current; 374 struct task_struct *tsk = current;
374 struct xregs_state *xsave_buf;
375 enum ctx_state prev_state; 375 enum ctx_state prev_state;
376 struct bndcsr *bndcsr; 376 const struct bndcsr *bndcsr;
377 siginfo_t *info; 377 siginfo_t *info;
378 378
379 prev_state = exception_enter(); 379 prev_state = exception_enter();
@@ -392,12 +392,11 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
392 392
393 /* 393 /*
394 * We need to look at BNDSTATUS to resolve this exception. 394 * We need to look at BNDSTATUS to resolve this exception.
395 * It is not directly accessible, though, so we need to 395 * A NULL here might mean that it is in its 'init state',
396 * do an xsave and then pull it out of the xsave buffer. 396 * which is all zeros which indicates MPX was not
397 * responsible for the exception.
397 */ 398 */
398 copy_fpregs_to_fpstate(&tsk->thread.fpu); 399 bndcsr = get_xsave_field_ptr(XSTATE_BNDCSR);
399 xsave_buf = &(tsk->thread.fpu.state.xsave);
400 bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
401 if (!bndcsr) 400 if (!bndcsr)
402 goto exit_trap; 401 goto exit_trap;
403 402
@@ -408,11 +407,11 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
408 */ 407 */
409 switch (bndcsr->bndstatus & MPX_BNDSTA_ERROR_CODE) { 408 switch (bndcsr->bndstatus & MPX_BNDSTA_ERROR_CODE) {
410 case 2: /* Bound directory has invalid entry. */ 409 case 2: /* Bound directory has invalid entry. */
411 if (mpx_handle_bd_fault(xsave_buf)) 410 if (mpx_handle_bd_fault(tsk))
412 goto exit_trap; 411 goto exit_trap;
413 break; /* Success, it was handled */ 412 break; /* Success, it was handled */
414 case 1: /* Bound violation. */ 413 case 1: /* Bound violation. */
415 info = mpx_generate_siginfo(regs, xsave_buf); 414 info = mpx_generate_siginfo(regs, tsk);
416 if (IS_ERR(info)) { 415 if (IS_ERR(info)) {
417 /* 416 /*
418 * We failed to decode the MPX instruction. Act as if 417 * We failed to decode the MPX instruction. Act as if
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
index 2e0dfd39bd22..9d67e230b4fb 100644
--- a/arch/x86/mm/mpx.c
+++ b/arch/x86/mm/mpx.c
@@ -272,9 +272,9 @@ bad_opcode:
272 * The caller is expected to kfree() the returned siginfo_t. 272 * The caller is expected to kfree() the returned siginfo_t.
273 */ 273 */
274siginfo_t *mpx_generate_siginfo(struct pt_regs *regs, 274siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
275 struct xregs_state *xsave_buf) 275 struct task_struct *tsk)
276{ 276{
277 struct bndreg *bndregs, *bndreg; 277 const struct bndreg *bndregs, *bndreg;
278 siginfo_t *info = NULL; 278 siginfo_t *info = NULL;
279 struct insn insn; 279 struct insn insn;
280 uint8_t bndregno; 280 uint8_t bndregno;
@@ -294,8 +294,8 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
294 err = -EINVAL; 294 err = -EINVAL;
295 goto err_out; 295 goto err_out;
296 } 296 }
297 /* get the bndregs _area_ of the xsave structure */ 297 /* get bndregs field from current task's xsave area */
298 bndregs = get_xsave_addr(xsave_buf, XSTATE_BNDREGS); 298 bndregs = get_xsave_field_ptr(XSTATE_BNDREGS);
299 if (!bndregs) { 299 if (!bndregs) {
300 err = -EINVAL; 300 err = -EINVAL;
301 goto err_out; 301 goto err_out;
@@ -342,7 +342,7 @@ err_out:
342 342
343static __user void *task_get_bounds_dir(struct task_struct *tsk) 343static __user void *task_get_bounds_dir(struct task_struct *tsk)
344{ 344{
345 struct bndcsr *bndcsr; 345 const struct bndcsr *bndcsr;
346 346
347 if (!cpu_feature_enabled(X86_FEATURE_MPX)) 347 if (!cpu_feature_enabled(X86_FEATURE_MPX))
348 return MPX_INVALID_BOUNDS_DIR; 348 return MPX_INVALID_BOUNDS_DIR;
@@ -357,8 +357,7 @@ static __user void *task_get_bounds_dir(struct task_struct *tsk)
357 * The bounds directory pointer is stored in a register 357 * The bounds directory pointer is stored in a register
358 * only accessible if we first do an xsave. 358 * only accessible if we first do an xsave.
359 */ 359 */
360 copy_fpregs_to_fpstate(&tsk->thread.fpu); 360 bndcsr = get_xsave_field_ptr(XSTATE_BNDCSR);
361 bndcsr = get_xsave_addr(&tsk->thread.fpu.state.xsave, XSTATE_BNDCSR);
362 if (!bndcsr) 361 if (!bndcsr)
363 return MPX_INVALID_BOUNDS_DIR; 362 return MPX_INVALID_BOUNDS_DIR;
364 363
@@ -389,9 +388,10 @@ int mpx_enable_management(struct task_struct *tsk)
389 * directory into XSAVE/XRSTOR Save Area and enable MPX through 388 * directory into XSAVE/XRSTOR Save Area and enable MPX through
390 * XRSTOR instruction. 389 * XRSTOR instruction.
391 * 390 *
392 * copy_xregs_to_kernel() is expected to be very expensive. Storing the bounds 391 * The copy_xregs_to_kernel() beneath get_xsave_field_ptr() is
393 * directory here means that we do not have to do xsave in the unmap 392 * expected to be relatively expensive. Storing the bounds
394 * path; we can just use mm->bd_addr instead. 393 * directory here means that we do not have to do xsave in the
394 * unmap path; we can just use mm->bd_addr instead.
395 */ 395 */
396 bd_base = task_get_bounds_dir(tsk); 396 bd_base = task_get_bounds_dir(tsk);
397 down_write(&mm->mmap_sem); 397 down_write(&mm->mmap_sem);
@@ -497,12 +497,12 @@ out_unmap:
497 * bound table is 16KB. With 64-bit mode, the size of BD is 2GB, 497 * bound table is 16KB. With 64-bit mode, the size of BD is 2GB,
498 * and the size of each bound table is 4MB. 498 * and the size of each bound table is 4MB.
499 */ 499 */
500static int do_mpx_bt_fault(struct xregs_state *xsave_buf) 500static int do_mpx_bt_fault(struct task_struct *tsk)
501{ 501{
502 unsigned long bd_entry, bd_base; 502 unsigned long bd_entry, bd_base;
503 struct bndcsr *bndcsr; 503 const struct bndcsr *bndcsr;
504 504
505 bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR); 505 bndcsr = get_xsave_field_ptr(XSTATE_BNDCSR);
506 if (!bndcsr) 506 if (!bndcsr)
507 return -EINVAL; 507 return -EINVAL;
508 /* 508 /*
@@ -525,7 +525,7 @@ static int do_mpx_bt_fault(struct xregs_state *xsave_buf)
525 return allocate_bt((long __user *)bd_entry); 525 return allocate_bt((long __user *)bd_entry);
526} 526}
527 527
528int mpx_handle_bd_fault(struct xregs_state *xsave_buf) 528int mpx_handle_bd_fault(struct task_struct *tsk)
529{ 529{
530 /* 530 /*
531 * Userspace never asked us to manage the bounds tables, 531 * Userspace never asked us to manage the bounds tables,
@@ -534,7 +534,7 @@ int mpx_handle_bd_fault(struct xregs_state *xsave_buf)
534 if (!kernel_managing_mpx_tables(current->mm)) 534 if (!kernel_managing_mpx_tables(current->mm))
535 return -EINVAL; 535 return -EINVAL;
536 536
537 if (do_mpx_bt_fault(xsave_buf)) { 537 if (do_mpx_bt_fault(tsk)) {
538 force_sig(SIGSEGV, current); 538 force_sig(SIGSEGV, current);
539 /* 539 /*
540 * The force_sig() is essentially "handling" this 540 * The force_sig() is essentially "handling" this