aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/bugs.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/cpu/bugs.c')
-rw-r--r--arch/x86/kernel/cpu/bugs.c134
1 files changed, 98 insertions, 36 deletions
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 390b3dc3d438..71949bf2de5a 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -11,6 +11,7 @@
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#include <linux/module.h>
14 15
15#include <asm/nospec-branch.h> 16#include <asm/nospec-branch.h>
16#include <asm/cmdline.h> 17#include <asm/cmdline.h>
@@ -90,20 +91,41 @@ static const char *spectre_v2_strings[] = {
90}; 91};
91 92
92#undef pr_fmt 93#undef pr_fmt
93#define pr_fmt(fmt) "Spectre V2 mitigation: " fmt 94#define pr_fmt(fmt) "Spectre V2 : " fmt
94 95
95static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; 96static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
96 97
98#ifdef RETPOLINE
99static bool spectre_v2_bad_module;
100
101bool retpoline_module_ok(bool has_retpoline)
102{
103 if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline)
104 return true;
105
106 pr_err("System may be vulnerable to spectre v2\n");
107 spectre_v2_bad_module = true;
108 return false;
109}
110
111static inline const char *spectre_v2_module_string(void)
112{
113 return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
114}
115#else
116static inline const char *spectre_v2_module_string(void) { return ""; }
117#endif
118
97static void __init spec2_print_if_insecure(const char *reason) 119static void __init spec2_print_if_insecure(const char *reason)
98{ 120{
99 if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) 121 if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
100 pr_info("%s\n", reason); 122 pr_info("%s selected on command line.\n", reason);
101} 123}
102 124
103static void __init spec2_print_if_secure(const char *reason) 125static void __init spec2_print_if_secure(const char *reason)
104{ 126{
105 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) 127 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
106 pr_info("%s\n", reason); 128 pr_info("%s selected on command line.\n", reason);
107} 129}
108 130
109static inline bool retp_compiler(void) 131static inline bool retp_compiler(void)
@@ -118,42 +140,68 @@ static inline bool match_option(const char *arg, int arglen, const char *opt)
118 return len == arglen && !strncmp(arg, opt, len); 140 return len == arglen && !strncmp(arg, opt, len);
119} 141}
120 142
143static const struct {
144 const char *option;
145 enum spectre_v2_mitigation_cmd cmd;
146 bool secure;
147} mitigation_options[] = {
148 { "off", SPECTRE_V2_CMD_NONE, false },
149 { "on", SPECTRE_V2_CMD_FORCE, true },
150 { "retpoline", SPECTRE_V2_CMD_RETPOLINE, false },
151 { "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_AMD, false },
152 { "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
153 { "auto", SPECTRE_V2_CMD_AUTO, false },
154};
155
121static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) 156static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
122{ 157{
123 char arg[20]; 158 char arg[20];
124 int ret; 159 int ret, i;
125 160 enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO;
126 ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, 161
127 sizeof(arg)); 162 if (cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
128 if (ret > 0) { 163 return SPECTRE_V2_CMD_NONE;
129 if (match_option(arg, ret, "off")) { 164 else {
130 goto disable; 165 ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
131 } else if (match_option(arg, ret, "on")) { 166 sizeof(arg));
132 spec2_print_if_secure("force enabled on command line."); 167 if (ret < 0)
133 return SPECTRE_V2_CMD_FORCE; 168 return SPECTRE_V2_CMD_AUTO;
134 } else if (match_option(arg, ret, "retpoline")) { 169
135 spec2_print_if_insecure("retpoline selected on command line."); 170 for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
136 return SPECTRE_V2_CMD_RETPOLINE; 171 if (!match_option(arg, ret, mitigation_options[i].option))
137 } else if (match_option(arg, ret, "retpoline,amd")) { 172 continue;
138 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { 173 cmd = mitigation_options[i].cmd;
139 pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n"); 174 break;
140 return SPECTRE_V2_CMD_AUTO; 175 }
141 } 176
142 spec2_print_if_insecure("AMD retpoline selected on command line."); 177 if (i >= ARRAY_SIZE(mitigation_options)) {
143 return SPECTRE_V2_CMD_RETPOLINE_AMD; 178 pr_err("unknown option (%s). Switching to AUTO select\n",
144 } else if (match_option(arg, ret, "retpoline,generic")) { 179 mitigation_options[i].option);
145 spec2_print_if_insecure("generic retpoline selected on command line.");
146 return SPECTRE_V2_CMD_RETPOLINE_GENERIC;
147 } else if (match_option(arg, ret, "auto")) {
148 return SPECTRE_V2_CMD_AUTO; 180 return SPECTRE_V2_CMD_AUTO;
149 } 181 }
150 } 182 }
151 183
152 if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2")) 184 if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
185 cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
186 cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
187 !IS_ENABLED(CONFIG_RETPOLINE)) {
188 pr_err("%s selected but not compiled in. Switching to AUTO select\n",
189 mitigation_options[i].option);
153 return SPECTRE_V2_CMD_AUTO; 190 return SPECTRE_V2_CMD_AUTO;
154disable: 191 }
155 spec2_print_if_insecure("disabled on command line."); 192
156 return SPECTRE_V2_CMD_NONE; 193 if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD &&
194 boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
195 pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
196 return SPECTRE_V2_CMD_AUTO;
197 }
198
199 if (mitigation_options[i].secure)
200 spec2_print_if_secure(mitigation_options[i].option);
201 else
202 spec2_print_if_insecure(mitigation_options[i].option);
203
204 return cmd;
157} 205}
158 206
159/* Check for Skylake-like CPUs (for RSB handling) */ 207/* Check for Skylake-like CPUs (for RSB handling) */
@@ -191,10 +239,10 @@ static void __init spectre_v2_select_mitigation(void)
191 return; 239 return;
192 240
193 case SPECTRE_V2_CMD_FORCE: 241 case SPECTRE_V2_CMD_FORCE:
194 /* FALLTRHU */
195 case SPECTRE_V2_CMD_AUTO: 242 case SPECTRE_V2_CMD_AUTO:
196 goto retpoline_auto; 243 if (IS_ENABLED(CONFIG_RETPOLINE))
197 244 goto retpoline_auto;
245 break;
198 case SPECTRE_V2_CMD_RETPOLINE_AMD: 246 case SPECTRE_V2_CMD_RETPOLINE_AMD:
199 if (IS_ENABLED(CONFIG_RETPOLINE)) 247 if (IS_ENABLED(CONFIG_RETPOLINE))
200 goto retpoline_amd; 248 goto retpoline_amd;
@@ -249,6 +297,12 @@ retpoline_auto:
249 setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); 297 setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
250 pr_info("Filling RSB on context switch\n"); 298 pr_info("Filling RSB on context switch\n");
251 } 299 }
300
301 /* Initialize Indirect Branch Prediction Barrier if supported */
302 if (boot_cpu_has(X86_FEATURE_IBPB)) {
303 setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
304 pr_info("Enabling Indirect Branch Prediction Barrier\n");
305 }
252} 306}
253 307
254#undef pr_fmt 308#undef pr_fmt
@@ -269,7 +323,7 @@ ssize_t cpu_show_spectre_v1(struct device *dev,
269{ 323{
270 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) 324 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1))
271 return sprintf(buf, "Not affected\n"); 325 return sprintf(buf, "Not affected\n");
272 return sprintf(buf, "Vulnerable\n"); 326 return sprintf(buf, "Mitigation: __user pointer sanitization\n");
273} 327}
274 328
275ssize_t cpu_show_spectre_v2(struct device *dev, 329ssize_t cpu_show_spectre_v2(struct device *dev,
@@ -278,6 +332,14 @@ ssize_t cpu_show_spectre_v2(struct device *dev,
278 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) 332 if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
279 return sprintf(buf, "Not affected\n"); 333 return sprintf(buf, "Not affected\n");
280 334
281 return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]); 335 return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
336 boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "",
337 spectre_v2_module_string());
282} 338}
283#endif 339#endif
340
341void __ibp_barrier(void)
342{
343 __wrmsr(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, 0);
344}
345EXPORT_SYMBOL_GPL(__ibp_barrier);