Commit-ID: 69218e47994da614e7af600bf06887750ab6657a
Gitweb: http://git.kernel.org/tip/69218e47994da614e7af600bf06887750ab6657a
Author: Thomas Garnier
AuthorDate: Tue, 14 Mar 2017 10:05:07 -0700
Committer: Ingo Molnar
CommitDate: Thu, 16 Mar 2017 09:06:35 +0100
x86: Remap GDT tables in the fixmap section
Each processor holds a GDT in its per-cpu structure. The sgdt
instruction gives the base address of the current GDT. This address can
be used to bypass KASLR memory randomization. With another bug, an
attacker could target other per-cpu structures or deduce the base of
the main memory section (PAGE_OFFSET).
This patch relocates the GDT table for each processor inside the
fixmap section. The space is reserved based on number of supported
processors.
For consistency, the remapping is done by default on 32 and 64-bit.
Each processor switches to its remapped GDT at the end of
initialization. For hibernation, the main processor returns with the
original GDT and switches back to the remapping at completion.
This patch was tested on both architectures. Hibernation and KVM were
both tested specially for their usage of the GDT.
Thanks to Boris Ostrovsky for testing and
recommending changes for Xen support.
Signed-off-by: Thomas Garnier
Cc: Alexander Potapenko
Cc: Andrew Morton
Cc: Andrey Ryabinin
Cc: Andy Lutomirski
Cc: Ard Biesheuvel
Cc: Boris Ostrovsky
Cc: Borislav Petkov
Cc: Chris Wilson
Cc: Christian Borntraeger
Cc: Dmitry Vyukov
Cc: Frederic Weisbecker
Cc: Jiri Kosina
Cc: Joerg Roedel
Cc: Jonathan Corbet
Cc: Josh Poimboeuf
Cc: Juergen Gross
Cc: Kees Cook
Cc: Len Brown
Cc: Linus Torvalds
Cc: Lorenzo Stoakes
Cc: Luis R . Rodriguez
Cc: Matt Fleming
Cc: Michal Hocko
Cc: Paolo Bonzini
Cc: Paul Gortmaker
Cc: Pavel Machek
Cc: Peter Zijlstra
Cc: Radim Krčmář
Cc: Rafael J . Wysocki
Cc: Rusty Russell
Cc: Stanislaw Gruszka
Cc: Thomas Gleixner
Cc: Tim Chen
Cc: Vitaly Kuznetsov
Cc: kasan-...@googlegroups.com
Cc: kernel-harden...@lists.openwall.com
Cc: k...@vger.kernel.org
Cc: lgu...@lists.ozlabs.org
Cc: linux-...@vger.kernel.org
Cc: linux-...@vger.kernel.org
Cc: linux...@kvack.org
Cc: linux...@vger.kernel.org
Cc: xen-de...@lists.xenproject.org
Cc: zijun_hu
Link: http://lkml.kernel.org/r/20170314170508.100882-2-thgar...@google.com
Signed-off-by: Ingo Molnar
---
arch/x86/entry/vdso/vma.c | 2 +-
arch/x86/include/asm/desc.h | 58 ---
arch/x86/include/asm/fixmap.h | 4 +++
arch/x86/include/asm/processor.h | 1 +
arch/x86/include/asm/stackprotector.h | 2 +-
arch/x86/kernel/acpi/sleep.c | 2 +-
arch/x86/kernel/apm_32.c | 6 ++--
arch/x86/kernel/cpu/common.c | 29 --
arch/x86/kernel/setup_percpu.c| 2 +-
arch/x86/kernel/smpboot.c | 2 +-
arch/x86/platform/efi/efi_32.c| 4 +--
arch/x86/power/cpu.c | 7 +++--
arch/x86/xen/enlighten.c | 5 ++-
arch/x86/xen/mmu.c| 1 +
arch/x86/xen/smp.c| 2 +-
drivers/lguest/x86/core.c | 6 ++--
drivers/pnp/pnpbios/bioscalls.c | 10 +++---
17 files changed, 114 insertions(+), 29 deletions(-)
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 226ca70..5c5d4d7 100644
--- a/arch/x86/entry/vdso/vma.c
+++ b/arch/x86/entry/vdso/vma.c
@@ -354,7 +354,7 @@ static void vgetcpu_cpu_init(void *arg)
d.p = 1;/* Present */
d.d = 1;/* 32-bit */
- write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, ,
DESCTYPE_S);
+ write_gdt_entry(get_cpu_gdt_rw(cpu), GDT_ENTRY_PER_CPU, , DESCTYPE_S);
}
static int vgetcpu_online(unsigned int cpu)
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
index 1548ca9..4b5ef0c 100644
--- a/arch/x86/include/asm/desc.h
+++ b/arch/x86/include/asm/desc.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include
@@ -38,6 +39,7 @@ extern struct desc_ptr idt_descr;
extern gate_desc idt_table[];
extern const struct desc_ptr debug_idt_descr;
extern gate_desc debug_idt_table[];
+extern pgprot_t pg_fixmap_gdt_flags;
struct gdt_page {
struct desc_struct gdt[GDT_ENTRIES];
@@ -45,11 +47,57 @@ struct gdt_page {
DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);
-static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
+/* Provide the original GDT */
+static inline struct desc_struct *get_cpu_gdt_rw(unsigned int cpu)
{
return per_cpu(gdt_page, cpu).gdt;
}
+static inline unsigned long get_cpu_gdt_rw_vaddr(unsigned int cpu)
+{
+ return (unsigned long)get_cpu_gdt_rw(cpu);
+}
+
+/* Provide the current original GDT */
+static inline struct desc_struct *get_current_gdt_rw(void)
+{
+ return this_cpu_ptr(_page)->gdt;
+}
+
+static inline unsigned long get_current_gdt_rw_vaddr(void)
+{
+ return (unsigned