]>
Commit | Line | Data |
---|---|---|
59d5af67 | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
321d628a FG |
2 | From: Thomas Gleixner <tglx@linutronix.de> |
3 | Date: Mon, 4 Dec 2017 15:07:49 +0100 | |
59d5af67 | 4 | Subject: [PATCH] x86/cpu_entry_area: Add debugstore entries to cpu_entry_area |
321d628a FG |
5 | MIME-Version: 1.0 |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | CVE-2017-5754 | |
10 | ||
11 | The Intel PEBS/BTS debug store is a design trainwreck as it expects virtual | |
12 | addresses which must be visible in any execution context. | |
13 | ||
14 | So it is required to make these mappings visible to user space when kernel | |
15 | page table isolation is active. | |
16 | ||
17 | Provide enough room for the buffer mappings in the cpu_entry_area so the | |
18 | buffers are available in the user space visible page tables. | |
19 | ||
20 | At the point where the kernel side entry area is populated there is no | |
21 | buffer available yet, but the kernel PMD must be populated. To achieve this | |
22 | set the entries for these buffers to non present. | |
23 | ||
24 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
25 | Cc: Andy Lutomirski <luto@kernel.org> | |
26 | Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> | |
27 | Cc: Borislav Petkov <bp@alien8.de> | |
28 | Cc: Brian Gerst <brgerst@gmail.com> | |
29 | Cc: Dave Hansen <dave.hansen@linux.intel.com> | |
30 | Cc: David Laight <David.Laight@aculab.com> | |
31 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
32 | Cc: Eduardo Valentin <eduval@amazon.com> | |
33 | Cc: Greg KH <gregkh@linuxfoundation.org> | |
34 | Cc: H. Peter Anvin <hpa@zytor.com> | |
35 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
36 | Cc: Juergen Gross <jgross@suse.com> | |
37 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
38 | Cc: Peter Zijlstra <peterz@infradead.org> | |
39 | Cc: Will Deacon <will.deacon@arm.com> | |
40 | Cc: aliguori@amazon.com | |
41 | Cc: daniel.gruss@iaik.tugraz.at | |
42 | Cc: hughd@google.com | |
43 | Cc: keescook@google.com | |
44 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
45 | (cherry picked from commit 10043e02db7f8a4161f76434931051e7d797a5f6) | |
46 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
47 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
48 | (cherry picked from commit 4b9996f9c2d35d23a9fa2afe4f161402e6f28309) | |
49 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
50 | --- | |
51 | arch/x86/events/perf_event.h | 21 ++------------------ | |
52 | arch/x86/include/asm/cpu_entry_area.h | 13 +++++++++++++ | |
53 | arch/x86/include/asm/intel_ds.h | 36 +++++++++++++++++++++++++++++++++++ | |
54 | arch/x86/events/intel/ds.c | 5 +++-- | |
55 | arch/x86/mm/cpu_entry_area.c | 27 ++++++++++++++++++++++++++ | |
56 | 5 files changed, 81 insertions(+), 21 deletions(-) | |
57 | create mode 100644 arch/x86/include/asm/intel_ds.h | |
58 | ||
59 | diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h | |
60 | index 590eaf7c2c3e..308bc14f58af 100644 | |
61 | --- a/arch/x86/events/perf_event.h | |
62 | +++ b/arch/x86/events/perf_event.h | |
63 | @@ -14,6 +14,8 @@ | |
64 | ||
65 | #include <linux/perf_event.h> | |
66 | ||
67 | +#include <asm/intel_ds.h> | |
68 | + | |
69 | /* To enable MSR tracing please use the generic trace points. */ | |
70 | ||
71 | /* | |
72 | @@ -77,8 +79,6 @@ struct amd_nb { | |
73 | struct event_constraint event_constraints[X86_PMC_IDX_MAX]; | |
74 | }; | |
75 | ||
76 | -/* The maximal number of PEBS events: */ | |
77 | -#define MAX_PEBS_EVENTS 8 | |
78 | #define PEBS_COUNTER_MASK ((1ULL << MAX_PEBS_EVENTS) - 1) | |
79 | ||
80 | /* | |
81 | @@ -95,23 +95,6 @@ struct amd_nb { | |
82 | PERF_SAMPLE_TRANSACTION | \ | |
83 | PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER) | |
84 | ||
85 | -/* | |
86 | - * A debug store configuration. | |
87 | - * | |
88 | - * We only support architectures that use 64bit fields. | |
89 | - */ | |
90 | -struct debug_store { | |
91 | - u64 bts_buffer_base; | |
92 | - u64 bts_index; | |
93 | - u64 bts_absolute_maximum; | |
94 | - u64 bts_interrupt_threshold; | |
95 | - u64 pebs_buffer_base; | |
96 | - u64 pebs_index; | |
97 | - u64 pebs_absolute_maximum; | |
98 | - u64 pebs_interrupt_threshold; | |
99 | - u64 pebs_event_reset[MAX_PEBS_EVENTS]; | |
100 | -}; | |
101 | - | |
102 | #define PEBS_REGS \ | |
103 | (PERF_REG_X86_AX | \ | |
104 | PERF_REG_X86_BX | \ | |
105 | diff --git a/arch/x86/include/asm/cpu_entry_area.h b/arch/x86/include/asm/cpu_entry_area.h | |
106 | index 2fbc69a0916e..4a7884b8dca5 100644 | |
107 | --- a/arch/x86/include/asm/cpu_entry_area.h | |
108 | +++ b/arch/x86/include/asm/cpu_entry_area.h | |
109 | @@ -5,6 +5,7 @@ | |
110 | ||
111 | #include <linux/percpu-defs.h> | |
112 | #include <asm/processor.h> | |
113 | +#include <asm/intel_ds.h> | |
114 | ||
115 | /* | |
116 | * cpu_entry_area is a percpu region that contains things needed by the CPU | |
117 | @@ -40,6 +41,18 @@ struct cpu_entry_area { | |
118 | */ | |
119 | char exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]; | |
120 | #endif | |
121 | +#ifdef CONFIG_CPU_SUP_INTEL | |
122 | + /* | |
123 | + * Per CPU debug store for Intel performance monitoring. Wastes a | |
124 | + * full page at the moment. | |
125 | + */ | |
126 | + struct debug_store cpu_debug_store; | |
127 | + /* | |
128 | + * The actual PEBS/BTS buffers must be mapped to user space | |
129 | + * Reserve enough fixmap PTEs. | |
130 | + */ | |
131 | + struct debug_store_buffers cpu_debug_buffers; | |
132 | +#endif | |
133 | }; | |
134 | ||
135 | #define CPU_ENTRY_AREA_SIZE (sizeof(struct cpu_entry_area)) | |
136 | diff --git a/arch/x86/include/asm/intel_ds.h b/arch/x86/include/asm/intel_ds.h | |
137 | new file mode 100644 | |
138 | index 000000000000..62a9f4966b42 | |
139 | --- /dev/null | |
140 | +++ b/arch/x86/include/asm/intel_ds.h | |
141 | @@ -0,0 +1,36 @@ | |
142 | +#ifndef _ASM_INTEL_DS_H | |
143 | +#define _ASM_INTEL_DS_H | |
144 | + | |
145 | +#include <linux/percpu-defs.h> | |
146 | + | |
147 | +#define BTS_BUFFER_SIZE (PAGE_SIZE << 4) | |
148 | +#define PEBS_BUFFER_SIZE (PAGE_SIZE << 4) | |
149 | + | |
150 | +/* The maximal number of PEBS events: */ | |
151 | +#define MAX_PEBS_EVENTS 8 | |
152 | + | |
153 | +/* | |
154 | + * A debug store configuration. | |
155 | + * | |
156 | + * We only support architectures that use 64bit fields. | |
157 | + */ | |
158 | +struct debug_store { | |
159 | + u64 bts_buffer_base; | |
160 | + u64 bts_index; | |
161 | + u64 bts_absolute_maximum; | |
162 | + u64 bts_interrupt_threshold; | |
163 | + u64 pebs_buffer_base; | |
164 | + u64 pebs_index; | |
165 | + u64 pebs_absolute_maximum; | |
166 | + u64 pebs_interrupt_threshold; | |
167 | + u64 pebs_event_reset[MAX_PEBS_EVENTS]; | |
168 | +} __aligned(PAGE_SIZE); | |
169 | + | |
170 | +DECLARE_PER_CPU_PAGE_ALIGNED(struct debug_store, cpu_debug_store); | |
171 | + | |
172 | +struct debug_store_buffers { | |
173 | + char bts_buffer[BTS_BUFFER_SIZE]; | |
174 | + char pebs_buffer[PEBS_BUFFER_SIZE]; | |
175 | +}; | |
176 | + | |
177 | +#endif | |
178 | diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c | |
179 | index 98e36e0c791c..21a4ed789ec0 100644 | |
180 | --- a/arch/x86/events/intel/ds.c | |
181 | +++ b/arch/x86/events/intel/ds.c | |
182 | @@ -7,11 +7,12 @@ | |
183 | ||
184 | #include "../perf_event.h" | |
185 | ||
186 | +/* Waste a full page so it can be mapped into the cpu_entry_area */ | |
187 | +DEFINE_PER_CPU_PAGE_ALIGNED(struct debug_store, cpu_debug_store); | |
188 | + | |
189 | /* The size of a BTS record in bytes: */ | |
190 | #define BTS_RECORD_SIZE 24 | |
191 | ||
192 | -#define BTS_BUFFER_SIZE (PAGE_SIZE << 4) | |
193 | -#define PEBS_BUFFER_SIZE (PAGE_SIZE << 4) | |
194 | #define PEBS_FIXUP_SIZE PAGE_SIZE | |
195 | ||
196 | /* | |
197 | diff --git a/arch/x86/mm/cpu_entry_area.c b/arch/x86/mm/cpu_entry_area.c | |
198 | index fe814fd5e014..b9283cc27622 100644 | |
199 | --- a/arch/x86/mm/cpu_entry_area.c | |
200 | +++ b/arch/x86/mm/cpu_entry_area.c | |
201 | @@ -38,6 +38,32 @@ cea_map_percpu_pages(void *cea_vaddr, void *ptr, int pages, pgprot_t prot) | |
202 | cea_set_pte(cea_vaddr, per_cpu_ptr_to_phys(ptr), prot); | |
203 | } | |
204 | ||
205 | +static void percpu_setup_debug_store(int cpu) | |
206 | +{ | |
207 | +#ifdef CONFIG_CPU_SUP_INTEL | |
208 | + int npages; | |
209 | + void *cea; | |
210 | + | |
211 | + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) | |
212 | + return; | |
213 | + | |
214 | + cea = &get_cpu_entry_area(cpu)->cpu_debug_store; | |
215 | + npages = sizeof(struct debug_store) / PAGE_SIZE; | |
216 | + BUILD_BUG_ON(sizeof(struct debug_store) % PAGE_SIZE != 0); | |
217 | + cea_map_percpu_pages(cea, &per_cpu(cpu_debug_store, cpu), npages, | |
218 | + PAGE_KERNEL); | |
219 | + | |
220 | + cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers; | |
221 | + /* | |
222 | + * Force the population of PMDs for not yet allocated per cpu | |
223 | + * memory like debug store buffers. | |
224 | + */ | |
225 | + npages = sizeof(struct debug_store_buffers) / PAGE_SIZE; | |
226 | + for (; npages; npages--, cea += PAGE_SIZE) | |
227 | + cea_set_pte(cea, 0, PAGE_NONE); | |
228 | +#endif | |
229 | +} | |
230 | + | |
231 | /* Setup the fixmap mappings only once per-processor */ | |
232 | static void __init setup_cpu_entry_area(int cpu) | |
233 | { | |
234 | @@ -109,6 +135,7 @@ static void __init setup_cpu_entry_area(int cpu) | |
235 | cea_set_pte(&get_cpu_entry_area(cpu)->entry_trampoline, | |
236 | __pa_symbol(_entry_trampoline), PAGE_KERNEL_RX); | |
237 | #endif | |
238 | + percpu_setup_debug_store(cpu); | |
239 | } | |
240 | ||
241 | static __init void setup_cpu_entry_area_ptes(void) | |
242 | -- | |
243 | 2.14.2 | |
244 |