]>
Commit | Line | Data |
---|---|---|
035dbe67 FG |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Tim Chen <tim@otc-grantley-02.jf.intel.com> | |
3 | Date: Thu, 16 Nov 2017 04:47:48 -0800 | |
4 | Subject: [PATCH] x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL | |
5 | feature | |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | CVE-2017-5753 | |
11 | CVE-2017-5715 | |
12 | ||
13 | There are 2 ways to control IBPB and IBRS | |
14 | ||
15 | 1. At boot time | |
16 | noibrs kernel boot parameter will disable IBRS usage | |
17 | noibpb kernel boot parameter will disable IBPB usage | |
18 | Otherwise if the above parameters are not specified, the system | |
19 | will enable ibrs and ibpb usage if the cpu supports it. | |
20 | ||
21 | 2. At run time | |
22 | echo 0 > /proc/sys/kernel/ibrs_enabled will turn off IBRS | |
23 | echo 1 > /proc/sys/kernel/ibrs_enabled will turn on IBRS in kernel | |
24 | echo 2 > /proc/sys/kernel/ibrs_enabled will turn on IBRS in both userspace and kernel | |
25 | ||
26 | Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com> | |
27 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
28 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
29 | [marcelo.cerri@canonical.com: add x86 guards to kernel/smp.c] | |
30 | [marcelo.cerri@canonical.com: include asm/msr.h under x86 guard in kernel/sysctl.c] | |
31 | Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> | |
32 | (cherry picked from commit 23225db7b02c7f8b94e5d5050987430089e6f7cc) | |
33 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
34 | --- | |
35 | Documentation/admin-guide/kernel-parameters.txt | 10 ++ | |
36 | arch/x86/include/asm/mwait.h | 4 +- | |
37 | arch/x86/include/asm/spec_ctrl.h | 24 ++++- | |
38 | include/linux/smp.h | 87 +++++++++++++++++ | |
39 | arch/x86/kernel/cpu/intel.c | 11 ++- | |
40 | arch/x86/kernel/cpu/microcode/core.c | 11 +++ | |
41 | arch/x86/kernel/process.c | 6 +- | |
42 | arch/x86/kernel/smpboot.c | 4 +- | |
43 | arch/x86/kvm/vmx.c | 4 +- | |
44 | arch/x86/lib/delay.c | 6 +- | |
45 | arch/x86/mm/tlb.c | 2 +- | |
46 | kernel/smp.c | 41 ++++++++ | |
47 | kernel/sysctl.c | 125 ++++++++++++++++++++++++ | |
48 | 13 files changed, 316 insertions(+), 19 deletions(-) | |
49 | ||
50 | diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt | |
51 | index 1a6ebc6cdf26..e7216bc05b3b 100644 | |
52 | --- a/Documentation/admin-guide/kernel-parameters.txt | |
53 | +++ b/Documentation/admin-guide/kernel-parameters.txt | |
54 | @@ -2566,6 +2566,16 @@ | |
55 | noexec=on: enable non-executable mappings (default) | |
56 | noexec=off: disable non-executable mappings | |
57 | ||
58 | + noibrs [X86] | |
59 | + Don't use indirect branch restricted speculation (IBRS) | |
60 | + feature when running in secure environment, | |
61 | + to avoid performance overhead. | |
62 | + | |
63 | + noibpb [X86] | |
64 | + Don't use indirect branch prediction barrier (IBPB) | |
65 | + feature when running in secure environment, | |
66 | + to avoid performance overhead. | |
67 | + | |
68 | nosmap [X86] | |
69 | Disable SMAP (Supervisor Mode Access Prevention) | |
70 | even if it is supported by processor. | |
71 | diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h | |
72 | index f15120ada161..d665daab3f84 100644 | |
73 | --- a/arch/x86/include/asm/mwait.h | |
74 | +++ b/arch/x86/include/asm/mwait.h | |
75 | @@ -107,14 +107,14 @@ static inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) | |
76 | mb(); | |
77 | } | |
78 | ||
79 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
80 | + if (ibrs_inuse) | |
81 | native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); | |
82 | ||
83 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | |
84 | if (!need_resched()) | |
85 | __mwait(eax, ecx); | |
86 | ||
87 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
88 | + if (ibrs_inuse) | |
89 | native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS); | |
90 | } | |
91 | current_clr_polling(); | |
92 | diff --git a/arch/x86/include/asm/spec_ctrl.h b/arch/x86/include/asm/spec_ctrl.h | |
93 | index 55ee1f36bda2..4c69e51261cc 100644 | |
94 | --- a/arch/x86/include/asm/spec_ctrl.h | |
95 | +++ b/arch/x86/include/asm/spec_ctrl.h | |
96 | @@ -8,6 +8,9 @@ | |
97 | ||
98 | #ifdef __ASSEMBLY__ | |
99 | ||
100 | +.extern use_ibrs | |
101 | +.extern use_ibpb | |
102 | + | |
103 | #define __ASM_ENABLE_IBRS \ | |
104 | pushq %rax; \ | |
105 | pushq %rcx; \ | |
106 | @@ -104,15 +107,30 @@ | |
107 | add $(32*8), %rsp; | |
108 | ||
109 | .macro ENABLE_IBRS | |
110 | -ALTERNATIVE "", __stringify(__ASM_ENABLE_IBRS), X86_FEATURE_SPEC_CTRL | |
111 | + testl $1, use_ibrs | |
112 | + jz 10f | |
113 | + __ASM_ENABLE_IBRS | |
114 | + jmp 20f | |
115 | +10: | |
116 | + lfence | |
117 | +20: | |
118 | .endm | |
119 | ||
120 | .macro ENABLE_IBRS_CLOBBER | |
121 | -ALTERNATIVE "", __stringify(__ASM_ENABLE_IBRS_CLOBBER), X86_FEATURE_SPEC_CTRL | |
122 | + testl $1, use_ibrs | |
123 | + jz 11f | |
124 | + __ASM_ENABLE_IBRS_CLOBBER | |
125 | + jmp 21f | |
126 | +11: | |
127 | + lfence | |
128 | +21: | |
129 | .endm | |
130 | ||
131 | .macro DISABLE_IBRS | |
132 | -ALTERNATIVE "", __stringify(__ASM_DISABLE_IBRS), X86_FEATURE_SPEC_CTRL | |
133 | + testl $1, use_ibrs | |
134 | + jz 9f | |
135 | + __ASM_DISABLE_IBRS | |
136 | +9: | |
137 | .endm | |
138 | ||
139 | .macro STUFF_RSB | |
140 | diff --git a/include/linux/smp.h b/include/linux/smp.h | |
141 | index 68123c1fe549..e2935c0a1bb4 100644 | |
142 | --- a/include/linux/smp.h | |
143 | +++ b/include/linux/smp.h | |
144 | @@ -50,6 +50,93 @@ void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), | |
145 | ||
146 | int smp_call_function_single_async(int cpu, struct call_single_data *csd); | |
147 | ||
148 | +#ifdef CONFIG_X86 | |
149 | +/* indicate usage of IBRS to control execution speculation */ | |
150 | +extern int use_ibrs; | |
151 | +extern u32 sysctl_ibrs_enabled; | |
152 | +extern struct mutex spec_ctrl_mutex; | |
153 | +#define ibrs_supported (use_ibrs & 0x2) | |
154 | +#define ibrs_disabled (use_ibrs & 0x4) | |
155 | +static inline void set_ibrs_inuse(void) | |
156 | +{ | |
157 | + if (ibrs_supported) | |
158 | + use_ibrs |= 0x1; | |
159 | +} | |
160 | +static inline void clear_ibrs_inuse(void) | |
161 | +{ | |
162 | + use_ibrs &= ~0x1; | |
163 | +} | |
164 | +static inline int check_ibrs_inuse(void) | |
165 | +{ | |
166 | + if (use_ibrs & 0x1) | |
167 | + return 1; | |
168 | + else | |
169 | + /* rmb to prevent wrong speculation for security */ | |
170 | + rmb(); | |
171 | + return 0; | |
172 | +} | |
173 | +static inline void set_ibrs_supported(void) | |
174 | +{ | |
175 | + use_ibrs |= 0x2; | |
176 | + if (!ibrs_disabled) | |
177 | + set_ibrs_inuse(); | |
178 | +} | |
179 | +static inline void set_ibrs_disabled(void) | |
180 | +{ | |
181 | + use_ibrs |= 0x4; | |
182 | + if (check_ibrs_inuse()) | |
183 | + clear_ibrs_inuse(); | |
184 | +} | |
185 | +static inline void clear_ibrs_disabled(void) | |
186 | +{ | |
187 | + use_ibrs &= ~0x4; | |
188 | + set_ibrs_inuse(); | |
189 | +} | |
190 | +#define ibrs_inuse (check_ibrs_inuse()) | |
191 | + | |
192 | +/* indicate usage of IBPB to control execution speculation */ | |
193 | +extern int use_ibpb; | |
194 | +extern u32 sysctl_ibpb_enabled; | |
195 | +#define ibpb_supported (use_ibpb & 0x2) | |
196 | +#define ibpb_disabled (use_ibpb & 0x4) | |
197 | +static inline void set_ibpb_inuse(void) | |
198 | +{ | |
199 | + if (ibpb_supported) | |
200 | + use_ibpb |= 0x1; | |
201 | +} | |
202 | +static inline void clear_ibpb_inuse(void) | |
203 | +{ | |
204 | + use_ibpb &= ~0x1; | |
205 | +} | |
206 | +static inline int check_ibpb_inuse(void) | |
207 | +{ | |
208 | + if (use_ibpb & 0x1) | |
209 | + return 1; | |
210 | + else | |
211 | + /* rmb to prevent wrong speculation for security */ | |
212 | + rmb(); | |
213 | + return 0; | |
214 | +} | |
215 | +static inline void set_ibpb_supported(void) | |
216 | +{ | |
217 | + use_ibpb |= 0x2; | |
218 | + if (!ibpb_disabled) | |
219 | + set_ibpb_inuse(); | |
220 | +} | |
221 | +static inline void set_ibpb_disabled(void) | |
222 | +{ | |
223 | + use_ibpb |= 0x4; | |
224 | + if (check_ibpb_inuse()) | |
225 | + clear_ibpb_inuse(); | |
226 | +} | |
227 | +static inline void clear_ibpb_disabled(void) | |
228 | +{ | |
229 | + use_ibpb &= ~0x4; | |
230 | + set_ibpb_inuse(); | |
231 | +} | |
232 | +#define ibpb_inuse (check_ibpb_inuse()) | |
233 | +#endif | |
234 | + | |
235 | #ifdef CONFIG_SMP | |
236 | ||
237 | #include <linux/preempt.h> | |
238 | diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c | |
239 | index f1d94c73625a..c69ea2efbed1 100644 | |
240 | --- a/arch/x86/kernel/cpu/intel.c | |
241 | +++ b/arch/x86/kernel/cpu/intel.c | |
242 | @@ -628,10 +628,17 @@ static void init_intel(struct cpuinfo_x86 *c) | |
243 | ||
244 | init_intel_misc_features(c); | |
245 | ||
246 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
247 | + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { | |
248 | printk_once(KERN_INFO "FEATURE SPEC_CTRL Present\n"); | |
249 | - else | |
250 | + set_ibrs_supported(); | |
251 | + set_ibpb_supported(); | |
252 | + if (ibrs_inuse) | |
253 | + sysctl_ibrs_enabled = 1; | |
254 | + if (ibpb_inuse) | |
255 | + sysctl_ibpb_enabled = 1; | |
256 | + } else { | |
257 | printk_once(KERN_INFO "FEATURE SPEC_CTRL Not Present\n"); | |
258 | + } | |
259 | } | |
260 | ||
261 | #ifdef CONFIG_X86_32 | |
262 | diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c | |
263 | index c4fa4a85d4cb..6450aeda72fc 100644 | |
264 | --- a/arch/x86/kernel/cpu/microcode/core.c | |
265 | +++ b/arch/x86/kernel/cpu/microcode/core.c | |
266 | @@ -535,6 +535,17 @@ static ssize_t reload_store(struct device *dev, | |
267 | } | |
268 | if (!ret) | |
269 | perf_check_microcode(); | |
270 | + | |
271 | + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { | |
272 | + printk_once(KERN_INFO "FEATURE SPEC_CTRL Present\n"); | |
273 | + set_ibrs_supported(); | |
274 | + set_ibpb_supported(); | |
275 | + if (ibrs_inuse) | |
276 | + sysctl_ibrs_enabled = 1; | |
277 | + if (ibpb_inuse) | |
278 | + sysctl_ibpb_enabled = 1; | |
279 | + } | |
280 | + | |
281 | mutex_unlock(µcode_mutex); | |
282 | put_online_cpus(); | |
283 | ||
284 | diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c | |
285 | index 3adb3806a284..3fdf5358998e 100644 | |
286 | --- a/arch/x86/kernel/process.c | |
287 | +++ b/arch/x86/kernel/process.c | |
288 | @@ -447,16 +447,16 @@ static __cpuidle void mwait_idle(void) | |
289 | mb(); /* quirk */ | |
290 | } | |
291 | ||
292 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
293 | + if (ibrs_inuse) | |
294 | native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); | |
295 | ||
296 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | |
297 | if (!need_resched()) { | |
298 | __sti_mwait(0, 0); | |
299 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
300 | + if (ibrs_inuse) | |
301 | native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS); | |
302 | } else { | |
303 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
304 | + if (ibrs_inuse) | |
305 | native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS); | |
306 | local_irq_enable(); | |
307 | } | |
308 | diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c | |
309 | index a652bff7add4..9317aa4a7446 100644 | |
310 | --- a/arch/x86/kernel/smpboot.c | |
311 | +++ b/arch/x86/kernel/smpboot.c | |
312 | @@ -1693,14 +1693,14 @@ void native_play_dead(void) | |
313 | play_dead_common(); | |
314 | tboot_shutdown(TB_SHUTDOWN_WFS); | |
315 | ||
316 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
317 | + if (ibrs_inuse) | |
318 | native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); | |
319 | ||
320 | mwait_play_dead(); /* Only returns on failure */ | |
321 | if (cpuidle_play_dead()) | |
322 | hlt_play_dead(); | |
323 | ||
324 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
325 | + if (ibrs_inuse) | |
326 | native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS); | |
327 | } | |
328 | ||
329 | diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c | |
330 | index 496884b6467f..d2168203bddc 100644 | |
331 | --- a/arch/x86/kvm/vmx.c | |
332 | +++ b/arch/x86/kvm/vmx.c | |
333 | @@ -2269,7 +2269,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |
334 | if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) { | |
335 | per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs; | |
336 | vmcs_load(vmx->loaded_vmcs->vmcs); | |
337 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
338 | + if (ibpb_inuse) | |
339 | native_wrmsrl(MSR_IA32_PRED_CMD, FEATURE_SET_IBPB); | |
340 | } | |
341 | ||
342 | @@ -9102,7 +9102,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) | |
343 | ||
344 | atomic_switch_perf_msrs(vmx); | |
345 | ||
346 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
347 | + if (ibrs_inuse) | |
348 | add_atomic_switch_msr(vmx, MSR_IA32_SPEC_CTRL, | |
349 | vcpu->arch.spec_ctrl, FEATURE_ENABLE_IBRS); | |
350 | ||
351 | diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c | |
352 | index b088463973e4..72a174642550 100644 | |
353 | --- a/arch/x86/lib/delay.c | |
354 | +++ b/arch/x86/lib/delay.c | |
355 | @@ -107,8 +107,7 @@ static void delay_mwaitx(unsigned long __loops) | |
356 | for (;;) { | |
357 | delay = min_t(u64, MWAITX_MAX_LOOPS, loops); | |
358 | ||
359 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) && | |
360 | - (delay > IBRS_DISABLE_THRESHOLD)) | |
361 | + if (ibrs_inuse && (delay > IBRS_DISABLE_THRESHOLD)) | |
362 | native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); | |
363 | ||
364 | /* | |
365 | @@ -124,8 +123,7 @@ static void delay_mwaitx(unsigned long __loops) | |
366 | */ | |
367 | __mwaitx(MWAITX_DISABLE_CSTATES, delay, MWAITX_ECX_TIMER_ENABLE); | |
368 | ||
369 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) && | |
370 | - (delay > IBRS_DISABLE_THRESHOLD)) | |
371 | + if (ibrs_inuse && (delay > IBRS_DISABLE_THRESHOLD)) | |
372 | native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS); | |
373 | ||
374 | end = rdtsc_ordered(); | |
375 | diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c | |
376 | index 301e6efbc514..6365f769de3d 100644 | |
377 | --- a/arch/x86/mm/tlb.c | |
378 | +++ b/arch/x86/mm/tlb.c | |
379 | @@ -221,7 +221,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, | |
380 | bool need_flush; | |
381 | ||
382 | /* Null tsk means switching to kernel, so that's safe */ | |
383 | - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) && tsk && | |
384 | + if (ibpb_inuse && tsk && | |
385 | ___ptrace_may_access(tsk, current, PTRACE_MODE_IBPB)) | |
386 | native_wrmsrl(MSR_IA32_PRED_CMD, FEATURE_SET_IBPB); | |
387 | ||
388 | diff --git a/kernel/smp.c b/kernel/smp.c | |
389 | index 3061483cb3ad..3bece045f4a4 100644 | |
390 | --- a/kernel/smp.c | |
391 | +++ b/kernel/smp.c | |
392 | @@ -498,6 +498,26 @@ EXPORT_SYMBOL(smp_call_function); | |
393 | unsigned int setup_max_cpus = NR_CPUS; | |
394 | EXPORT_SYMBOL(setup_max_cpus); | |
395 | ||
396 | +#ifdef CONFIG_X86 | |
397 | +/* | |
398 | + * use IBRS | |
399 | + * bit 0 = indicate if ibrs is currently in use | |
400 | + * bit 1 = indicate if system supports ibrs | |
401 | + * bit 2 = indicate if admin disables ibrs | |
402 | +*/ | |
403 | + | |
404 | +int use_ibrs; | |
405 | +EXPORT_SYMBOL(use_ibrs); | |
406 | + | |
407 | +/* | |
408 | + * use IBRS | |
409 | + * bit 0 = indicate if ibpb is currently in use | |
410 | + * bit 1 = indicate if system supports ibpb | |
411 | + * bit 2 = indicate if admin disables ibpb | |
412 | +*/ | |
413 | +int use_ibpb; | |
414 | +EXPORT_SYMBOL(use_ibpb); | |
415 | +#endif | |
416 | ||
417 | /* | |
418 | * Setup routine for controlling SMP activation | |
419 | @@ -522,6 +542,27 @@ static int __init nosmp(char *str) | |
420 | ||
421 | early_param("nosmp", nosmp); | |
422 | ||
423 | +#ifdef CONFIG_X86 | |
424 | +static int __init noibrs(char *str) | |
425 | +{ | |
426 | + set_ibrs_disabled(); | |
427 | + | |
428 | + return 0; | |
429 | +} | |
430 | + | |
431 | +early_param("noibrs", noibrs); | |
432 | + | |
433 | +static int __init noibpb(char *str) | |
434 | +{ | |
435 | + set_ibpb_disabled(); | |
436 | + | |
437 | + return 0; | |
438 | +} | |
439 | + | |
440 | +early_param("noibpb", noibpb); | |
441 | +#endif | |
442 | + | |
443 | + | |
444 | /* this is hard limit */ | |
445 | static int __init nrcpus(char *str) | |
446 | { | |
447 | diff --git a/kernel/sysctl.c b/kernel/sysctl.c | |
448 | index 7ab08d5728e6..69c37bd6251a 100644 | |
449 | --- a/kernel/sysctl.c | |
450 | +++ b/kernel/sysctl.c | |
451 | @@ -72,6 +72,7 @@ | |
452 | #include <asm/processor.h> | |
453 | ||
454 | #ifdef CONFIG_X86 | |
455 | +#include <asm/msr.h> | |
456 | #include <asm/nmi.h> | |
457 | #include <asm/stacktrace.h> | |
458 | #include <asm/io.h> | |
459 | @@ -222,6 +223,15 @@ static int proc_dostring_coredump(struct ctl_table *table, int write, | |
460 | void __user *buffer, size_t *lenp, loff_t *ppos); | |
461 | #endif | |
462 | ||
463 | +#ifdef CONFIG_X86 | |
464 | +int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write, | |
465 | + void __user *buffer, size_t *lenp, loff_t *ppos); | |
466 | +int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write, | |
467 | + void __user *buffer, size_t *lenp, loff_t *ppos); | |
468 | +int proc_dointvec_ibrs_dump(struct ctl_table *table, int write, | |
469 | + void __user *buffer, size_t *lenp, loff_t *ppos); | |
470 | +#endif | |
471 | + | |
472 | #ifdef CONFIG_MAGIC_SYSRQ | |
473 | /* Note: sysrq code uses it's own private copy */ | |
474 | static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; | |
475 | @@ -258,6 +268,12 @@ extern struct ctl_table epoll_table[]; | |
476 | int sysctl_legacy_va_layout; | |
477 | #endif | |
478 | ||
479 | +u32 sysctl_ibrs_dump = 0; | |
480 | +u32 sysctl_ibrs_enabled = 0; | |
481 | +EXPORT_SYMBOL(sysctl_ibrs_enabled); | |
482 | +u32 sysctl_ibpb_enabled = 0; | |
483 | +EXPORT_SYMBOL(sysctl_ibpb_enabled); | |
484 | + | |
485 | /* The default sysctl tables: */ | |
486 | ||
487 | static struct ctl_table sysctl_base_table[] = { | |
488 | @@ -1241,6 +1257,35 @@ static struct ctl_table kern_table[] = { | |
489 | .extra1 = &zero, | |
490 | .extra2 = &one, | |
491 | }, | |
492 | +#endif | |
493 | +#ifdef CONFIG_X86 | |
494 | + { | |
495 | + .procname = "ibrs_enabled", | |
496 | + .data = &sysctl_ibrs_enabled, | |
497 | + .maxlen = sizeof(unsigned int), | |
498 | + .mode = 0644, | |
499 | + .proc_handler = proc_dointvec_ibrs_ctrl, | |
500 | + .extra1 = &zero, | |
501 | + .extra2 = &two, | |
502 | + }, | |
503 | + { | |
504 | + .procname = "ibpb_enabled", | |
505 | + .data = &sysctl_ibpb_enabled, | |
506 | + .maxlen = sizeof(unsigned int), | |
507 | + .mode = 0644, | |
508 | + .proc_handler = proc_dointvec_ibpb_ctrl, | |
509 | + .extra1 = &zero, | |
510 | + .extra2 = &one, | |
511 | + }, | |
512 | + { | |
513 | + .procname = "ibrs_dump", | |
514 | + .data = &sysctl_ibrs_dump, | |
515 | + .maxlen = sizeof(unsigned int), | |
516 | + .mode = 0644, | |
517 | + .proc_handler = proc_dointvec_ibrs_dump, | |
518 | + .extra1 = &zero, | |
519 | + .extra2 = &one, | |
520 | + }, | |
521 | #endif | |
522 | { } | |
523 | }; | |
524 | @@ -2585,6 +2630,86 @@ int proc_dointvec_minmax(struct ctl_table *table, int write, | |
525 | do_proc_dointvec_minmax_conv, ¶m); | |
526 | } | |
527 | ||
528 | +#ifdef CONFIG_X86 | |
529 | +int proc_dointvec_ibrs_dump(struct ctl_table *table, int write, | |
530 | + void __user *buffer, size_t *lenp, loff_t *ppos) | |
531 | +{ | |
532 | + int ret; | |
533 | + unsigned int cpu; | |
534 | + | |
535 | + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | |
536 | + printk("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled); | |
537 | + printk("use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); | |
538 | + for_each_online_cpu(cpu) { | |
539 | + u64 val; | |
540 | + | |
541 | + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) | |
542 | + rdmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, &val); | |
543 | + else | |
544 | + val = 0; | |
545 | + printk("read cpu %d ibrs val %lu\n", cpu, (unsigned long) val); | |
546 | + } | |
547 | + return ret; | |
548 | +} | |
549 | + | |
550 | +int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write, | |
551 | + void __user *buffer, size_t *lenp, loff_t *ppos) | |
552 | +{ | |
553 | + int ret; | |
554 | + unsigned int cpu; | |
555 | + | |
556 | + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | |
557 | + pr_debug("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled); | |
558 | + pr_debug("before:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); | |
559 | + if (sysctl_ibrs_enabled == 0) { | |
560 | + /* always set IBRS off */ | |
561 | + set_ibrs_disabled(); | |
562 | + if (ibrs_supported) { | |
563 | + for_each_online_cpu(cpu) | |
564 | + wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, 0x0); | |
565 | + } | |
566 | + } else if (sysctl_ibrs_enabled == 2) { | |
567 | + /* always set IBRS on, even in user space */ | |
568 | + clear_ibrs_disabled(); | |
569 | + if (ibrs_supported) { | |
570 | + for_each_online_cpu(cpu) | |
571 | + wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS); | |
572 | + } else { | |
573 | + sysctl_ibrs_enabled = 0; | |
574 | + } | |
575 | + } else if (sysctl_ibrs_enabled == 1) { | |
576 | + /* use IBRS in kernel */ | |
577 | + clear_ibrs_disabled(); | |
578 | + if (!ibrs_inuse) | |
579 | + /* platform don't support ibrs */ | |
580 | + sysctl_ibrs_enabled = 0; | |
581 | + } | |
582 | + pr_debug("after:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); | |
583 | + return ret; | |
584 | +} | |
585 | + | |
586 | +int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write, | |
587 | + void __user *buffer, size_t *lenp, loff_t *ppos) | |
588 | +{ | |
589 | + int ret; | |
590 | + | |
591 | + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | |
592 | + pr_debug("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled); | |
593 | + pr_debug("before:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); | |
594 | + if (sysctl_ibpb_enabled == 0) | |
595 | + set_ibpb_disabled(); | |
596 | + else if (sysctl_ibpb_enabled == 1) { | |
597 | + clear_ibpb_disabled(); | |
598 | + if (!ibpb_inuse) | |
599 | + /* platform don't support ibpb */ | |
600 | + sysctl_ibpb_enabled = 0; | |
601 | + } | |
602 | + pr_debug("after:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); | |
603 | + return ret; | |
604 | +} | |
605 | +#endif | |
606 | + | |
607 | + | |
608 | struct do_proc_douintvec_minmax_conv_param { | |
609 | unsigned int *min; | |
610 | unsigned int *max; | |
611 | -- | |
612 | 2.14.2 | |
613 |