Skip to content

Commit da28512

Browse files
dwmw2KAGA-KOKO
authored andcommitted
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 <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: Rik van Riel <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: [email protected] Cc: Peter Zijlstra <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Jiri Kosina <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Kees Cook <[email protected]> Cc: Tim Chen <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Paul Turner <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 76b0438 commit da28512

File tree

4 files changed

+195
-5
lines changed

4 files changed

+195
-5
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2599,6 +2599,11 @@
25992599
nosmt [KNL,S390] Disable symmetric multithreading (SMT).
26002600
Equivalent to smt=1.
26012601

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+
26022607
noxsave [BUGS=X86] Disables x86 extended register state save
26032608
and restore using xsave. The kernel will fallback to
26042609
enabling legacy floating-point and sse state.
@@ -3908,6 +3913,29 @@
39083913
sonypi.*= [HW] Sony Programmable I/O Control Device driver
39093914
See Documentation/laptops/sonypi.txt
39103915

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+
39113939
spia_io_base= [HW,MTD]
39123940
spia_fio_base=
39133941
spia_pedr=

arch/x86/include/asm/nospec-branch.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,15 @@
124124
# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
125125
#endif
126126

127+
/* The Spectre V2 mitigation variants */
128+
enum 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+
127137
#endif /* __ASSEMBLY__ */
128138
#endif /* __NOSPEC_BRANCH_H__ */

arch/x86/kernel/cpu/bugs.c

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#include <linux/init.h>
1212
#include <linux/utsname.h>
1313
#include <linux/cpu.h>
14+
15+
#include <asm/nospec-branch.h>
16+
#include <asm/cmdline.h>
1417
#include <asm/bugs.h>
1518
#include <asm/processor.h>
1619
#include <asm/processor-flags.h>
@@ -21,6 +24,8 @@
2124
#include <asm/pgtable.h>
2225
#include <asm/set_memory.h>
2326

27+
static void __init spectre_v2_select_mitigation(void);
28+
2429
void __init check_bugs(void)
2530
{
2631
identify_boot_cpu();
@@ -30,6 +35,9 @@ void __init check_bugs(void)
3035
print_cpu_info(&boot_cpu_data);
3136
}
3237

38+
/* Select the proper spectre mitigation before patching alternatives */
39+
spectre_v2_select_mitigation();
40+
3341
#ifdef CONFIG_X86_32
3442
/*
3543
* Check whether we are able to run this kernel safely on SMP.
@@ -62,6 +70,153 @@ void __init check_bugs(void)
6270
#endif
6371
}
6472

73+
/* The kernel command line selection */
74+
enum 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+
83+
static 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+
94+
static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
95+
96+
static 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+
102+
static 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+
108+
static inline bool retp_compiler(void)
109+
{
110+
return __is_defined(RETPOLINE);
111+
}
112+
113+
static 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+
120+
static 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;
153+
disable:
154+
spec2_print_if_insecure("disabled on command line.");
155+
return SPECTRE_V2_CMD_NONE;
156+
}
157+
158+
static 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+
196+
retpoline_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+
65220
#ifdef CONFIG_SYSFS
66221
ssize_t cpu_show_meltdown(struct device *dev,
67222
struct device_attribute *attr, char *buf)
@@ -86,6 +241,7 @@ ssize_t cpu_show_spectre_v2(struct device *dev,
86241
{
87242
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
88243
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]);
90246
}
91247
#endif

arch/x86/kernel/cpu/common.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -905,10 +905,6 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
905905
setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
906906
setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
907907

908-
#ifdef CONFIG_RETPOLINE
909-
setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
910-
#endif
911-
912908
fpu__init_system(c);
913909

914910
#ifdef CONFIG_X86_32

0 commit comments

Comments
 (0)