]>
Commit | Line | Data |
---|---|---|
321d628a FG |
1 | From 384e4cfab1886f8abb94fe16abbad2a034612f78 Mon Sep 17 00:00:00 2001 |
2 | From: Thomas Gleixner <tglx@linutronix.de> | |
3 | Date: Mon, 4 Dec 2017 15:07:36 +0100 | |
633c5ed1 | 4 | Subject: [PATCH 190/242] x86/mm/pti: Add infrastructure for page table |
321d628a FG |
5 | isolation |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | CVE-2017-5754 | |
11 | ||
12 | Add the initial files for kernel page table isolation, with a minimal init | |
13 | function and the boot time detection for this misfeature. | |
14 | ||
15 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
16 | Reviewed-by: Borislav Petkov <bp@suse.de> | |
17 | Cc: Andy Lutomirski <luto@kernel.org> | |
18 | Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> | |
19 | Cc: Borislav Petkov <bp@alien8.de> | |
20 | Cc: Brian Gerst <brgerst@gmail.com> | |
21 | Cc: Dave Hansen <dave.hansen@linux.intel.com> | |
22 | Cc: David Laight <David.Laight@aculab.com> | |
23 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
24 | Cc: Eduardo Valentin <eduval@amazon.com> | |
25 | Cc: Greg KH <gregkh@linuxfoundation.org> | |
26 | Cc: H. Peter Anvin <hpa@zytor.com> | |
27 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
28 | Cc: Juergen Gross <jgross@suse.com> | |
29 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
30 | Cc: Peter Zijlstra <peterz@infradead.org> | |
31 | Cc: Will Deacon <will.deacon@arm.com> | |
32 | Cc: aliguori@amazon.com | |
33 | Cc: daniel.gruss@iaik.tugraz.at | |
34 | Cc: hughd@google.com | |
35 | Cc: keescook@google.com | |
36 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
37 | (backported from commit aa8c6248f8c75acfd610fe15d8cae23cf70d9d09) | |
38 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
39 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
40 | (cherry picked from commit 50da124a01ed7a59f9b2c9551f622c5a27d1caec) | |
41 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
42 | --- | |
43 | Documentation/admin-guide/kernel-parameters.txt | 2 + | |
44 | arch/x86/mm/Makefile | 7 ++- | |
45 | arch/x86/entry/calling.h | 7 +++ | |
46 | arch/x86/include/asm/pti.h | 14 +++++ | |
47 | include/linux/pti.h | 11 ++++ | |
48 | arch/x86/boot/compressed/pagetable.c | 3 + | |
49 | arch/x86/mm/init.c | 2 + | |
50 | arch/x86/mm/pti.c | 84 +++++++++++++++++++++++++ | |
51 | init/main.c | 3 + | |
52 | 9 files changed, 130 insertions(+), 3 deletions(-) | |
53 | create mode 100644 arch/x86/include/asm/pti.h | |
54 | create mode 100644 include/linux/pti.h | |
55 | create mode 100644 arch/x86/mm/pti.c | |
56 | ||
57 | diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt | |
58 | index 3510e255ef4c..e2a4608da5d2 100644 | |
59 | --- a/Documentation/admin-guide/kernel-parameters.txt | |
60 | +++ b/Documentation/admin-guide/kernel-parameters.txt | |
61 | @@ -2677,6 +2677,8 @@ | |
62 | steal time is computed, but won't influence scheduler | |
63 | behaviour | |
64 | ||
65 | + nopti [X86-64] Disable kernel page table isolation | |
66 | + | |
67 | nolapic [X86-32,APIC] Do not enable or use the local APIC. | |
68 | ||
69 | nolapic_timer [X86-32,APIC] Do not use the local APIC timer. | |
70 | diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile | |
71 | index 76f5399a8356..7aa68fc18abe 100644 | |
72 | --- a/arch/x86/mm/Makefile | |
73 | +++ b/arch/x86/mm/Makefile | |
74 | @@ -35,7 +35,8 @@ obj-$(CONFIG_AMD_NUMA) += amdtopology.o | |
75 | obj-$(CONFIG_ACPI_NUMA) += srat.o | |
76 | obj-$(CONFIG_NUMA_EMU) += numa_emulation.o | |
77 | ||
78 | -obj-$(CONFIG_X86_INTEL_MPX) += mpx.o | |
79 | -obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o | |
80 | -obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o | |
81 | +obj-$(CONFIG_X86_INTEL_MPX) += mpx.o | |
82 | +obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o | |
83 | +obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o | |
84 | +obj-$(CONFIG_PAGE_TABLE_ISOLATION) += pti.o | |
85 | ||
86 | diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h | |
87 | index dde6262be0a3..bb56f5346ae8 100644 | |
88 | --- a/arch/x86/entry/calling.h | |
89 | +++ b/arch/x86/entry/calling.h | |
90 | @@ -204,18 +204,23 @@ For 32-bit we have the following conventions - kernel is built with | |
91 | .endm | |
92 | ||
93 | .macro SWITCH_TO_KERNEL_CR3 scratch_reg:req | |
94 | + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI | |
95 | mov %cr3, \scratch_reg | |
96 | ADJUST_KERNEL_CR3 \scratch_reg | |
97 | mov \scratch_reg, %cr3 | |
98 | +.Lend_\@: | |
99 | .endm | |
100 | ||
101 | .macro SWITCH_TO_USER_CR3 scratch_reg:req | |
102 | + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI | |
103 | mov %cr3, \scratch_reg | |
104 | ADJUST_USER_CR3 \scratch_reg | |
105 | mov \scratch_reg, %cr3 | |
106 | +.Lend_\@: | |
107 | .endm | |
108 | ||
109 | .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req | |
110 | + ALTERNATIVE "jmp .Ldone_\@", "", X86_FEATURE_PTI | |
111 | movq %cr3, \scratch_reg | |
112 | movq \scratch_reg, \save_reg | |
113 | /* | |
114 | @@ -232,11 +237,13 @@ For 32-bit we have the following conventions - kernel is built with | |
115 | .endm | |
116 | ||
117 | .macro RESTORE_CR3 save_reg:req | |
118 | + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI | |
119 | /* | |
120 | * The CR3 write could be avoided when not changing its value, | |
121 | * but would require a CR3 read *and* a scratch register. | |
122 | */ | |
123 | movq \save_reg, %cr3 | |
124 | +.Lend_\@: | |
125 | .endm | |
126 | ||
127 | #else /* CONFIG_PAGE_TABLE_ISOLATION=n: */ | |
128 | diff --git a/arch/x86/include/asm/pti.h b/arch/x86/include/asm/pti.h | |
129 | new file mode 100644 | |
130 | index 000000000000..0b5ef05b2d2d | |
131 | --- /dev/null | |
132 | +++ b/arch/x86/include/asm/pti.h | |
133 | @@ -0,0 +1,14 @@ | |
134 | +// SPDX-License-Identifier: GPL-2.0 | |
135 | +#ifndef _ASM_X86_PTI_H | |
136 | +#define _ASM_X86_PTI_H | |
137 | +#ifndef __ASSEMBLY__ | |
138 | + | |
139 | +#ifdef CONFIG_PAGE_TABLE_ISOLATION | |
140 | +extern void pti_init(void); | |
141 | +extern void pti_check_boottime_disable(void); | |
142 | +#else | |
143 | +static inline void pti_check_boottime_disable(void) { } | |
144 | +#endif | |
145 | + | |
146 | +#endif /* __ASSEMBLY__ */ | |
147 | +#endif /* _ASM_X86_PTI_H */ | |
148 | diff --git a/include/linux/pti.h b/include/linux/pti.h | |
149 | new file mode 100644 | |
150 | index 000000000000..0174883a935a | |
151 | --- /dev/null | |
152 | +++ b/include/linux/pti.h | |
153 | @@ -0,0 +1,11 @@ | |
154 | +// SPDX-License-Identifier: GPL-2.0 | |
155 | +#ifndef _INCLUDE_PTI_H | |
156 | +#define _INCLUDE_PTI_H | |
157 | + | |
158 | +#ifdef CONFIG_PAGE_TABLE_ISOLATION | |
159 | +#include <asm/pti.h> | |
160 | +#else | |
161 | +static inline void pti_init(void) { } | |
162 | +#endif | |
163 | + | |
164 | +#endif | |
165 | diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c | |
166 | index 28029be47fbb..21d8839cdaa7 100644 | |
167 | --- a/arch/x86/boot/compressed/pagetable.c | |
168 | +++ b/arch/x86/boot/compressed/pagetable.c | |
169 | @@ -15,6 +15,9 @@ | |
170 | #define __pa(x) ((unsigned long)(x)) | |
171 | #define __va(x) ((void *)((unsigned long)(x))) | |
172 | ||
173 | +/* No PAGE_TABLE_ISOLATION support needed either: */ | |
174 | +#undef CONFIG_PAGE_TABLE_ISOLATION | |
175 | + | |
176 | #include "misc.h" | |
177 | ||
178 | /* These actually do the work of building the kernel identity maps. */ | |
179 | diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c | |
180 | index 020223420308..af75069fb116 100644 | |
181 | --- a/arch/x86/mm/init.c | |
182 | +++ b/arch/x86/mm/init.c | |
183 | @@ -20,6 +20,7 @@ | |
184 | #include <asm/kaslr.h> | |
185 | #include <asm/hypervisor.h> | |
186 | #include <asm/cpufeature.h> | |
187 | +#include <asm/pti.h> | |
188 | ||
189 | /* | |
190 | * We need to define the tracepoints somewhere, and tlb.c | |
191 | @@ -630,6 +631,7 @@ void __init init_mem_mapping(void) | |
192 | { | |
193 | unsigned long end; | |
194 | ||
195 | + pti_check_boottime_disable(); | |
196 | probe_page_size_mask(); | |
197 | setup_pcid(); | |
198 | ||
199 | diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c | |
200 | new file mode 100644 | |
201 | index 000000000000..375f23a758bc | |
202 | --- /dev/null | |
203 | +++ b/arch/x86/mm/pti.c | |
204 | @@ -0,0 +1,84 @@ | |
205 | +/* | |
206 | + * Copyright(c) 2017 Intel Corporation. All rights reserved. | |
207 | + * | |
208 | + * This program is free software; you can redistribute it and/or modify | |
209 | + * it under the terms of version 2 of the GNU General Public License as | |
210 | + * published by the Free Software Foundation. | |
211 | + * | |
212 | + * This program is distributed in the hope that it will be useful, but | |
213 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
214 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
215 | + * General Public License for more details. | |
216 | + * | |
217 | + * This code is based in part on work published here: | |
218 | + * | |
219 | + * https://github.com/IAIK/KAISER | |
220 | + * | |
221 | + * The original work was written by and and signed off by for the Linux | |
222 | + * kernel by: | |
223 | + * | |
224 | + * Signed-off-by: Richard Fellner <richard.fellner@student.tugraz.at> | |
225 | + * Signed-off-by: Moritz Lipp <moritz.lipp@iaik.tugraz.at> | |
226 | + * Signed-off-by: Daniel Gruss <daniel.gruss@iaik.tugraz.at> | |
227 | + * Signed-off-by: Michael Schwarz <michael.schwarz@iaik.tugraz.at> | |
228 | + * | |
229 | + * Major changes to the original code by: Dave Hansen <dave.hansen@intel.com> | |
230 | + * Mostly rewritten by Thomas Gleixner <tglx@linutronix.de> and | |
231 | + * Andy Lutomirsky <luto@amacapital.net> | |
232 | + */ | |
233 | +#include <linux/kernel.h> | |
234 | +#include <linux/errno.h> | |
235 | +#include <linux/string.h> | |
236 | +#include <linux/types.h> | |
237 | +#include <linux/bug.h> | |
238 | +#include <linux/init.h> | |
239 | +#include <linux/spinlock.h> | |
240 | +#include <linux/mm.h> | |
241 | +#include <linux/uaccess.h> | |
242 | + | |
243 | +#include <asm/cpufeature.h> | |
244 | +#include <asm/hypervisor.h> | |
245 | +#include <asm/cmdline.h> | |
246 | +#include <asm/pti.h> | |
247 | +#include <asm/pgtable.h> | |
248 | +#include <asm/pgalloc.h> | |
249 | +#include <asm/tlbflush.h> | |
250 | +#include <asm/desc.h> | |
251 | + | |
252 | +#undef pr_fmt | |
253 | +#define pr_fmt(fmt) "Kernel/User page tables isolation: " fmt | |
254 | + | |
255 | +static void __init pti_print_if_insecure(const char *reason) | |
256 | +{ | |
257 | + if (boot_cpu_has_bug(X86_BUG_CPU_INSECURE)) | |
258 | + pr_info("%s\n", reason); | |
259 | +} | |
260 | + | |
261 | +void __init pti_check_boottime_disable(void) | |
262 | +{ | |
263 | + if (hypervisor_is_type(X86_HYPER_XEN_PV)) { | |
264 | + pti_print_if_insecure("disabled on XEN PV."); | |
265 | + return; | |
266 | + } | |
267 | + | |
268 | + if (cmdline_find_option_bool(boot_command_line, "nopti")) { | |
269 | + pti_print_if_insecure("disabled on command line."); | |
270 | + return; | |
271 | + } | |
272 | + | |
273 | + if (!boot_cpu_has_bug(X86_BUG_CPU_INSECURE)) | |
274 | + return; | |
275 | + | |
276 | + setup_force_cpu_cap(X86_FEATURE_PTI); | |
277 | +} | |
278 | + | |
279 | +/* | |
280 | + * Initialize kernel page table isolation | |
281 | + */ | |
282 | +void __init pti_init(void) | |
283 | +{ | |
284 | + if (!static_cpu_has(X86_FEATURE_PTI)) | |
285 | + return; | |
286 | + | |
287 | + pr_info("enabled\n"); | |
288 | +} | |
289 | diff --git a/init/main.c b/init/main.c | |
290 | index de1c495da782..bb0896c24c08 100644 | |
291 | --- a/init/main.c | |
292 | +++ b/init/main.c | |
293 | @@ -75,6 +75,7 @@ | |
294 | #include <linux/slab.h> | |
295 | #include <linux/perf_event.h> | |
296 | #include <linux/ptrace.h> | |
297 | +#include <linux/pti.h> | |
298 | #include <linux/blkdev.h> | |
299 | #include <linux/elevator.h> | |
300 | #include <linux/sched_clock.h> | |
301 | @@ -506,6 +507,8 @@ static void __init mm_init(void) | |
302 | ioremap_huge_init(); | |
303 | /* Should be run before the first non-init thread is created */ | |
304 | init_espfix_bsp(); | |
305 | + /* Should be run after espfix64 is set up. */ | |
306 | + pti_init(); | |
307 | } | |
308 | ||
309 | asmlinkage __visible void __init start_kernel(void) | |
310 | -- | |
311 | 2.14.2 | |
312 |