summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Garnier <thgarnie@google.com>2017-03-14 13:05:07 -0400
committerIngo Molnar <mingo@kernel.org>2017-03-16 04:06:35 -0400
commit69218e47994da614e7af600bf06887750ab6657a (patch)
treec1399085e63a1b42cda253a73a0d33b1e84cb864
parentf06bdd4001c257792c54dce9427399f2896470af (diff)
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 <boris.ostrovsky@oracle.com> for testing and recommending changes for Xen support. Signed-off-by: Thomas Garnier <thgarnie@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Borislav Petkov <bp@suse.de> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Kosina <jikos@kernel.org> Cc: Joerg Roedel <joro@8bytes.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: Kees Cook <keescook@chromium.org> Cc: Len Brown <len.brown@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Lorenzo Stoakes <lstoakes@gmail.com> Cc: Luis R . Rodriguez <mcgrof@kernel.org> Cc: Matt Fleming <matt@codeblueprint.co.uk> Cc: Michal Hocko <mhocko@suse.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: Pavel Machek <pavel@ucw.cz> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Radim Krčmář <rkrcmar@redhat.com> Cc: Rafael J . Wysocki <rjw@rjwysocki.net> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Stanislaw Gruszka <sgruszka@redhat.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tim Chen <tim.c.chen@linux.intel.com> Cc: Vitaly Kuznetsov <vkuznets@redhat.com> Cc: kasan-dev@googlegroups.com Cc: kernel-hardening@lists.openwall.com Cc: kvm@vger.kernel.org Cc: lguest@lists.ozlabs.org Cc: linux-doc@vger.kernel.org Cc: linux-efi@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-pm@vger.kernel.org Cc: xen-devel@lists.xenproject.org Cc: zijun_hu <zijun_hu@htc.com> Link: http://lkml.kernel.org/r/20170314170508.100882-2-thgarnie@google.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/entry/vdso/vma.c2
-rw-r--r--arch/x86/include/asm/desc.h58
-rw-r--r--arch/x86/include/asm/fixmap.h4
-rw-r--r--arch/x86/include/asm/processor.h1
-rw-r--r--arch/x86/include/asm/stackprotector.h2
-rw-r--r--arch/x86/kernel/acpi/sleep.c2
-rw-r--r--arch/x86/kernel/apm_32.c6
-rw-r--r--arch/x86/kernel/cpu/common.c29
-rw-r--r--arch/x86/kernel/setup_percpu.c2
-rw-r--r--arch/x86/kernel/smpboot.c2
-rw-r--r--arch/x86/platform/efi/efi_32.c4
-rw-r--r--arch/x86/power/cpu.c7
-rw-r--r--arch/x86/xen/enlighten.c5
-rw-r--r--arch/x86/xen/mmu.c1
-rw-r--r--arch/x86/xen/smp.c2
-rw-r--r--drivers/lguest/x86/core.c6
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c10
17 files changed, 114 insertions, 29 deletions
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 226ca70dc6bd..5c5d4d7618e6 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)
354 d.p = 1; /* Present */ 354 d.p = 1; /* Present */
355 d.d = 1; /* 32-bit */ 355 d.d = 1; /* 32-bit */
356 356
357 write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S); 357 write_gdt_entry(get_cpu_gdt_rw(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S);
358} 358}
359 359
360static int vgetcpu_online(unsigned int cpu) 360static int vgetcpu_online(unsigned int cpu)
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
index 1548ca92ad3f..4b5ef0c64291 100644
--- a/arch/x86/include/asm/desc.h
+++ b/arch/x86/include/asm/desc.h
@@ -4,6 +4,7 @@
4#include <asm/desc_defs.h> 4#include <asm/desc_defs.h>
5#include <asm/ldt.h> 5#include <asm/ldt.h>
6#include <asm/mmu.h> 6#include <asm/mmu.h>
7#include <asm/fixmap.h>
7 8
8#include <linux/smp.h> 9#include <linux/smp.h>
9#include <linux/percpu.h> 10#include <linux/percpu.h>
@@ -38,6 +39,7 @@ extern struct desc_ptr idt_descr;
38extern gate_desc idt_table[]; 39extern gate_desc idt_table[];
39extern const struct desc_ptr debug_idt_descr; 40extern const struct desc_ptr debug_idt_descr;
40extern gate_desc debug_idt_table[]; 41extern gate_desc debug_idt_table[];
42extern pgprot_t pg_fixmap_gdt_flags;
41 43
42struct gdt_page { 44struct gdt_page {
43 struct desc_struct gdt[GDT_ENTRIES]; 45 struct desc_struct gdt[GDT_ENTRIES];
@@ -45,11 +47,57 @@ struct gdt_page {
45 47
46DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page); 48DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);
47 49
48static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) 50/* Provide the original GDT */
51static inline struct desc_struct *get_cpu_gdt_rw(unsigned int cpu)
49{ 52{
50 return per_cpu(gdt_page, cpu).gdt; 53 return per_cpu(gdt_page, cpu).gdt;
51} 54}
52 55
56static inline unsigned long get_cpu_gdt_rw_vaddr(unsigned int cpu)
57{
58 return (unsigned long)get_cpu_gdt_rw(cpu);
59}
60
61/* Provide the current original GDT */
62static inline struct desc_struct *get_current_gdt_rw(void)
63{
64 return this_cpu_ptr(&gdt_page)->gdt;
65}
66
67static inline unsigned long get_current_gdt_rw_vaddr(void)
68{
69 return (unsigned long)get_current_gdt_rw();
70}
71
72/* Get the fixmap index for a specific processor */
73static inline unsigned int get_cpu_gdt_ro_index(int cpu)
74{
75 return FIX_GDT_REMAP_BEGIN + cpu;
76}
77
78/* Provide the fixmap address of the remapped GDT */
79static inline struct desc_struct *get_cpu_gdt_ro(int cpu)
80{
81 unsigned int idx = get_cpu_gdt_ro_index(cpu);
82 return (struct desc_struct *)__fix_to_virt(idx);
83}
84
85static inline unsigned long get_cpu_gdt_ro_vaddr(int cpu)
86{
87 return (unsigned long)get_cpu_gdt_ro(cpu);
88}
89
90/* Provide the current read-only GDT */
91static inline struct desc_struct *get_current_gdt_ro(void)
92{
93 return get_cpu_gdt_ro(smp_processor_id());
94}
95
96static inline unsigned long get_current_gdt_ro_vaddr(void)
97{
98 return (unsigned long)get_current_gdt_ro();
99}
100
53#ifdef CONFIG_X86_64 101#ifdef CONFIG_X86_64
54 102
55static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func, 103static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
@@ -174,7 +222,7 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned t
174 222
175static inline void __set_tss_desc(unsigned cpu, unsigned int entry, void *addr) 223static inline void __set_tss_desc(unsigned cpu, unsigned int entry, void *addr)
176{ 224{
177 struct desc_struct *d = get_cpu_gdt_table(cpu); 225 struct desc_struct *d = get_cpu_gdt_rw(cpu);
178 tss_desc tss; 226 tss_desc tss;
179 227
180 set_tssldt_descriptor(&tss, (unsigned long)addr, DESC_TSS, 228 set_tssldt_descriptor(&tss, (unsigned long)addr, DESC_TSS,
@@ -194,7 +242,7 @@ static inline void native_set_ldt(const void *addr, unsigned int entries)
194 242
195 set_tssldt_descriptor(&ldt, (unsigned long)addr, DESC_LDT, 243 set_tssldt_descriptor(&ldt, (unsigned long)addr, DESC_LDT,
196 entries * LDT_ENTRY_SIZE - 1); 244 entries * LDT_ENTRY_SIZE - 1);
197 write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, 245 write_gdt_entry(get_cpu_gdt_rw(cpu), GDT_ENTRY_LDT,
198 &ldt, DESC_LDT); 246 &ldt, DESC_LDT);
199 asm volatile("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); 247 asm volatile("lldt %w0"::"q" (GDT_ENTRY_LDT*8));
200 } 248 }
@@ -209,7 +257,7 @@ DECLARE_PER_CPU(bool, __tss_limit_invalid);
209 257
210static inline void force_reload_TR(void) 258static inline void force_reload_TR(void)
211{ 259{
212 struct desc_struct *d = get_cpu_gdt_table(smp_processor_id()); 260 struct desc_struct *d = get_current_gdt_rw();
213 tss_desc tss; 261 tss_desc tss;
214 262
215 memcpy(&tss, &d[GDT_ENTRY_TSS], sizeof(tss_desc)); 263 memcpy(&tss, &d[GDT_ENTRY_TSS], sizeof(tss_desc));
@@ -288,7 +336,7 @@ static inline unsigned long native_store_tr(void)
288 336
289static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) 337static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
290{ 338{
291 struct desc_struct *gdt = get_cpu_gdt_table(cpu); 339 struct desc_struct *gdt = get_cpu_gdt_rw(cpu);
292 unsigned int i; 340 unsigned int i;
293 341
294 for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) 342 for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
index 8554f960e21b..b65155cc3760 100644
--- a/arch/x86/include/asm/fixmap.h
+++ b/arch/x86/include/asm/fixmap.h
@@ -100,6 +100,10 @@ enum fixed_addresses {
100#ifdef CONFIG_X86_INTEL_MID 100#ifdef CONFIG_X86_INTEL_MID
101 FIX_LNW_VRTC, 101 FIX_LNW_VRTC,
102#endif 102#endif
103 /* Fixmap entries to remap the GDTs, one per processor. */
104 FIX_GDT_REMAP_BEGIN,
105 FIX_GDT_REMAP_END = FIX_GDT_REMAP_BEGIN + NR_CPUS - 1,
106
103 __end_of_permanent_fixed_addresses, 107 __end_of_permanent_fixed_addresses,
104 108
105 /* 109 /*
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 7caa2ac50ea2..1150e1b21b0d 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -716,6 +716,7 @@ extern struct desc_ptr early_gdt_descr;
716 716
717extern void cpu_set_gdt(int); 717extern void cpu_set_gdt(int);
718extern void switch_to_new_gdt(int); 718extern void switch_to_new_gdt(int);
719extern void load_fixmap_gdt(int);
719extern void load_percpu_segment(int); 720extern void load_percpu_segment(int);
720extern void cpu_init(void); 721extern void cpu_init(void);
721 722
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index 58505f01962f..dcbd9bcce714 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -87,7 +87,7 @@ static inline void setup_stack_canary_segment(int cpu)
87{ 87{
88#ifdef CONFIG_X86_32 88#ifdef CONFIG_X86_32
89 unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu); 89 unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu);
90 struct desc_struct *gdt_table = get_cpu_gdt_table(cpu); 90 struct desc_struct *gdt_table = get_cpu_gdt_rw(cpu);
91 struct desc_struct desc; 91 struct desc_struct desc;
92 92
93 desc = gdt_table[GDT_ENTRY_STACK_CANARY]; 93 desc = gdt_table[GDT_ENTRY_STACK_CANARY];
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 48587335ede8..ed014814ea35 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -101,7 +101,7 @@ int x86_acpi_suspend_lowlevel(void)
101#ifdef CONFIG_SMP 101#ifdef CONFIG_SMP
102 initial_stack = (unsigned long)temp_stack + sizeof(temp_stack); 102 initial_stack = (unsigned long)temp_stack + sizeof(temp_stack);
103 early_gdt_descr.address = 103 early_gdt_descr.address =
104 (unsigned long)get_cpu_gdt_table(smp_processor_id()); 104 (unsigned long)get_cpu_gdt_rw(smp_processor_id());
105 initial_gs = per_cpu_offset(smp_processor_id()); 105 initial_gs = per_cpu_offset(smp_processor_id());
106#endif 106#endif
107 initial_code = (unsigned long)wakeup_long64; 107 initial_code = (unsigned long)wakeup_long64;
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 5a414545e8a3..446b0d3d4932 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -609,7 +609,7 @@ static long __apm_bios_call(void *_call)
609 609
610 cpu = get_cpu(); 610 cpu = get_cpu();
611 BUG_ON(cpu != 0); 611 BUG_ON(cpu != 0);
612 gdt = get_cpu_gdt_table(cpu); 612 gdt = get_cpu_gdt_rw(cpu);
613 save_desc_40 = gdt[0x40 / 8]; 613 save_desc_40 = gdt[0x40 / 8];
614 gdt[0x40 / 8] = bad_bios_desc; 614 gdt[0x40 / 8] = bad_bios_desc;
615 615
@@ -685,7 +685,7 @@ static long __apm_bios_call_simple(void *_call)
685 685
686 cpu = get_cpu(); 686 cpu = get_cpu();
687 BUG_ON(cpu != 0); 687 BUG_ON(cpu != 0);
688 gdt = get_cpu_gdt_table(cpu); 688 gdt = get_cpu_gdt_rw(cpu);
689 save_desc_40 = gdt[0x40 / 8]; 689 save_desc_40 = gdt[0x40 / 8];
690 gdt[0x40 / 8] = bad_bios_desc; 690 gdt[0x40 / 8] = bad_bios_desc;
691 691
@@ -2352,7 +2352,7 @@ static int __init apm_init(void)
2352 * Note we only set APM segments on CPU zero, since we pin the APM 2352 * Note we only set APM segments on CPU zero, since we pin the APM
2353 * code to that CPU. 2353 * code to that CPU.
2354 */ 2354 */
2355 gdt = get_cpu_gdt_table(0); 2355 gdt = get_cpu_gdt_rw(0);
2356 set_desc_base(&gdt[APM_CS >> 3], 2356 set_desc_base(&gdt[APM_CS >> 3],
2357 (unsigned long)__va((unsigned long)apm_info.bios.cseg << 4)); 2357 (unsigned long)__va((unsigned long)apm_info.bios.cseg << 4));
2358 set_desc_base(&gdt[APM_CS_16 >> 3], 2358 set_desc_base(&gdt[APM_CS_16 >> 3],
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 58094a1f9e9d..3cf1590ec9ce 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -448,6 +448,26 @@ void load_percpu_segment(int cpu)
448 load_stack_canary_segment(); 448 load_stack_canary_segment();
449} 449}
450 450
451/* Used by XEN to force the GDT read-only when required */
452pgprot_t pg_fixmap_gdt_flags = PAGE_KERNEL;
453
454/* Setup the fixmap mapping only once per-processor */
455static inline void setup_fixmap_gdt(int cpu)
456{
457 __set_fixmap(get_cpu_gdt_ro_index(cpu),
458 __pa(get_cpu_gdt_rw(cpu)), pg_fixmap_gdt_flags);
459}
460
461/* Load a fixmap remapping of the per-cpu GDT */
462void load_fixmap_gdt(int cpu)
463{
464 struct desc_ptr gdt_descr;
465
466 gdt_descr.address = (long)get_cpu_gdt_ro(cpu);
467 gdt_descr.size = GDT_SIZE - 1;
468 load_gdt(&gdt_descr);
469}
470
451/* 471/*
452 * Current gdt points %fs at the "master" per-cpu area: after this, 472 * Current gdt points %fs at the "master" per-cpu area: after this,
453 * it's on the real one. 473 * it's on the real one.
@@ -456,11 +476,10 @@ void switch_to_new_gdt(int cpu)
456{ 476{
457 struct desc_ptr gdt_descr; 477 struct desc_ptr gdt_descr;
458 478
459 gdt_descr.address = (long)get_cpu_gdt_table(cpu); 479 gdt_descr.address = (long)get_cpu_gdt_rw(cpu);
460 gdt_descr.size = GDT_SIZE - 1; 480 gdt_descr.size = GDT_SIZE - 1;
461 load_gdt(&gdt_descr); 481 load_gdt(&gdt_descr);
462 /* Reload the per-cpu base */ 482 /* Reload the per-cpu base */
463
464 load_percpu_segment(cpu); 483 load_percpu_segment(cpu);
465} 484}
466 485
@@ -1526,6 +1545,9 @@ void cpu_init(void)
1526 1545
1527 if (is_uv_system()) 1546 if (is_uv_system())
1528 uv_cpu_init(); 1547 uv_cpu_init();
1548
1549 setup_fixmap_gdt(cpu);
1550 load_fixmap_gdt(cpu);
1529} 1551}
1530 1552
1531#else 1553#else
@@ -1581,6 +1603,9 @@ void cpu_init(void)
1581 dbg_restore_debug_regs(); 1603 dbg_restore_debug_regs();
1582 1604
1583 fpu__init_cpu(); 1605 fpu__init_cpu();
1606
1607 setup_fixmap_gdt(cpu);
1608 load_fixmap_gdt(cpu);
1584} 1609}
1585#endif 1610#endif
1586 1611
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index 9820d6d977c6..11338b0b3ad2 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -160,7 +160,7 @@ static inline void setup_percpu_segment(int cpu)
160 pack_descriptor(&gdt, per_cpu_offset(cpu), 0xFFFFF, 160 pack_descriptor(&gdt, per_cpu_offset(cpu), 0xFFFFF,
161 0x2 | DESCTYPE_S, 0x8); 161 0x2 | DESCTYPE_S, 0x8);
162 gdt.s = 1; 162 gdt.s = 1;
163 write_gdt_entry(get_cpu_gdt_table(cpu), 163 write_gdt_entry(get_cpu_gdt_rw(cpu),
164 GDT_ENTRY_PERCPU, &gdt, DESCTYPE_S); 164 GDT_ENTRY_PERCPU, &gdt, DESCTYPE_S);
165#endif 165#endif
166} 166}
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index bd1f1ad35284..f04479a8f74f 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -983,7 +983,7 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
983 unsigned long timeout; 983 unsigned long timeout;
984 984
985 idle->thread.sp = (unsigned long)task_pt_regs(idle); 985 idle->thread.sp = (unsigned long)task_pt_regs(idle);
986 early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); 986 early_gdt_descr.address = (unsigned long)get_cpu_gdt_rw(cpu);
987 initial_code = (unsigned long)start_secondary; 987 initial_code = (unsigned long)start_secondary;
988 initial_stack = idle->thread.sp; 988 initial_stack = idle->thread.sp;
989 989
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index cef39b097649..950071171436 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -68,7 +68,7 @@ pgd_t * __init efi_call_phys_prolog(void)
68 load_cr3(initial_page_table); 68 load_cr3(initial_page_table);
69 __flush_tlb_all(); 69 __flush_tlb_all();
70 70
71 gdt_descr.address = __pa(get_cpu_gdt_table(0)); 71 gdt_descr.address = __pa(get_cpu_gdt_rw(0));
72 gdt_descr.size = GDT_SIZE - 1; 72 gdt_descr.size = GDT_SIZE - 1;
73 load_gdt(&gdt_descr); 73 load_gdt(&gdt_descr);
74 74
@@ -79,7 +79,7 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd)
79{ 79{
80 struct desc_ptr gdt_descr; 80 struct desc_ptr gdt_descr;
81 81
82 gdt_descr.address = (unsigned long)get_cpu_gdt_table(0); 82 gdt_descr.address = (unsigned long)get_cpu_gdt_rw(0);
83 gdt_descr.size = GDT_SIZE - 1; 83 gdt_descr.size = GDT_SIZE - 1;
84 load_gdt(&gdt_descr); 84 load_gdt(&gdt_descr);
85 85
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 66ade16c7693..6b05a9219ea2 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -95,7 +95,7 @@ static void __save_processor_state(struct saved_context *ctxt)
95 * 'pmode_gdt' in wakeup_start. 95 * 'pmode_gdt' in wakeup_start.
96 */ 96 */
97 ctxt->gdt_desc.size = GDT_SIZE - 1; 97 ctxt->gdt_desc.size = GDT_SIZE - 1;
98 ctxt->gdt_desc.address = (unsigned long)get_cpu_gdt_table(smp_processor_id()); 98 ctxt->gdt_desc.address = (unsigned long)get_cpu_gdt_rw(smp_processor_id());
99 99
100 store_tr(ctxt->tr); 100 store_tr(ctxt->tr);
101 101
@@ -162,7 +162,7 @@ static void fix_processor_context(void)
162 int cpu = smp_processor_id(); 162 int cpu = smp_processor_id();
163 struct tss_struct *t = &per_cpu(cpu_tss, cpu); 163 struct tss_struct *t = &per_cpu(cpu_tss, cpu);
164#ifdef CONFIG_X86_64 164#ifdef CONFIG_X86_64
165 struct desc_struct *desc = get_cpu_gdt_table(cpu); 165 struct desc_struct *desc = get_cpu_gdt_rw(cpu);
166 tss_desc tss; 166 tss_desc tss;
167#endif 167#endif
168 set_tss_desc(cpu, t); /* 168 set_tss_desc(cpu, t); /*
@@ -183,6 +183,9 @@ static void fix_processor_context(void)
183 load_mm_ldt(current->active_mm); /* This does lldt */ 183 load_mm_ldt(current->active_mm); /* This does lldt */
184 184
185 fpu__resume_cpu(); 185 fpu__resume_cpu();
186
187 /* The processor is back on the direct GDT, load back the fixmap */
188 load_fixmap_gdt(cpu);
186} 189}
187 190
188/** 191/**
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index ec1d5c46e58f..08faa61de5f7 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -710,7 +710,7 @@ static void load_TLS_descriptor(struct thread_struct *t,
710 710
711 *shadow = t->tls_array[i]; 711 *shadow = t->tls_array[i];
712 712
713 gdt = get_cpu_gdt_table(cpu); 713 gdt = get_cpu_gdt_rw(cpu);
714 maddr = arbitrary_virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]); 714 maddr = arbitrary_virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]);
715 mc = __xen_mc_entry(0); 715 mc = __xen_mc_entry(0);
716 716
@@ -1545,6 +1545,9 @@ asmlinkage __visible void __init xen_start_kernel(void)
1545 */ 1545 */
1546 xen_initial_gdt = &per_cpu(gdt_page, 0); 1546 xen_initial_gdt = &per_cpu(gdt_page, 0);
1547 1547
1548 /* GDT can only be remapped RO */
1549 pg_fixmap_gdt_flags = PAGE_KERNEL_RO;
1550
1548 xen_smp_init(); 1551 xen_smp_init();
1549 1552
1550#ifdef CONFIG_ACPI_NUMA 1553#ifdef CONFIG_ACPI_NUMA
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 37cb5aad71de..ebbfe00133f7 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2326,6 +2326,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
2326#endif 2326#endif
2327 case FIX_TEXT_POKE0: 2327 case FIX_TEXT_POKE0:
2328 case FIX_TEXT_POKE1: 2328 case FIX_TEXT_POKE1:
2329 case FIX_GDT_REMAP_BEGIN ... FIX_GDT_REMAP_END:
2329 /* All local page mappings */ 2330 /* All local page mappings */
2330 pte = pfn_pte(phys, prot); 2331 pte = pfn_pte(phys, prot);
2331 break; 2332 break;
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 7ff2f1bfb7ec..eaa36162ed4a 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -392,7 +392,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
392 if (ctxt == NULL) 392 if (ctxt == NULL)
393 return -ENOMEM; 393 return -ENOMEM;
394 394
395 gdt = get_cpu_gdt_table(cpu); 395 gdt = get_cpu_gdt_rw(cpu);
396 396
397#ifdef CONFIG_X86_32 397#ifdef CONFIG_X86_32
398 ctxt->user_regs.fs = __KERNEL_PERCPU; 398 ctxt->user_regs.fs = __KERNEL_PERCPU;
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index d71f6323ac00..b4f79b923aea 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -504,7 +504,7 @@ void __init lguest_arch_host_init(void)
504 * byte, not the size, hence the "-1"). 504 * byte, not the size, hence the "-1").
505 */ 505 */
506 state->host_gdt_desc.size = GDT_SIZE-1; 506 state->host_gdt_desc.size = GDT_SIZE-1;
507 state->host_gdt_desc.address = (long)get_cpu_gdt_table(i); 507 state->host_gdt_desc.address = (long)get_cpu_gdt_rw(i);
508 508
509 /* 509 /*
510 * All CPUs on the Host use the same Interrupt Descriptor 510 * All CPUs on the Host use the same Interrupt Descriptor
@@ -554,8 +554,8 @@ void __init lguest_arch_host_init(void)
554 * The Host needs to be able to use the LGUEST segments on this 554 * The Host needs to be able to use the LGUEST segments on this
555 * CPU, too, so put them in the Host GDT. 555 * CPU, too, so put them in the Host GDT.
556 */ 556 */
557 get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT; 557 get_cpu_gdt_rw(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
558 get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT; 558 get_cpu_gdt_rw(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
559 } 559 }
560 560
561 /* 561 /*
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index 438d4c72c7b3..ff563db025b3 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -54,7 +54,7 @@ __asm__(".text \n"
54 54
55#define Q2_SET_SEL(cpu, selname, address, size) \ 55#define Q2_SET_SEL(cpu, selname, address, size) \
56do { \ 56do { \
57 struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ 57 struct desc_struct *gdt = get_cpu_gdt_rw((cpu)); \
58 set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \ 58 set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \
59 set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ 59 set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \
60} while(0) 60} while(0)
@@ -95,8 +95,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
95 return PNP_FUNCTION_NOT_SUPPORTED; 95 return PNP_FUNCTION_NOT_SUPPORTED;
96 96
97 cpu = get_cpu(); 97 cpu = get_cpu();
98 save_desc_40 = get_cpu_gdt_table(cpu)[0x40 / 8]; 98 save_desc_40 = get_cpu_gdt_rw(cpu)[0x40 / 8];
99 get_cpu_gdt_table(cpu)[0x40 / 8] = bad_bios_desc; 99 get_cpu_gdt_rw(cpu)[0x40 / 8] = bad_bios_desc;
100 100
101 /* On some boxes IRQ's during PnP BIOS calls are deadly. */ 101 /* On some boxes IRQ's during PnP BIOS calls are deadly. */
102 spin_lock_irqsave(&pnp_bios_lock, flags); 102 spin_lock_irqsave(&pnp_bios_lock, flags);
@@ -134,7 +134,7 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
134 :"memory"); 134 :"memory");
135 spin_unlock_irqrestore(&pnp_bios_lock, flags); 135 spin_unlock_irqrestore(&pnp_bios_lock, flags);
136 136
137 get_cpu_gdt_table(cpu)[0x40 / 8] = save_desc_40; 137 get_cpu_gdt_rw(cpu)[0x40 / 8] = save_desc_40;
138 put_cpu(); 138 put_cpu();
139 139
140 /* If we get here and this is set then the PnP BIOS faulted on us. */ 140 /* If we get here and this is set then the PnP BIOS faulted on us. */
@@ -477,7 +477,7 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header)
477 pnp_bios_callpoint.segment = PNP_CS16; 477 pnp_bios_callpoint.segment = PNP_CS16;
478 478
479 for_each_possible_cpu(i) { 479 for_each_possible_cpu(i) {
480 struct desc_struct *gdt = get_cpu_gdt_table(i); 480 struct desc_struct *gdt = get_cpu_gdt_rw(i);
481 if (!gdt) 481 if (!gdt)
482 continue; 482 continue;
483 set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32], 483 set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32],