]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Jan 2018 00:41:07 +0000 (16:41 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Jan 2018 00:41:07 +0000 (16:41 -0800)
Pull x86 page table isolation fixes from Thomas Gleixner:
 "A couple of urgent fixes for PTI:

   - Fix a PTE mismatch between user and kernel visible mapping of the
     cpu entry area (differs vs. the GLB bit) and causes a TLB mismatch
     MCE on older AMD K8 machines

   - Fix the misplaced CR3 switch in the SYSCALL compat entry code which
     causes access to unmapped kernel memory resulting in double faults.

   - Fix the section mismatch of the cpu_tss_rw percpu storage caused by
     using a different mechanism for declaration and definition.

   - Two fixes for dumpstack which help to decode entry stack issues
     better

   - Enable PTI by default in Kconfig. We should have done that earlier,
     but it slipped through the cracks.

   - Exclude AMD from the PTI enforcement. Not necessarily a fix, but if
     AMD is so confident that they are not affected, then we should not
     burden users with the overhead"

* 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/process: Define cpu_tss_rw in same section as declaration
  x86/pti: Switch to kernel CR3 at early in entry_SYSCALL_compat()
  x86/dumpstack: Print registers for first stack frame
  x86/dumpstack: Fix partial register dumps
  x86/pti: Make sure the user/kernel PTEs match
  x86/cpu, x86/pti: Do not enable PTI on AMD processors
  x86/pti: Enable PTI by default

arch/x86/entry/entry_64_compat.S
arch/x86/include/asm/unwind.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/process.c
arch/x86/kernel/stacktrace.c
arch/x86/mm/pti.c
security/Kconfig

index 40f17009ec20cd5e4eff6147aa0468232d47e096..98d5358e4041a7e144ec566f7db19ff054cedbcc 100644 (file)
@@ -190,8 +190,13 @@ ENTRY(entry_SYSCALL_compat)
        /* Interrupts are off on entry. */
        swapgs
 
-       /* Stash user ESP and switch to the kernel stack. */
+       /* Stash user ESP */
        movl    %esp, %r8d
+
+       /* Use %rsp as scratch reg. User ESP is stashed in r8 */
+       SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp
+
+       /* Switch to the kernel stack */
        movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp
 
        /* Construct struct pt_regs on stack */
@@ -219,12 +224,6 @@ GLOBAL(entry_SYSCALL_compat_after_hwframe)
        pushq   $0                      /* pt_regs->r14 = 0 */
        pushq   $0                      /* pt_regs->r15 = 0 */
 
-       /*
-        * We just saved %rdi so it is safe to clobber.  It is not
-        * preserved during the C calls inside TRACE_IRQS_OFF anyway.
-        */
-       SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi
-
        /*
         * User mode is traced as though IRQs are on, and SYSENTER
         * turned them off.
index c1688c2d0a128f063053697dc60bcbfbca509765..1f86e1b0a5cdc1afeb4667e8c770ec81456e9fb4 100644 (file)
@@ -56,18 +56,27 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
 
 #if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
 /*
- * WARNING: The entire pt_regs may not be safe to dereference.  In some cases,
- * only the iret frame registers are accessible.  Use with caution!
+ * If 'partial' returns true, only the iret frame registers are valid.
  */
-static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
+static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state,
+                                                   bool *partial)
 {
        if (unwind_done(state))
                return NULL;
 
+       if (partial) {
+#ifdef CONFIG_UNWINDER_ORC
+               *partial = !state->full_regs;
+#else
+               *partial = false;
+#endif
+       }
+
        return state->regs;
 }
 #else
-static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
+static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state,
+                                                   bool *partial)
 {
        return NULL;
 }
index c47de4ebf63a3e84a64511662c08d5b20faa94db..7d9e3b06209b8f36bf1ddd690308df76485c7950 100644 (file)
@@ -923,8 +923,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 
        setup_force_cpu_cap(X86_FEATURE_ALWAYS);
 
-       /* Assume for now that ALL x86 CPUs are insecure */
-       setup_force_cpu_bug(X86_BUG_CPU_INSECURE);
+       if (c->x86_vendor != X86_VENDOR_AMD)
+               setup_force_cpu_bug(X86_BUG_CPU_INSECURE);
 
        fpu__init_system(c);
 
index 5fa110699ed275fe81dc9d8f678a2a2f8902017e..afbecff161d162c11a82d0610ae406b910c3f791 100644 (file)
@@ -76,12 +76,23 @@ void show_iret_regs(struct pt_regs *regs)
                regs->sp, regs->flags);
 }
 
-static void show_regs_safe(struct stack_info *info, struct pt_regs *regs)
+static void show_regs_if_on_stack(struct stack_info *info, struct pt_regs *regs,
+                                 bool partial)
 {
-       if (on_stack(info, regs, sizeof(*regs)))
+       /*
+        * These on_stack() checks aren't strictly necessary: the unwind code
+        * has already validated the 'regs' pointer.  The checks are done for
+        * ordering reasons: if the registers are on the next stack, we don't
+        * want to print them out yet.  Otherwise they'll be shown as part of
+        * the wrong stack.  Later, when show_trace_log_lvl() switches to the
+        * next stack, this function will be called again with the same regs so
+        * they can be printed in the right context.
+        */
+       if (!partial && on_stack(info, regs, sizeof(*regs))) {
                __show_regs(regs, 0);
-       else if (on_stack(info, (void *)regs + IRET_FRAME_OFFSET,
-                         IRET_FRAME_SIZE)) {
+
+       } else if (partial && on_stack(info, (void *)regs + IRET_FRAME_OFFSET,
+                                      IRET_FRAME_SIZE)) {
                /*
                 * When an interrupt or exception occurs in entry code, the
                 * full pt_regs might not have been saved yet.  In that case
@@ -98,11 +109,13 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
        struct stack_info stack_info = {0};
        unsigned long visit_mask = 0;
        int graph_idx = 0;
+       bool partial;
 
        printk("%sCall Trace:\n", log_lvl);
 
        unwind_start(&state, task, regs, stack);
        stack = stack ? : get_stack_pointer(task, regs);
+       regs = unwind_get_entry_regs(&state, &partial);
 
        /*
         * Iterate through the stacks, starting with the current stack pointer.
@@ -120,7 +133,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
         * - hardirq stack
         * - entry stack
         */
-       for (regs = NULL; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) {
+       for ( ; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) {
                const char *stack_name;
 
                if (get_stack_info(stack, task, &stack_info, &visit_mask)) {
@@ -140,7 +153,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
                        printk("%s <%s>\n", log_lvl, stack_name);
 
                if (regs)
-                       show_regs_safe(&stack_info, regs);
+                       show_regs_if_on_stack(&stack_info, regs, partial);
 
                /*
                 * Scan the stack, printing any text addresses we find.  At the
@@ -164,7 +177,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
 
                        /*
                         * Don't print regs->ip again if it was already printed
-                        * by show_regs_safe() below.
+                        * by show_regs_if_on_stack().
                         */
                        if (regs && stack == &regs->ip)
                                goto next;
@@ -199,9 +212,9 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
                        unwind_next_frame(&state);
 
                        /* if the frame has entry regs, print them */
-                       regs = unwind_get_entry_regs(&state);
+                       regs = unwind_get_entry_regs(&state, &partial);
                        if (regs)
-                               show_regs_safe(&stack_info, regs);
+                               show_regs_if_on_stack(&stack_info, regs, partial);
                }
 
                if (stack_name)
index aed9d94bd46f41bb049b8e0153a44a43d97e80b4..832a6acd730fad70e1426052d502f6438b30e38e 100644 (file)
@@ -47,7 +47,7 @@
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */
-__visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss_rw) = {
+__visible DEFINE_PER_CPU_PAGE_ALIGNED(struct tss_struct, cpu_tss_rw) = {
        .x86_tss = {
                /*
                 * .sp0 is only used when entering ring 0 from a lower
index 20161ef53537c760d858388295f57d21ae2f7346..093f2ea5dd56b613d03ccaeeb87fd50900f64ba1 100644 (file)
@@ -102,7 +102,7 @@ __save_stack_trace_reliable(struct stack_trace *trace,
        for (unwind_start(&state, task, NULL, NULL); !unwind_done(&state);
             unwind_next_frame(&state)) {
 
-               regs = unwind_get_entry_regs(&state);
+               regs = unwind_get_entry_regs(&state, NULL);
                if (regs) {
                        /*
                         * Kernel mode registers on the stack indicate an
index bce8aea656062197ac0649e7a204d0c5cd0a5e29..2da28ba975082474b83664e7d58836ed82c6432a 100644 (file)
@@ -367,7 +367,8 @@ static void __init pti_setup_espfix64(void)
 static void __init pti_clone_entry_text(void)
 {
        pti_clone_pmds((unsigned long) __entry_text_start,
-                       (unsigned long) __irqentry_text_end, _PAGE_RW);
+                       (unsigned long) __irqentry_text_end,
+                      _PAGE_RW | _PAGE_GLOBAL);
 }
 
 /*
index a623d13bf2884afdc6fdcdbe656811b7d31b2951..3d4debd0257e2544996ac97c90831bde3a854e7d 100644 (file)
@@ -56,6 +56,7 @@ config SECURITY_NETWORK
 
 config PAGE_TABLE_ISOLATION
        bool "Remove the kernel mapping in user mode"
+       default y
        depends on X86_64 && !UML
        help
          This feature reduces the number of hardware side channels by