aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw@amazon.co.uk>2018-01-11 16:46:26 -0500
committerThomas Gleixner <tglx@linutronix.de>2018-01-11 18:14:29 -0500
commitda285121560e769cc31797bba6422eea71d473e0 (patch)
treec28344795834b8449fc63bb22c9d2a6c50edfe6c
parent76b043848fd22dbf7f8bf3a1452f8c70d557b860 (diff)
x86/spectre: Add boot time option to select Spectre v2 mitigation
Add a spectre_v2= option to select the mitigation used for the indirect branch speculation vulnerability. Currently, the only option available is retpoline, in its various forms. This will be expanded to cover the new IBRS/IBPB microcode features. The RETPOLINE_AMD feature relies on a serializing LFENCE for speculation control. For AMD hardware, only set RETPOLINE_AMD if LFENCE is a serializing instruction, which is indicated by the LFENCE_RDTSC feature. [ tglx: Folded back the LFENCE/AMD fixes and reworked it so IBRS integration becomes simple ] Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: gnomes@lxorguk.ukuu.org.uk Cc: Rik van Riel <riel@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: thomas.lendacky@amd.com Cc: Peter Zijlstra <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Jiri Kosina <jikos@kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Kees Cook <keescook@google.com> Cc: Tim Chen <tim.c.chen@linux.intel.com> Cc: Greg Kroah-Hartman <gregkh@linux-foundation.org> Cc: Paul Turner <pjt@google.com> Link: https://lkml.kernel.org/r/1515707194-20531-5-git-send-email-dwmw@amazon.co.uk
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt28
-rw-r--r--arch/x86/include/asm/nospec-branch.h10
-rw-r--r--arch/x86/kernel/cpu/bugs.c158
-rw-r--r--arch/x86/kernel/cpu/common.c4
4 files changed, 195 insertions, 5 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 905991745d26..8122b5f98ea1 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2599,6 +2599,11 @@
2599 nosmt [KNL,S390] Disable symmetric multithreading (SMT). 2599 nosmt [KNL,S390] Disable symmetric multithreading (SMT).
2600 Equivalent to smt=1. 2600 Equivalent to smt=1.
2601 2601
2602 nospectre_v2 [X86] Disable all mitigations for the Spectre variant 2
2603 (indirect branch prediction) vulnerability. System may
2604 allow data leaks with this option, which is equivalent
2605 to spectre_v2=off.
2606
2602 noxsave [BUGS=X86] Disables x86 extended register state save 2607 noxsave [BUGS=X86] Disables x86 extended register state save
2603 and restore using xsave. The kernel will fallback to 2608 and restore using xsave. The kernel will fallback to
2604 enabling legacy floating-point and sse state. 2609 enabling legacy floating-point and sse state.
@@ -3908,6 +3913,29 @@
3908 sonypi.*= [HW] Sony Programmable I/O Control Device driver 3913 sonypi.*= [HW] Sony Programmable I/O Control Device driver
3909 See Documentation/laptops/sonypi.txt 3914 See Documentation/laptops/sonypi.txt
3910 3915
3916 spectre_v2= [X86] Control mitigation of Spectre variant 2
3917 (indirect branch speculation) vulnerability.
3918
3919 on - unconditionally enable
3920 off - unconditionally disable
3921 auto - kernel detects whether your CPU model is
3922 vulnerable
3923
3924 Selecting 'on' will, and 'auto' may, choose a
3925 mitigation method at run time according to the
3926 CPU, the available microcode, the setting of the
3927 CONFIG_RETPOLINE configuration option, and the
3928 compiler with which the kernel was built.
3929
3930 Specific mitigations can also be selected manually:
3931
3932 retpoline - replace indirect branches
3933 retpoline,generic - google's original retpoline
3934 retpoline,amd - AMD-specific minimal thunk
3935
3936 Not specifying this option is equivalent to
3937 spectre_v2=auto.
3938
3911 spia_io_base= [HW,MTD] 3939 spia_io_base= [HW,MTD]
3912 spia_fio_base= 3940 spia_fio_base=
3913 spia_pedr= 3941 spia_pedr=
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index e20e92ef2ca8..ea034fa6e261 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -124,5 +124,15 @@
124# define THUNK_TARGET(addr) [thunk_target] "rm" (addr) 124# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
125#endif 125#endif
126 126
127/* The Spectre V2 mitigation variants */
128enum spectre_v2_mitigation {
129 SPECTRE_V2_NONE,
130 SPECTRE_V2_RETPOLINE_MINIMAL,
131 SPECTRE_V2_RETPOLINE_MINIMAL_AMD,
132 SPECTRE_V2_RETPOLINE_GENERIC,
133 SPECTRE_V2_RETPOLINE_AMD,
134 SPECTRE_V2_IBRS,
135};
136
127#endif /* __ASSEMBLY__ */ 137#endif /* __ASSEMBLY__ */
128#endif /* __NOSPEC_BRANCH_H__ */ 138#endif /* __NOSPEC_BRANCH_H__ */
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 76ad6cb44b40..e4dc26185aa7 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -11,6 +11,9 @@
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/utsname.h> 12#include <linux/utsname.h>
13#include <linux/cpu.h> 13#include <linux/cpu.h>
14
15#include <asm/nospec-branch.h>
16#include <asm/cmdline.h>
14#include <asm/bugs.h> 17#include <asm/bugs.h>
15#include <asm/processor.h> 18#include <asm/processor.h>
16#include <asm/processor-flags.h> 19#include <asm/processor-flags.h>
@@ -21,6 +24,8 @@
21#include <asm/pgtable.h> 24#include <asm/pgtable.h>
22#include <asm/set_memory.h> 25#include <asm/set_memory.h>
23 26
27static void __init spectre_v2_select_mitigation(void);
28
24void __init check_bugs(void) 29void __init check_bugs(void)
25{ 30{
26 identify_boot_cpu(); 31 identify_boot_cpu();
@@ -30,6 +35,9 @@ void __init check_bugs(void)
30 print_cpu_info(&boot_cpu_data); 35 print_cpu_info(&boot_cpu_data);
31 } 36 }
32 37
38 /* Select the proper spectre mitigation before patching alternatives */
39 spectre_v2_select_mitigation();
40
33#ifdef CONFIG_X86_32 41#ifdef CONFIG_X86_32
34 /* 42 /*
35 * Check whether we are able to run this kernel safely on SMP. 43 * Check whether we are able to run this kernel safely on SMP.
@@ -62,6 +70,153 @@ void __init check_bugs(void)
62#endif 70#endif
63} 71}
64 72
73/* The kernel command line selection */
74enum spectre_v2_mitigation_cmd {
75 SPECTRE_V2_CMD_NONE,
76 SPECTRE_V2_CMD_AUTO,
77 SPECTRE_V2_CMD_FORCE,
78 SPECTRE_V2_CMD_RETPOLINE,
79 SPECTRE_V2_CMD_RETPOLINE_GENERIC,
80 SPECTRE_V2_CMD_RETPOLINE_AMD,
81};
82
83static const char *spectre_v2_strings[] = {
84 [SPECTRE_V2_NONE] = "Vulnerable",
85 [SPECTRE_V2_RETPOLINE_MINIMAL] = "Vulnerable: Minimal generic ASM retpoline",
86 [SPECTRE_V2_RETPOLINE_MINIMAL_AMD] = "Vulnerable: Minimal AMD ASM retpoline",
87 [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline",
88 [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline",
89};
90
91#undef pr_fmt
92#define pr_fmt(fmt) "Spectre V2 mitigation: " fmt
93
94static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
95
96static void __init spec2_print_if_insecure(const char *reason)
97{
98 if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
99 pr_info("%s\n", reason);
100}
101
102static void __init spec2_print_if_secure(const char *reason)
103{
104 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
105 pr_info("%s\n", reason);
106}
107
108static inline bool retp_compiler(void)
109{
110 return __is_defined(RETPOLINE);
111}
112
113static inline bool match_option(const char *arg, int arglen, const char *opt)
114{
115 int len = strlen(opt);
116
117 return len == arglen && !strncmp(arg, opt, len);
118}
119
120static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
121{
122 char arg[20];
123 int ret;
124
125 ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
126 sizeof(arg));
127 if (ret > 0) {
128 if (match_option(arg, ret, "off")) {
129 goto disable;
130 } else if (match_option(arg, ret, "on")) {
131 spec2_print_if_secure("force enabled on command line.");
132 return SPECTRE_V2_CMD_FORCE;
133 } else if (match_option(arg, ret, "retpoline")) {
134 spec2_print_if_insecure("retpoline selected on command line.");
135 return SPECTRE_V2_CMD_RETPOLINE;
136 } else if (match_option(arg, ret, "retpoline,amd")) {
137 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
138 pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
139 return SPECTRE_V2_CMD_AUTO;
140 }
141 spec2_print_if_insecure("AMD retpoline selected on command line.");
142 return SPECTRE_V2_CMD_RETPOLINE_AMD;
143 } else if (match_option(arg, ret, "retpoline,generic")) {
144 spec2_print_if_insecure("generic retpoline selected on command line.");
145 return SPECTRE_V2_CMD_RETPOLINE_GENERIC;
146 } else if (match_option(arg, ret, "auto")) {
147 return SPECTRE_V2_CMD_AUTO;
148 }
149 }
150
151 if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
152 return SPECTRE_V2_CMD_AUTO;
153disable:
154 spec2_print_if_insecure("disabled on command line.");
155 return SPECTRE_V2_CMD_NONE;
156}
157
158static void __init spectre_v2_select_mitigation(void)
159{
160 enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
161 enum spectre_v2_mitigation mode = SPECTRE_V2_NONE;
162
163 /*
164 * If the CPU is not affected and the command line mode is NONE or AUTO
165 * then nothing to do.
166 */
167 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) &&
168 (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO))
169 return;
170
171 switch (cmd) {
172 case SPECTRE_V2_CMD_NONE:
173 return;
174
175 case SPECTRE_V2_CMD_FORCE:
176 /* FALLTRHU */
177 case SPECTRE_V2_CMD_AUTO:
178 goto retpoline_auto;
179
180 case SPECTRE_V2_CMD_RETPOLINE_AMD:
181 if (IS_ENABLED(CONFIG_RETPOLINE))
182 goto retpoline_amd;
183 break;
184 case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
185 if (IS_ENABLED(CONFIG_RETPOLINE))
186 goto retpoline_generic;
187 break;
188 case SPECTRE_V2_CMD_RETPOLINE:
189 if (IS_ENABLED(CONFIG_RETPOLINE))
190 goto retpoline_auto;
191 break;
192 }
193 pr_err("kernel not compiled with retpoline; no mitigation available!");
194 return;
195
196retpoline_auto:
197 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
198 retpoline_amd:
199 if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
200 pr_err("LFENCE not serializing. Switching to generic retpoline\n");
201 goto retpoline_generic;
202 }
203 mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD :
204 SPECTRE_V2_RETPOLINE_MINIMAL_AMD;
205 setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD);
206 setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
207 } else {
208 retpoline_generic:
209 mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC :
210 SPECTRE_V2_RETPOLINE_MINIMAL;
211 setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
212 }
213
214 spectre_v2_enabled = mode;
215 pr_info("%s\n", spectre_v2_strings[mode]);
216}
217
218#undef pr_fmt
219
65#ifdef CONFIG_SYSFS 220#ifdef CONFIG_SYSFS
66ssize_t cpu_show_meltdown(struct device *dev, 221ssize_t cpu_show_meltdown(struct device *dev,
67 struct device_attribute *attr, char *buf) 222 struct device_attribute *attr, char *buf)
@@ -86,6 +241,7 @@ ssize_t cpu_show_spectre_v2(struct device *dev,
86{ 241{
87 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) 242 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
88 return sprintf(buf, "Not affected\n"); 243 return sprintf(buf, "Not affected\n");
89 return sprintf(buf, "Vulnerable\n"); 244
245 return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]);
90} 246}
91#endif 247#endif
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 7a671d1ae3cb..372ba3fb400f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -905,10 +905,6 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
905 setup_force_cpu_bug(X86_BUG_SPECTRE_V1); 905 setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
906 setup_force_cpu_bug(X86_BUG_SPECTRE_V2); 906 setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
907 907
908#ifdef CONFIG_RETPOLINE
909 setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
910#endif
911
912 fpu__init_system(c); 908 fpu__init_system(c);
913 909
914#ifdef CONFIG_X86_32 910#ifdef CONFIG_X86_32