Merge branch 'x86-mpx-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Dec 2014 21:22:42 +0000 (13:22 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Dec 2014 21:22:42 +0000 (13:22 -0800)
Pull x86 MPX fixes from Thomas Gleixner:
 "Three updates for the new MPX infrastructure:
   - Use the proper error check in the trap handler
   - Add a proper config option for it
   - Bring documentation up to date"

* 'x86-mpx-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, mpx: Give MPX a real config option prompt
  x86, mpx: Update documentation
  x86_64/traps: Fix always true condition

1  2 
arch/x86/Kconfig
arch/x86/kernel/traps.c

diff --combined arch/x86/Kconfig
@@@ -24,7 -24,6 +24,7 @@@ config X8
        select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
        select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select ARCH_HAS_FAST_MULTIPLIER
 +      select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
        select HAVE_AOUT if X86_32
@@@ -145,7 -144,7 +145,7 @@@ config INSTRUCTION_DECODE
  
  config PERF_EVENTS_INTEL_UNCORE
        def_bool y
 -      depends on PERF_EVENTS && SUP_SUP_INTEL && PCI
 +      depends on PERF_EVENTS && CPU_SUP_INTEL && PCI
  
  config OUTPUT_FORMAT
        string
@@@ -249,10 -248,6 +249,6 @@@ config HAVE_INTEL_TX
        def_bool y
        depends on INTEL_IOMMU && ACPI
  
- config X86_INTEL_MPX
-       def_bool y
-       depends on CPU_SUP_INTEL
  config X86_32_SMP
        def_bool y
        depends on X86_32 && SMP
@@@ -993,24 -988,6 +989,24 @@@ config X86_ESPFIX6
        def_bool y
        depends on X86_16BIT && X86_64
  
 +config X86_VSYSCALL_EMULATION
 +       bool "Enable vsyscall emulation" if EXPERT
 +       default y
 +       depends on X86_64
 +       ---help---
 +       This enables emulation of the legacy vsyscall page.  Disabling
 +       it is roughly equivalent to booting with vsyscall=none, except
 +       that it will also disable the helpful warning if a program
 +       tries to use a vsyscall.  With this option set to N, offending
 +       programs will just segfault, citing addresses of the form
 +       0xffffffffff600?00.
 +
 +       This option is required by many programs built before 2013, and
 +       care should be used even with newer programs if set to N.
 +
 +       Disabling this option saves about 7K of kernel size and
 +       possibly 4K of additional runtime pagetable memory.
 +
  config TOSHIBA
        tristate "Toshiba Laptop support"
        depends on X86_32
@@@ -1594,6 -1571,32 +1590,32 @@@ config X86_SMA
  
          If unsure, say Y.
  
+ config X86_INTEL_MPX
+       prompt "Intel MPX (Memory Protection Extensions)"
+       def_bool n
+       depends on CPU_SUP_INTEL
+       ---help---
+         MPX provides hardware features that can be used in
+         conjunction with compiler-instrumented code to check
+         memory references.  It is designed to detect buffer
+         overflow or underflow bugs.
+         This option enables running applications which are
+         instrumented or otherwise use MPX.  It does not use MPX
+         itself inside the kernel or to protect the kernel
+         against bad memory references.
+         Enabling this option will make the kernel larger:
+         ~8k of kernel text and 36 bytes of data on a 64-bit
+         defconfig.  It adds a long to the 'mm_struct' which
+         will increase the kernel memory overhead of each
+         process and adds some branches to paths used during
+         exec() and munmap().
+         For details, see Documentation/x86/intel_mpx.txt
+         If unsure, say N.
  config EFI
        bool "EFI runtime service support"
        depends on ACPI
diff --combined arch/x86/kernel/traps.c
@@@ -233,40 -233,32 +233,40 @@@ DO_ERROR(X86_TRAP_UD,     SIGILL,  "inv
  DO_ERROR(X86_TRAP_OLD_MF, SIGFPE,  "coprocessor segment overrun",coprocessor_segment_overrun)
  DO_ERROR(X86_TRAP_TS,     SIGSEGV, "invalid TSS",             invalid_TSS)
  DO_ERROR(X86_TRAP_NP,     SIGBUS,  "segment not present",     segment_not_present)
 -#ifdef CONFIG_X86_32
  DO_ERROR(X86_TRAP_SS,     SIGBUS,  "stack segment",           stack_segment)
 -#endif
  DO_ERROR(X86_TRAP_AC,     SIGBUS,  "alignment check",         alignment_check)
  
  #ifdef CONFIG_X86_64
  /* Runs on IST stack */
 -dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
 -{
 -      enum ctx_state prev_state;
 -
 -      prev_state = exception_enter();
 -      if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
 -                     X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
 -              preempt_conditional_sti(regs);
 -              do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
 -              preempt_conditional_cli(regs);
 -      }
 -      exception_exit(prev_state);
 -}
 -
  dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
  {
        static const char str[] = "double fault";
        struct task_struct *tsk = current;
  
 +#ifdef CONFIG_X86_ESPFIX64
 +      extern unsigned char native_irq_return_iret[];
 +
 +      /*
 +       * If IRET takes a non-IST fault on the espfix64 stack, then we
 +       * end up promoting it to a doublefault.  In that case, modify
 +       * the stack to make it look like we just entered the #GP
 +       * handler from user space, similar to bad_iret.
 +       */
 +      if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY &&
 +              regs->cs == __KERNEL_CS &&
 +              regs->ip == (unsigned long)native_irq_return_iret)
 +      {
 +              struct pt_regs *normal_regs = task_pt_regs(current);
 +
 +              /* Fake a #GP(0) from userspace. */
 +              memmove(&normal_regs->ip, (void *)regs->sp, 5*8);
 +              normal_regs->orig_ax = 0;  /* Missing (lost) #GP error code */
 +              regs->ip = (unsigned long)general_protection;
 +              regs->sp = (unsigned long)&normal_regs->orig_ax;
 +              return;
 +      }
 +#endif
 +
        exception_enter();
        /* Return not checked because double check cannot be ignored */
        notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
@@@ -331,7 -323,7 +331,7 @@@ dotraplinkage void do_bounds(struct pt_
                break; /* Success, it was handled */
        case 1: /* Bound violation. */
                info = mpx_generate_siginfo(regs, xsave_buf);
-               if (PTR_ERR(info)) {
+               if (IS_ERR(info)) {
                        /*
                         * We failed to decode the MPX instruction.  Act as if
                         * the exception was not caused by MPX.
@@@ -470,7 -462,7 +470,7 @@@ NOKPROBE_SYMBOL(do_int3)
   * for scheduling or signal handling. The actual stack switch is done in
   * entry.S
   */
 -asmlinkage __visible struct pt_regs *sync_regs(struct pt_regs *eregs)
 +asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs)
  {
        struct pt_regs *regs = eregs;
        /* Did already sync */
        return regs;
  }
  NOKPROBE_SYMBOL(sync_regs);
 +
 +struct bad_iret_stack {
 +      void *error_entry_ret;
 +      struct pt_regs regs;
 +};
 +
 +asmlinkage __visible notrace
 +struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s)
 +{
 +      /*
 +       * This is called from entry_64.S early in handling a fault
 +       * caused by a bad iret to user mode.  To handle the fault
 +       * correctly, we want move our stack frame to task_pt_regs
 +       * and we want to pretend that the exception came from the
 +       * iret target.
 +       */
 +      struct bad_iret_stack *new_stack =
 +              container_of(task_pt_regs(current),
 +                           struct bad_iret_stack, regs);
 +
 +      /* Copy the IRET target to the new stack. */
 +      memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8);
 +
 +      /* Copy the remainder of the stack from the current stack. */
 +      memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip));
 +
 +      BUG_ON(!user_mode_vm(&new_stack->regs));
 +      return new_stack;
 +}
 +NOKPROBE_SYMBOL(fixup_bad_iret);
  #endif
  
  /*
@@@ -899,7 -861,7 +899,7 @@@ void __init trap_init(void
        set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun);
        set_intr_gate(X86_TRAP_TS, invalid_TSS);
        set_intr_gate(X86_TRAP_NP, segment_not_present);
 -      set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);
 +      set_intr_gate(X86_TRAP_SS, stack_segment);
        set_intr_gate(X86_TRAP_GP, general_protection);
        set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug);
        set_intr_gate(X86_TRAP_MF, coprocessor_error);