diff options
author | Kees Cook <keescook@chromium.org> | 2013-04-10 15:24:22 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2013-04-11 16:53:19 -0400 |
commit | 4eefbe792baedb474e256d35370849992fcf1c79 (patch) | |
tree | 03a95dab4a014a7f36133f9660ca180b01df62d4 | |
parent | 31880c37c11e28cb81c70757e38392b42e695dc6 (diff) |
x86: Use a read-only IDT alias on all CPUs
Make a copy of the IDT (as seen via the "sidt" instruction) read-only.
This primarily removes the IDT from being a target for arbitrary memory
write attacks, and has the added benefit of also not leaking the kernel
base offset, if it has been relocated.
We already did this on vendor == Intel and family == 5 because of the
F0 0F bug -- regardless of if a particular CPU had the F0 0F bug or
not. Since the workaround was so cheap, there simply was no reason to
be very specific. This patch extends the readonly alias to all CPUs,
but does not activate the #PF to #UD conversion code needed to deliver
the proper exception in the F0 0F case except on Intel family 5
processors.
Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/20130410192422.GA17344@www.outflux.net
Cc: Eric Northup <digitaleric@google.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r-- | arch/x86/include/asm/fixmap.h | 4 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/intel.c | 18 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 9 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 4 |
4 files changed, 12 insertions, 23 deletions
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index a09c28571064..51b9e322cb8f 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h | |||
@@ -104,9 +104,7 @@ enum fixed_addresses { | |||
104 | FIX_LI_PCIA, /* Lithium PCI Bridge A */ | 104 | FIX_LI_PCIA, /* Lithium PCI Bridge A */ |
105 | FIX_LI_PCIB, /* Lithium PCI Bridge B */ | 105 | FIX_LI_PCIB, /* Lithium PCI Bridge B */ |
106 | #endif | 106 | #endif |
107 | #ifdef CONFIG_X86_F00F_BUG | 107 | FIX_RO_IDT, /* Virtual mapping for read-only IDT */ |
108 | FIX_F00F_IDT, /* Virtual mapping for IDT */ | ||
109 | #endif | ||
110 | #ifdef CONFIG_X86_CYCLONE_TIMER | 108 | #ifdef CONFIG_X86_CYCLONE_TIMER |
111 | FIX_CYCLONE_TIMER, /*cyclone timer register*/ | 109 | FIX_CYCLONE_TIMER, /*cyclone timer register*/ |
112 | #endif | 110 | #endif |
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 1905ce98bee0..71700247a5d7 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
@@ -164,20 +164,6 @@ int __cpuinit ppro_with_ram_bug(void) | |||
164 | return 0; | 164 | return 0; |
165 | } | 165 | } |
166 | 166 | ||
167 | #ifdef CONFIG_X86_F00F_BUG | ||
168 | static void __cpuinit trap_init_f00f_bug(void) | ||
169 | { | ||
170 | __set_fixmap(FIX_F00F_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO); | ||
171 | |||
172 | /* | ||
173 | * Update the IDT descriptor and reload the IDT so that | ||
174 | * it uses the read-only mapped virtual address. | ||
175 | */ | ||
176 | idt_descr.address = fix_to_virt(FIX_F00F_IDT); | ||
177 | load_idt(&idt_descr); | ||
178 | } | ||
179 | #endif | ||
180 | |||
181 | static void __cpuinit intel_smp_check(struct cpuinfo_x86 *c) | 167 | static void __cpuinit intel_smp_check(struct cpuinfo_x86 *c) |
182 | { | 168 | { |
183 | /* calling is from identify_secondary_cpu() ? */ | 169 | /* calling is from identify_secondary_cpu() ? */ |
@@ -206,8 +192,7 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c) | |||
206 | /* | 192 | /* |
207 | * All current models of Pentium and Pentium with MMX technology CPUs | 193 | * All current models of Pentium and Pentium with MMX technology CPUs |
208 | * have the F0 0F bug, which lets nonprivileged users lock up the | 194 | * have the F0 0F bug, which lets nonprivileged users lock up the |
209 | * system. | 195 | * system. Announce that the fault handler will be checking for it. |
210 | * Note that the workaround only should be initialized once... | ||
211 | */ | 196 | */ |
212 | c->f00f_bug = 0; | 197 | c->f00f_bug = 0; |
213 | if (!paravirt_enabled() && c->x86 == 5) { | 198 | if (!paravirt_enabled() && c->x86 == 5) { |
@@ -215,7 +200,6 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c) | |||
215 | 200 | ||
216 | c->f00f_bug = 1; | 201 | c->f00f_bug = 1; |
217 | if (!f00f_workaround_enabled) { | 202 | if (!f00f_workaround_enabled) { |
218 | trap_init_f00f_bug(); | ||
219 | printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); | 203 | printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); |
220 | f00f_workaround_enabled = 1; | 204 | f00f_workaround_enabled = 1; |
221 | } | 205 | } |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 68bda7a84159..10e24462c058 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <asm/fpu-internal.h> | 56 | #include <asm/fpu-internal.h> |
57 | #include <asm/mce.h> | 57 | #include <asm/mce.h> |
58 | #include <asm/context_tracking.h> | 58 | #include <asm/context_tracking.h> |
59 | #include <asm/fixmap.h> | ||
59 | 60 | ||
60 | #include <asm/mach_traps.h> | 61 | #include <asm/mach_traps.h> |
61 | 62 | ||
@@ -753,6 +754,14 @@ void __init trap_init(void) | |||
753 | #endif | 754 | #endif |
754 | 755 | ||
755 | /* | 756 | /* |
757 | * Set the IDT descriptor to a fixed read-only location, so that the | ||
758 | * "sidt" instruction will not leak the location of the kernel, and | ||
759 | * to defend the IDT against arbitrary memory write vulnerabilities. | ||
760 | * It will be reloaded in cpu_init() */ | ||
761 | __set_fixmap(FIX_RO_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO); | ||
762 | idt_descr.address = fix_to_virt(FIX_RO_IDT); | ||
763 | |||
764 | /* | ||
756 | * Should be a barrier for any external CPU state: | 765 | * Should be a barrier for any external CPU state: |
757 | */ | 766 | */ |
758 | cpu_init(); | 767 | cpu_init(); |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 6afbb2ca9a0a..8bc4decb14ca 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -2039,9 +2039,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) | |||
2039 | 2039 | ||
2040 | switch (idx) { | 2040 | switch (idx) { |
2041 | case FIX_BTMAP_END ... FIX_BTMAP_BEGIN: | 2041 | case FIX_BTMAP_END ... FIX_BTMAP_BEGIN: |
2042 | #ifdef CONFIG_X86_F00F_BUG | 2042 | case FIX_RO_IDT: |
2043 | case FIX_F00F_IDT: | ||
2044 | #endif | ||
2045 | #ifdef CONFIG_X86_32 | 2043 | #ifdef CONFIG_X86_32 |
2046 | case FIX_WP_TEST: | 2044 | case FIX_WP_TEST: |
2047 | case FIX_VDSO: | 2045 | case FIX_VDSO: |