Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2018-01-12 21:55:29 +0100
committerBorislav Petkov <bp@suse.de>2018-01-12 21:55:36 +0100
commitc448b944a1f160e0ada0aa0ac5c1aa7d31b2a89f (patch)
treef9c972bc9e1775e7939e618b4c9518bf821feb72
parent6d0350da8d8231a34e4b4c28cbeb741efdf2c84a (diff)
x86/entry: Remap the TSS into the CPU entry area (bsc#1068032
CVE-2017-5754).
-rw-r--r--patches.arch/12-x86-entry-remap-the-tss-into-the-cpu-entry-area.patch262
-rw-r--r--series.conf1
2 files changed, 263 insertions, 0 deletions
diff --git a/patches.arch/12-x86-entry-remap-the-tss-into-the-cpu-entry-area.patch b/patches.arch/12-x86-entry-remap-the-tss-into-the-cpu-entry-area.patch
new file mode 100644
index 0000000000..a77bc83497
--- /dev/null
+++ b/patches.arch/12-x86-entry-remap-the-tss-into-the-cpu-entry-area.patch
@@ -0,0 +1,262 @@
+From: Andy Lutomirski <luto@kernel.org>
+Date: Mon, 4 Dec 2017 15:07:20 +0100
+Subject: x86/entry: Remap the TSS into the CPU entry area
+Git-commit: 72f5e08dbba2d01aa90b592cf76c378ea233b00b
+Patch-mainline: v4.15-rc5
+References: bsc#1068032 CVE-2017-5754
+
+This has a secondary purpose: it puts the entry stack into a region
+with a well-controlled layout. A subsequent patch will take
+advantage of this to streamline the SYSCALL entry code to be able to
+find it more easily.
+
+Signed-off-by: Andy Lutomirski <luto@kernel.org>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Borislav Petkov <bpetkov@suse.de>
+Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Brian Gerst <brgerst@gmail.com>
+Cc: Dave Hansen <dave.hansen@intel.com>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: David Laight <David.Laight@aculab.com>
+Cc: Denys Vlasenko <dvlasenk@redhat.com>
+Cc: Eduardo Valentin <eduval@amazon.com>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: H. Peter Anvin <hpa@zytor.com>
+Cc: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Juergen Gross <jgross@suse.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: Will Deacon <will.deacon@arm.com>
+Cc: aliguori@amazon.com
+Cc: daniel.gruss@iaik.tugraz.at
+Cc: hughd@google.com
+Cc: keescook@google.com
+Link: https://lkml.kernel.org/r/20171204150605.962042855@linutronix.de
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Borislav Petkov <bp@suse.de>
+---
+ arch/x86/entry/entry_32.S | 6 ++++--
+ arch/x86/include/asm/fixmap.h | 7 +++++++
+ arch/x86/kernel/asm-offsets.c | 3 +++
+ arch/x86/kernel/cpu/common.c | 41 +++++++++++++++++++++++++++++++++++------
+ arch/x86/kernel/dumpstack.c | 3 ++-
+ arch/x86/kvm/vmx.c | 2 +-
+ arch/x86/power/cpu.c | 11 ++++++-----
+ 7 files changed, 58 insertions(+), 15 deletions(-)
+
+--- a/arch/x86/entry/entry_32.S
++++ b/arch/x86/entry/entry_32.S
+@@ -956,7 +956,8 @@ ENTRY(debug)
+ movl %esp, %eax # pt_regs pointer
+
+ /* Are we currently on the SYSENTER stack? */
+- PER_CPU(cpu_tss + CPU_TSS_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx)
++ movl PER_CPU_VAR(cpu_entry_area), %ecx
++ addl $CPU_ENTRY_AREA_tss + CPU_TSS_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx
+ subl %eax, %ecx /* ecx = (end of SYSENTER_stack) - esp */
+ cmpl $SIZEOF_SYSENTER_stack, %ecx
+ jb .Ldebug_from_sysenter_stack
+@@ -999,7 +1000,8 @@ ENTRY(nmi)
+ movl %esp, %eax # pt_regs pointer
+
+ /* Are we currently on the SYSENTER stack? */
+- PER_CPU(cpu_tss + CPU_TSS_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx)
++ movl PER_CPU_VAR(cpu_entry_area), %ecx
++ addl $CPU_ENTRY_AREA_tss + CPU_TSS_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx
+ subl %eax, %ecx /* ecx = (end of SYSENTER_stack) - esp */
+ cmpl $SIZEOF_SYSENTER_stack, %ecx
+ jb .Lnmi_from_sysenter_stack
+--- a/arch/x86/include/asm/fixmap.h
++++ b/arch/x86/include/asm/fixmap.h
+@@ -54,6 +54,13 @@ extern unsigned long __FIXADDR_TOP;
+ */
+ struct cpu_entry_area {
+ char gdt[PAGE_SIZE];
++
++ /*
++ * The GDT is just below cpu_tss and thus serves (on x86_64) as a
++ * a read-only guard page for the SYSENTER stack at the bottom
++ * of the TSS region.
++ */
++ struct tss_struct tss;
+ };
+
+ #define CPU_ENTRY_AREA_PAGES (sizeof(struct cpu_entry_area) / PAGE_SIZE)
+--- a/arch/x86/kernel/asm-offsets.c
++++ b/arch/x86/kernel/asm-offsets.c
+@@ -97,4 +97,7 @@ void common(void) {
+ OFFSET(CPU_TSS_SYSENTER_stack, tss_struct, SYSENTER_stack);
+ /* Size of SYSENTER_stack */
+ DEFINE(SIZEOF_SYSENTER_stack, sizeof(((struct tss_struct *)0)->SYSENTER_stack));
++
++ /* Layout info for cpu_entry_area */
++ OFFSET(CPU_ENTRY_AREA_tss, cpu_entry_area, tss);
+ }
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -448,6 +448,22 @@ void load_percpu_segment(int cpu)
+ load_stack_canary_segment();
+ }
+
++static void set_percpu_fixmap_pages(int fixmap_index, void *ptr,
++ int pages, pgprot_t prot)
++{
++ int i;
++
++ for (i = 0; i < pages; i++) {
++ __set_fixmap(fixmap_index - i,
++ per_cpu_ptr_to_phys(ptr + i * PAGE_SIZE), prot);
++ }
++}
++
++#ifdef CONFIG_X86_32
++/* The 32-bit entry code needs to find cpu_entry_area. */
++DEFINE_PER_CPU(struct cpu_entry_area *, cpu_entry_area);
++#endif
++
+ /* Setup the fixmap mappings only once per-processor */
+ static inline void setup_cpu_entry_area(int cpu)
+ {
+@@ -489,7 +505,15 @@ static inline void setup_cpu_entry_area(
+ */
+ BUILD_BUG_ON((offsetof(struct tss_struct, x86_tss) ^
+ offsetofend(struct tss_struct, x86_tss)) & PAGE_MASK);
++ BUILD_BUG_ON(sizeof(struct tss_struct) % PAGE_SIZE != 0);
++ set_percpu_fixmap_pages(get_cpu_entry_area_index(cpu, tss),
++ &per_cpu(cpu_tss, cpu),
++ sizeof(struct tss_struct) / PAGE_SIZE,
++ PAGE_KERNEL);
+
++#ifdef CONFIG_X86_32
++ this_cpu_write(cpu_entry_area, get_cpu_entry_area(cpu));
++#endif
+ }
+
+ /* Load the original GDT from the per-cpu structure */
+@@ -1231,7 +1255,8 @@ void enable_sep_cpu(void)
+ wrmsr(MSR_IA32_SYSENTER_CS, tss->x86_tss.ss1, 0);
+
+ wrmsr(MSR_IA32_SYSENTER_ESP,
+- (unsigned long)tss + offsetofend(struct tss_struct, SYSENTER_stack),
++ (unsigned long)&get_cpu_entry_area(cpu)->tss +
++ offsetofend(struct tss_struct, SYSENTER_stack),
+ 0);
+
+ wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long)entry_SYSENTER_32, 0);
+@@ -1355,6 +1380,8 @@ static DEFINE_PER_CPU_PAGE_ALIGNED(char,
+ /* May not be marked __init: used by software suspend */
+ void syscall_init(void)
+ {
++ int cpu = smp_processor_id();
++
+ wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
+ wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
+
+@@ -1368,7 +1395,7 @@ void syscall_init(void)
+ */
+ wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
+ wrmsrl_safe(MSR_IA32_SYSENTER_ESP,
+- (unsigned long)this_cpu_ptr(&cpu_tss) +
++ (unsigned long)&get_cpu_entry_area(cpu)->tss +
+ offsetofend(struct tss_struct, SYSENTER_stack));
+ wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
+ #else
+@@ -1577,11 +1604,13 @@ void cpu_init(void)
+ BUG_ON(me->mm);
+ enter_lazy_tlb(&init_mm, me);
+
++ setup_cpu_entry_area(cpu);
++
+ /*
+ * Initialize the TSS. Don't bother initializing sp0, as the initial
+ * task never enters user mode.
+ */
+- set_tss_desc(cpu, &t->x86_tss);
++ set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
+ load_TR_desc();
+
+ load_mm_ldt(&init_mm);
+@@ -1594,7 +1623,6 @@ void cpu_init(void)
+ if (is_uv_system())
+ uv_cpu_init();
+
+- setup_cpu_entry_area(cpu);
+ load_fixmap_gdt(cpu);
+ }
+
+@@ -1634,11 +1662,13 @@ void cpu_init(void)
+ BUG_ON(curr->mm);
+ enter_lazy_tlb(&init_mm, curr);
+
++ setup_cpu_entry_area(cpu);
++
+ /*
+ * Initialize the TSS. Don't bother initializing sp0, as the initial
+ * task never enters user mode.
+ */
+- set_tss_desc(cpu, &t->x86_tss);
++ set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
+ load_TR_desc();
+
+ load_mm_ldt(&init_mm);
+@@ -1655,7 +1685,6 @@ void cpu_init(void)
+
+ fpu__init_cpu();
+
+- setup_cpu_entry_area(cpu);
+ load_fixmap_gdt(cpu);
+ }
+ #endif
+--- a/arch/x86/kernel/dumpstack.c
++++ b/arch/x86/kernel/dumpstack.c
+@@ -45,7 +45,8 @@ bool in_task_stack(unsigned long *stack,
+
+ bool in_sysenter_stack(unsigned long *stack, struct stack_info *info)
+ {
+- struct tss_struct *tss = this_cpu_ptr(&cpu_tss);
++ int cpu = smp_processor_id();
++ struct tss_struct *tss = &get_cpu_entry_area(cpu)->tss;
+
+ /* Treat the canary as part of the stack for unwinding purposes. */
+ void *begin = &tss->SYSENTER_stack_canary;
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -2274,7 +2274,7 @@ static void vmx_vcpu_load(struct kvm_vcp
+ * processors. See 22.2.4.
+ */
+ vmcs_writel(HOST_TR_BASE,
+- (unsigned long)this_cpu_ptr(&cpu_tss.x86_tss));
++ (unsigned long)&get_cpu_entry_area(cpu)->tss.x86_tss);
+ vmcs_writel(HOST_GDTR_BASE, (unsigned long)gdt); /* 22.2.4 */
+
+ /*
+--- a/arch/x86/power/cpu.c
++++ b/arch/x86/power/cpu.c
+@@ -160,18 +160,19 @@ static void do_fpu_end(void)
+ static void fix_processor_context(void)
+ {
+ int cpu = smp_processor_id();
+- struct tss_struct *t = &per_cpu(cpu_tss, cpu);
+ #ifdef CONFIG_X86_64
+ struct desc_struct *desc = get_cpu_gdt_rw(cpu);
+ tss_desc tss;
+ #endif
+
+ /*
+- * This just modifies memory; should not be necessary. But... This is
+- * necessary, because 386 hardware has concept of busy TSS or some
+- * similar stupidity.
++ * We need to reload TR, which requires that we change the
++ * GDT entry to indicate "available" first.
++ *
++ * XXX: This could probably all be replaced by a call to
++ * force_reload_TR().
+ */
+- set_tss_desc(cpu, &t->x86_tss);
++ set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
+
+ #ifdef CONFIG_X86_64
+ memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc));
diff --git a/series.conf b/series.conf
index 6de913a6a8..ab6762e1f0 100644
--- a/series.conf
+++ b/series.conf
@@ -7383,6 +7383,7 @@
patches.arch/09-x86-entry-fix-assumptions-that-the-hw-tss-is-at-the-beginning-of-cpu_tss.patch
patches.arch/10-x86-dumpstack-handle-stack-overflow-on-all-stacks.patch
patches.arch/11-x86-entry-move-sysenter_stack-to-the-beginning-of-struct-tss_struct.patch
+ patches.arch/12-x86-entry-remap-the-tss-into-the-cpu-entry-area.patch
########################################################
# Staging tree patches