diff options
Diffstat (limited to 'arch/x86/kernel/cpu/bugs.c')
-rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 525 |
1 files changed, 388 insertions, 137 deletions
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index c37e66e493bf..500278f5308e 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/nospec.h> | 15 | #include <linux/nospec.h> |
16 | #include <linux/prctl.h> | 16 | #include <linux/prctl.h> |
17 | #include <linux/sched/smt.h> | ||
17 | 18 | ||
18 | #include <asm/spec-ctrl.h> | 19 | #include <asm/spec-ctrl.h> |
19 | #include <asm/cmdline.h> | 20 | #include <asm/cmdline.h> |
@@ -53,6 +54,13 @@ static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS; | |||
53 | u64 __ro_after_init x86_amd_ls_cfg_base; | 54 | u64 __ro_after_init x86_amd_ls_cfg_base; |
54 | u64 __ro_after_init x86_amd_ls_cfg_ssbd_mask; | 55 | u64 __ro_after_init x86_amd_ls_cfg_ssbd_mask; |
55 | 56 | ||
57 | /* Control conditional STIPB in switch_to() */ | ||
58 | DEFINE_STATIC_KEY_FALSE(switch_to_cond_stibp); | ||
59 | /* Control conditional IBPB in switch_mm() */ | ||
60 | DEFINE_STATIC_KEY_FALSE(switch_mm_cond_ibpb); | ||
61 | /* Control unconditional IBPB in switch_mm() */ | ||
62 | DEFINE_STATIC_KEY_FALSE(switch_mm_always_ibpb); | ||
63 | |||
56 | void __init check_bugs(void) | 64 | void __init check_bugs(void) |
57 | { | 65 | { |
58 | identify_boot_cpu(); | 66 | identify_boot_cpu(); |
@@ -123,31 +131,6 @@ void __init check_bugs(void) | |||
123 | #endif | 131 | #endif |
124 | } | 132 | } |
125 | 133 | ||
126 | /* The kernel command line selection */ | ||
127 | enum spectre_v2_mitigation_cmd { | ||
128 | SPECTRE_V2_CMD_NONE, | ||
129 | SPECTRE_V2_CMD_AUTO, | ||
130 | SPECTRE_V2_CMD_FORCE, | ||
131 | SPECTRE_V2_CMD_RETPOLINE, | ||
132 | SPECTRE_V2_CMD_RETPOLINE_GENERIC, | ||
133 | SPECTRE_V2_CMD_RETPOLINE_AMD, | ||
134 | }; | ||
135 | |||
136 | static const char *spectre_v2_strings[] = { | ||
137 | [SPECTRE_V2_NONE] = "Vulnerable", | ||
138 | [SPECTRE_V2_RETPOLINE_MINIMAL] = "Vulnerable: Minimal generic ASM retpoline", | ||
139 | [SPECTRE_V2_RETPOLINE_MINIMAL_AMD] = "Vulnerable: Minimal AMD ASM retpoline", | ||
140 | [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", | ||
141 | [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline", | ||
142 | [SPECTRE_V2_IBRS_ENHANCED] = "Mitigation: Enhanced IBRS", | ||
143 | }; | ||
144 | |||
145 | #undef pr_fmt | ||
146 | #define pr_fmt(fmt) "Spectre V2 : " fmt | ||
147 | |||
148 | static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = | ||
149 | SPECTRE_V2_NONE; | ||
150 | |||
151 | void | 134 | void |
152 | x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) | 135 | x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) |
153 | { | 136 | { |
@@ -169,6 +152,10 @@ x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) | |||
169 | static_cpu_has(X86_FEATURE_AMD_SSBD)) | 152 | static_cpu_has(X86_FEATURE_AMD_SSBD)) |
170 | hostval |= ssbd_tif_to_spec_ctrl(ti->flags); | 153 | hostval |= ssbd_tif_to_spec_ctrl(ti->flags); |
171 | 154 | ||
155 | /* Conditional STIBP enabled? */ | ||
156 | if (static_branch_unlikely(&switch_to_cond_stibp)) | ||
157 | hostval |= stibp_tif_to_spec_ctrl(ti->flags); | ||
158 | |||
172 | if (hostval != guestval) { | 159 | if (hostval != guestval) { |
173 | msrval = setguest ? guestval : hostval; | 160 | msrval = setguest ? guestval : hostval; |
174 | wrmsrl(MSR_IA32_SPEC_CTRL, msrval); | 161 | wrmsrl(MSR_IA32_SPEC_CTRL, msrval); |
@@ -202,7 +189,7 @@ x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest) | |||
202 | tif = setguest ? ssbd_spec_ctrl_to_tif(guestval) : | 189 | tif = setguest ? ssbd_spec_ctrl_to_tif(guestval) : |
203 | ssbd_spec_ctrl_to_tif(hostval); | 190 | ssbd_spec_ctrl_to_tif(hostval); |
204 | 191 | ||
205 | speculative_store_bypass_update(tif); | 192 | speculation_ctrl_update(tif); |
206 | } | 193 | } |
207 | } | 194 | } |
208 | EXPORT_SYMBOL_GPL(x86_virt_spec_ctrl); | 195 | EXPORT_SYMBOL_GPL(x86_virt_spec_ctrl); |
@@ -217,6 +204,15 @@ static void x86_amd_ssb_disable(void) | |||
217 | wrmsrl(MSR_AMD64_LS_CFG, msrval); | 204 | wrmsrl(MSR_AMD64_LS_CFG, msrval); |
218 | } | 205 | } |
219 | 206 | ||
207 | #undef pr_fmt | ||
208 | #define pr_fmt(fmt) "Spectre V2 : " fmt | ||
209 | |||
210 | static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = | ||
211 | SPECTRE_V2_NONE; | ||
212 | |||
213 | static enum spectre_v2_user_mitigation spectre_v2_user __ro_after_init = | ||
214 | SPECTRE_V2_USER_NONE; | ||
215 | |||
220 | #ifdef RETPOLINE | 216 | #ifdef RETPOLINE |
221 | static bool spectre_v2_bad_module; | 217 | static bool spectre_v2_bad_module; |
222 | 218 | ||
@@ -238,67 +234,217 @@ static inline const char *spectre_v2_module_string(void) | |||
238 | static inline const char *spectre_v2_module_string(void) { return ""; } | 234 | static inline const char *spectre_v2_module_string(void) { return ""; } |
239 | #endif | 235 | #endif |
240 | 236 | ||
241 | static void __init spec2_print_if_insecure(const char *reason) | 237 | static inline bool match_option(const char *arg, int arglen, const char *opt) |
242 | { | 238 | { |
243 | if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | 239 | int len = strlen(opt); |
244 | pr_info("%s selected on command line.\n", reason); | 240 | |
241 | return len == arglen && !strncmp(arg, opt, len); | ||
245 | } | 242 | } |
246 | 243 | ||
247 | static void __init spec2_print_if_secure(const char *reason) | 244 | /* The kernel command line selection for spectre v2 */ |
245 | enum spectre_v2_mitigation_cmd { | ||
246 | SPECTRE_V2_CMD_NONE, | ||
247 | SPECTRE_V2_CMD_AUTO, | ||
248 | SPECTRE_V2_CMD_FORCE, | ||
249 | SPECTRE_V2_CMD_RETPOLINE, | ||
250 | SPECTRE_V2_CMD_RETPOLINE_GENERIC, | ||
251 | SPECTRE_V2_CMD_RETPOLINE_AMD, | ||
252 | }; | ||
253 | |||
254 | enum spectre_v2_user_cmd { | ||
255 | SPECTRE_V2_USER_CMD_NONE, | ||
256 | SPECTRE_V2_USER_CMD_AUTO, | ||
257 | SPECTRE_V2_USER_CMD_FORCE, | ||
258 | SPECTRE_V2_USER_CMD_PRCTL, | ||
259 | SPECTRE_V2_USER_CMD_PRCTL_IBPB, | ||
260 | SPECTRE_V2_USER_CMD_SECCOMP, | ||
261 | SPECTRE_V2_USER_CMD_SECCOMP_IBPB, | ||
262 | }; | ||
263 | |||
264 | static const char * const spectre_v2_user_strings[] = { | ||
265 | [SPECTRE_V2_USER_NONE] = "User space: Vulnerable", | ||
266 | [SPECTRE_V2_USER_STRICT] = "User space: Mitigation: STIBP protection", | ||
267 | [SPECTRE_V2_USER_PRCTL] = "User space: Mitigation: STIBP via prctl", | ||
268 | [SPECTRE_V2_USER_SECCOMP] = "User space: Mitigation: STIBP via seccomp and prctl", | ||
269 | }; | ||
270 | |||
271 | static const struct { | ||
272 | const char *option; | ||
273 | enum spectre_v2_user_cmd cmd; | ||
274 | bool secure; | ||
275 | } v2_user_options[] __initdata = { | ||
276 | { "auto", SPECTRE_V2_USER_CMD_AUTO, false }, | ||
277 | { "off", SPECTRE_V2_USER_CMD_NONE, false }, | ||
278 | { "on", SPECTRE_V2_USER_CMD_FORCE, true }, | ||
279 | { "prctl", SPECTRE_V2_USER_CMD_PRCTL, false }, | ||
280 | { "prctl,ibpb", SPECTRE_V2_USER_CMD_PRCTL_IBPB, false }, | ||
281 | { "seccomp", SPECTRE_V2_USER_CMD_SECCOMP, false }, | ||
282 | { "seccomp,ibpb", SPECTRE_V2_USER_CMD_SECCOMP_IBPB, false }, | ||
283 | }; | ||
284 | |||
285 | static void __init spec_v2_user_print_cond(const char *reason, bool secure) | ||
248 | { | 286 | { |
249 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | 287 | if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2) != secure) |
250 | pr_info("%s selected on command line.\n", reason); | 288 | pr_info("spectre_v2_user=%s forced on command line.\n", reason); |
251 | } | 289 | } |
252 | 290 | ||
253 | static inline bool retp_compiler(void) | 291 | static enum spectre_v2_user_cmd __init |
292 | spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd) | ||
254 | { | 293 | { |
255 | return __is_defined(RETPOLINE); | 294 | char arg[20]; |
295 | int ret, i; | ||
296 | |||
297 | switch (v2_cmd) { | ||
298 | case SPECTRE_V2_CMD_NONE: | ||
299 | return SPECTRE_V2_USER_CMD_NONE; | ||
300 | case SPECTRE_V2_CMD_FORCE: | ||
301 | return SPECTRE_V2_USER_CMD_FORCE; | ||
302 | default: | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | ret = cmdline_find_option(boot_command_line, "spectre_v2_user", | ||
307 | arg, sizeof(arg)); | ||
308 | if (ret < 0) | ||
309 | return SPECTRE_V2_USER_CMD_AUTO; | ||
310 | |||
311 | for (i = 0; i < ARRAY_SIZE(v2_user_options); i++) { | ||
312 | if (match_option(arg, ret, v2_user_options[i].option)) { | ||
313 | spec_v2_user_print_cond(v2_user_options[i].option, | ||
314 | v2_user_options[i].secure); | ||
315 | return v2_user_options[i].cmd; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | pr_err("Unknown user space protection option (%s). Switching to AUTO select\n", arg); | ||
320 | return SPECTRE_V2_USER_CMD_AUTO; | ||
256 | } | 321 | } |
257 | 322 | ||
258 | static inline bool match_option(const char *arg, int arglen, const char *opt) | 323 | static void __init |
324 | spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd) | ||
259 | { | 325 | { |
260 | int len = strlen(opt); | 326 | enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE; |
327 | bool smt_possible = IS_ENABLED(CONFIG_SMP); | ||
328 | enum spectre_v2_user_cmd cmd; | ||
261 | 329 | ||
262 | return len == arglen && !strncmp(arg, opt, len); | 330 | if (!boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_STIBP)) |
331 | return; | ||
332 | |||
333 | if (cpu_smt_control == CPU_SMT_FORCE_DISABLED || | ||
334 | cpu_smt_control == CPU_SMT_NOT_SUPPORTED) | ||
335 | smt_possible = false; | ||
336 | |||
337 | cmd = spectre_v2_parse_user_cmdline(v2_cmd); | ||
338 | switch (cmd) { | ||
339 | case SPECTRE_V2_USER_CMD_NONE: | ||
340 | goto set_mode; | ||
341 | case SPECTRE_V2_USER_CMD_FORCE: | ||
342 | mode = SPECTRE_V2_USER_STRICT; | ||
343 | break; | ||
344 | case SPECTRE_V2_USER_CMD_PRCTL: | ||
345 | case SPECTRE_V2_USER_CMD_PRCTL_IBPB: | ||
346 | mode = SPECTRE_V2_USER_PRCTL; | ||
347 | break; | ||
348 | case SPECTRE_V2_USER_CMD_AUTO: | ||
349 | case SPECTRE_V2_USER_CMD_SECCOMP: | ||
350 | case SPECTRE_V2_USER_CMD_SECCOMP_IBPB: | ||
351 | if (IS_ENABLED(CONFIG_SECCOMP)) | ||
352 | mode = SPECTRE_V2_USER_SECCOMP; | ||
353 | else | ||
354 | mode = SPECTRE_V2_USER_PRCTL; | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | /* Initialize Indirect Branch Prediction Barrier */ | ||
359 | if (boot_cpu_has(X86_FEATURE_IBPB)) { | ||
360 | setup_force_cpu_cap(X86_FEATURE_USE_IBPB); | ||
361 | |||
362 | switch (cmd) { | ||
363 | case SPECTRE_V2_USER_CMD_FORCE: | ||
364 | case SPECTRE_V2_USER_CMD_PRCTL_IBPB: | ||
365 | case SPECTRE_V2_USER_CMD_SECCOMP_IBPB: | ||
366 | static_branch_enable(&switch_mm_always_ibpb); | ||
367 | break; | ||
368 | case SPECTRE_V2_USER_CMD_PRCTL: | ||
369 | case SPECTRE_V2_USER_CMD_AUTO: | ||
370 | case SPECTRE_V2_USER_CMD_SECCOMP: | ||
371 | static_branch_enable(&switch_mm_cond_ibpb); | ||
372 | break; | ||
373 | default: | ||
374 | break; | ||
375 | } | ||
376 | |||
377 | pr_info("mitigation: Enabling %s Indirect Branch Prediction Barrier\n", | ||
378 | static_key_enabled(&switch_mm_always_ibpb) ? | ||
379 | "always-on" : "conditional"); | ||
380 | } | ||
381 | |||
382 | /* If enhanced IBRS is enabled no STIPB required */ | ||
383 | if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED) | ||
384 | return; | ||
385 | |||
386 | /* | ||
387 | * If SMT is not possible or STIBP is not available clear the STIPB | ||
388 | * mode. | ||
389 | */ | ||
390 | if (!smt_possible || !boot_cpu_has(X86_FEATURE_STIBP)) | ||
391 | mode = SPECTRE_V2_USER_NONE; | ||
392 | set_mode: | ||
393 | spectre_v2_user = mode; | ||
394 | /* Only print the STIBP mode when SMT possible */ | ||
395 | if (smt_possible) | ||
396 | pr_info("%s\n", spectre_v2_user_strings[mode]); | ||
263 | } | 397 | } |
264 | 398 | ||
399 | static const char * const spectre_v2_strings[] = { | ||
400 | [SPECTRE_V2_NONE] = "Vulnerable", | ||
401 | [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", | ||
402 | [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline", | ||
403 | [SPECTRE_V2_IBRS_ENHANCED] = "Mitigation: Enhanced IBRS", | ||
404 | }; | ||
405 | |||
265 | static const struct { | 406 | static const struct { |
266 | const char *option; | 407 | const char *option; |
267 | enum spectre_v2_mitigation_cmd cmd; | 408 | enum spectre_v2_mitigation_cmd cmd; |
268 | bool secure; | 409 | bool secure; |
269 | } mitigation_options[] = { | 410 | } mitigation_options[] __initdata = { |
270 | { "off", SPECTRE_V2_CMD_NONE, false }, | 411 | { "off", SPECTRE_V2_CMD_NONE, false }, |
271 | { "on", SPECTRE_V2_CMD_FORCE, true }, | 412 | { "on", SPECTRE_V2_CMD_FORCE, true }, |
272 | { "retpoline", SPECTRE_V2_CMD_RETPOLINE, false }, | 413 | { "retpoline", SPECTRE_V2_CMD_RETPOLINE, false }, |
273 | { "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_AMD, false }, | 414 | { "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_AMD, false }, |
274 | { "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false }, | 415 | { "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false }, |
275 | { "auto", SPECTRE_V2_CMD_AUTO, false }, | 416 | { "auto", SPECTRE_V2_CMD_AUTO, false }, |
276 | }; | 417 | }; |
277 | 418 | ||
419 | static void __init spec_v2_print_cond(const char *reason, bool secure) | ||
420 | { | ||
421 | if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2) != secure) | ||
422 | pr_info("%s selected on command line.\n", reason); | ||
423 | } | ||
424 | |||
278 | static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) | 425 | static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) |
279 | { | 426 | { |
427 | enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO; | ||
280 | char arg[20]; | 428 | char arg[20]; |
281 | int ret, i; | 429 | int ret, i; |
282 | enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO; | ||
283 | 430 | ||
284 | if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) | 431 | if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) |
285 | return SPECTRE_V2_CMD_NONE; | 432 | return SPECTRE_V2_CMD_NONE; |
286 | else { | ||
287 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg)); | ||
288 | if (ret < 0) | ||
289 | return SPECTRE_V2_CMD_AUTO; | ||
290 | 433 | ||
291 | for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) { | 434 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg)); |
292 | if (!match_option(arg, ret, mitigation_options[i].option)) | 435 | if (ret < 0) |
293 | continue; | 436 | return SPECTRE_V2_CMD_AUTO; |
294 | cmd = mitigation_options[i].cmd; | ||
295 | break; | ||
296 | } | ||
297 | 437 | ||
298 | if (i >= ARRAY_SIZE(mitigation_options)) { | 438 | for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) { |
299 | pr_err("unknown option (%s). Switching to AUTO select\n", arg); | 439 | if (!match_option(arg, ret, mitigation_options[i].option)) |
300 | return SPECTRE_V2_CMD_AUTO; | 440 | continue; |
301 | } | 441 | cmd = mitigation_options[i].cmd; |
442 | break; | ||
443 | } | ||
444 | |||
445 | if (i >= ARRAY_SIZE(mitigation_options)) { | ||
446 | pr_err("unknown option (%s). Switching to AUTO select\n", arg); | ||
447 | return SPECTRE_V2_CMD_AUTO; | ||
302 | } | 448 | } |
303 | 449 | ||
304 | if ((cmd == SPECTRE_V2_CMD_RETPOLINE || | 450 | if ((cmd == SPECTRE_V2_CMD_RETPOLINE || |
@@ -316,54 +462,11 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) | |||
316 | return SPECTRE_V2_CMD_AUTO; | 462 | return SPECTRE_V2_CMD_AUTO; |
317 | } | 463 | } |
318 | 464 | ||
319 | if (mitigation_options[i].secure) | 465 | spec_v2_print_cond(mitigation_options[i].option, |
320 | spec2_print_if_secure(mitigation_options[i].option); | 466 | mitigation_options[i].secure); |
321 | else | ||
322 | spec2_print_if_insecure(mitigation_options[i].option); | ||
323 | |||
324 | return cmd; | 467 | return cmd; |
325 | } | 468 | } |
326 | 469 | ||
327 | static bool stibp_needed(void) | ||
328 | { | ||
329 | if (spectre_v2_enabled == SPECTRE_V2_NONE) | ||
330 | return false; | ||
331 | |||
332 | if (!boot_cpu_has(X86_FEATURE_STIBP)) | ||
333 | return false; | ||
334 | |||
335 | return true; | ||
336 | } | ||
337 | |||
338 | static void update_stibp_msr(void *info) | ||
339 | { | ||
340 | wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); | ||
341 | } | ||
342 | |||
343 | void arch_smt_update(void) | ||
344 | { | ||
345 | u64 mask; | ||
346 | |||
347 | if (!stibp_needed()) | ||
348 | return; | ||
349 | |||
350 | mutex_lock(&spec_ctrl_mutex); | ||
351 | mask = x86_spec_ctrl_base; | ||
352 | if (cpu_smt_control == CPU_SMT_ENABLED) | ||
353 | mask |= SPEC_CTRL_STIBP; | ||
354 | else | ||
355 | mask &= ~SPEC_CTRL_STIBP; | ||
356 | |||
357 | if (mask != x86_spec_ctrl_base) { | ||
358 | pr_info("Spectre v2 cross-process SMT mitigation: %s STIBP\n", | ||
359 | cpu_smt_control == CPU_SMT_ENABLED ? | ||
360 | "Enabling" : "Disabling"); | ||
361 | x86_spec_ctrl_base = mask; | ||
362 | on_each_cpu(update_stibp_msr, NULL, 1); | ||
363 | } | ||
364 | mutex_unlock(&spec_ctrl_mutex); | ||
365 | } | ||
366 | |||
367 | static void __init spectre_v2_select_mitigation(void) | 470 | static void __init spectre_v2_select_mitigation(void) |
368 | { | 471 | { |
369 | enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); | 472 | enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); |
@@ -417,14 +520,12 @@ retpoline_auto: | |||
417 | pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n"); | 520 | pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n"); |
418 | goto retpoline_generic; | 521 | goto retpoline_generic; |
419 | } | 522 | } |
420 | mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD : | 523 | mode = SPECTRE_V2_RETPOLINE_AMD; |
421 | SPECTRE_V2_RETPOLINE_MINIMAL_AMD; | ||
422 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); | 524 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); |
423 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); | 525 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); |
424 | } else { | 526 | } else { |
425 | retpoline_generic: | 527 | retpoline_generic: |
426 | mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC : | 528 | mode = SPECTRE_V2_RETPOLINE_GENERIC; |
427 | SPECTRE_V2_RETPOLINE_MINIMAL; | ||
428 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); | 529 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); |
429 | } | 530 | } |
430 | 531 | ||
@@ -443,12 +544,6 @@ specv2_set_mode: | |||
443 | setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); | 544 | setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); |
444 | pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n"); | 545 | pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n"); |
445 | 546 | ||
446 | /* Initialize Indirect Branch Prediction Barrier if supported */ | ||
447 | if (boot_cpu_has(X86_FEATURE_IBPB)) { | ||
448 | setup_force_cpu_cap(X86_FEATURE_USE_IBPB); | ||
449 | pr_info("Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier\n"); | ||
450 | } | ||
451 | |||
452 | /* | 547 | /* |
453 | * Retpoline means the kernel is safe because it has no indirect | 548 | * Retpoline means the kernel is safe because it has no indirect |
454 | * branches. Enhanced IBRS protects firmware too, so, enable restricted | 549 | * branches. Enhanced IBRS protects firmware too, so, enable restricted |
@@ -465,10 +560,67 @@ specv2_set_mode: | |||
465 | pr_info("Enabling Restricted Speculation for firmware calls\n"); | 560 | pr_info("Enabling Restricted Speculation for firmware calls\n"); |
466 | } | 561 | } |
467 | 562 | ||
563 | /* Set up IBPB and STIBP depending on the general spectre V2 command */ | ||
564 | spectre_v2_user_select_mitigation(cmd); | ||
565 | |||
468 | /* Enable STIBP if appropriate */ | 566 | /* Enable STIBP if appropriate */ |
469 | arch_smt_update(); | 567 | arch_smt_update(); |
470 | } | 568 | } |
471 | 569 | ||
570 | static void update_stibp_msr(void * __unused) | ||
571 | { | ||
572 | wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base); | ||
573 | } | ||
574 | |||
575 | /* Update x86_spec_ctrl_base in case SMT state changed. */ | ||
576 | static void update_stibp_strict(void) | ||
577 | { | ||
578 | u64 mask = x86_spec_ctrl_base & ~SPEC_CTRL_STIBP; | ||
579 | |||
580 | if (sched_smt_active()) | ||
581 | mask |= SPEC_CTRL_STIBP; | ||
582 | |||
583 | if (mask == x86_spec_ctrl_base) | ||
584 | return; | ||
585 | |||
586 | pr_info("Update user space SMT mitigation: STIBP %s\n", | ||
587 | mask & SPEC_CTRL_STIBP ? "always-on" : "off"); | ||
588 | x86_spec_ctrl_base = mask; | ||
589 | on_each_cpu(update_stibp_msr, NULL, 1); | ||
590 | } | ||
591 | |||
592 | /* Update the static key controlling the evaluation of TIF_SPEC_IB */ | ||
593 | static void update_indir_branch_cond(void) | ||
594 | { | ||
595 | if (sched_smt_active()) | ||
596 | static_branch_enable(&switch_to_cond_stibp); | ||
597 | else | ||
598 | static_branch_disable(&switch_to_cond_stibp); | ||
599 | } | ||
600 | |||
601 | void arch_smt_update(void) | ||
602 | { | ||
603 | /* Enhanced IBRS implies STIBP. No update required. */ | ||
604 | if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED) | ||
605 | return; | ||
606 | |||
607 | mutex_lock(&spec_ctrl_mutex); | ||
608 | |||
609 | switch (spectre_v2_user) { | ||
610 | case SPECTRE_V2_USER_NONE: | ||
611 | break; | ||
612 | case SPECTRE_V2_USER_STRICT: | ||
613 | update_stibp_strict(); | ||
614 | break; | ||
615 | case SPECTRE_V2_USER_PRCTL: | ||
616 | case SPECTRE_V2_USER_SECCOMP: | ||
617 | update_indir_branch_cond(); | ||
618 | break; | ||
619 | } | ||
620 | |||
621 | mutex_unlock(&spec_ctrl_mutex); | ||
622 | } | ||
623 | |||
472 | #undef pr_fmt | 624 | #undef pr_fmt |
473 | #define pr_fmt(fmt) "Speculative Store Bypass: " fmt | 625 | #define pr_fmt(fmt) "Speculative Store Bypass: " fmt |
474 | 626 | ||
@@ -483,7 +635,7 @@ enum ssb_mitigation_cmd { | |||
483 | SPEC_STORE_BYPASS_CMD_SECCOMP, | 635 | SPEC_STORE_BYPASS_CMD_SECCOMP, |
484 | }; | 636 | }; |
485 | 637 | ||
486 | static const char *ssb_strings[] = { | 638 | static const char * const ssb_strings[] = { |
487 | [SPEC_STORE_BYPASS_NONE] = "Vulnerable", | 639 | [SPEC_STORE_BYPASS_NONE] = "Vulnerable", |
488 | [SPEC_STORE_BYPASS_DISABLE] = "Mitigation: Speculative Store Bypass disabled", | 640 | [SPEC_STORE_BYPASS_DISABLE] = "Mitigation: Speculative Store Bypass disabled", |
489 | [SPEC_STORE_BYPASS_PRCTL] = "Mitigation: Speculative Store Bypass disabled via prctl", | 641 | [SPEC_STORE_BYPASS_PRCTL] = "Mitigation: Speculative Store Bypass disabled via prctl", |
@@ -493,7 +645,7 @@ static const char *ssb_strings[] = { | |||
493 | static const struct { | 645 | static const struct { |
494 | const char *option; | 646 | const char *option; |
495 | enum ssb_mitigation_cmd cmd; | 647 | enum ssb_mitigation_cmd cmd; |
496 | } ssb_mitigation_options[] = { | 648 | } ssb_mitigation_options[] __initdata = { |
497 | { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ | 649 | { "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */ |
498 | { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ | 650 | { "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */ |
499 | { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ | 651 | { "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */ |
@@ -604,10 +756,25 @@ static void ssb_select_mitigation(void) | |||
604 | #undef pr_fmt | 756 | #undef pr_fmt |
605 | #define pr_fmt(fmt) "Speculation prctl: " fmt | 757 | #define pr_fmt(fmt) "Speculation prctl: " fmt |
606 | 758 | ||
607 | static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) | 759 | static void task_update_spec_tif(struct task_struct *tsk) |
608 | { | 760 | { |
609 | bool update; | 761 | /* Force the update of the real TIF bits */ |
762 | set_tsk_thread_flag(tsk, TIF_SPEC_FORCE_UPDATE); | ||
610 | 763 | ||
764 | /* | ||
765 | * Immediately update the speculation control MSRs for the current | ||
766 | * task, but for a non-current task delay setting the CPU | ||
767 | * mitigation until it is scheduled next. | ||
768 | * | ||
769 | * This can only happen for SECCOMP mitigation. For PRCTL it's | ||
770 | * always the current task. | ||
771 | */ | ||
772 | if (tsk == current) | ||
773 | speculation_ctrl_update_current(); | ||
774 | } | ||
775 | |||
776 | static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) | ||
777 | { | ||
611 | if (ssb_mode != SPEC_STORE_BYPASS_PRCTL && | 778 | if (ssb_mode != SPEC_STORE_BYPASS_PRCTL && |
612 | ssb_mode != SPEC_STORE_BYPASS_SECCOMP) | 779 | ssb_mode != SPEC_STORE_BYPASS_SECCOMP) |
613 | return -ENXIO; | 780 | return -ENXIO; |
@@ -618,28 +785,56 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) | |||
618 | if (task_spec_ssb_force_disable(task)) | 785 | if (task_spec_ssb_force_disable(task)) |
619 | return -EPERM; | 786 | return -EPERM; |
620 | task_clear_spec_ssb_disable(task); | 787 | task_clear_spec_ssb_disable(task); |
621 | update = test_and_clear_tsk_thread_flag(task, TIF_SSBD); | 788 | task_update_spec_tif(task); |
622 | break; | 789 | break; |
623 | case PR_SPEC_DISABLE: | 790 | case PR_SPEC_DISABLE: |
624 | task_set_spec_ssb_disable(task); | 791 | task_set_spec_ssb_disable(task); |
625 | update = !test_and_set_tsk_thread_flag(task, TIF_SSBD); | 792 | task_update_spec_tif(task); |
626 | break; | 793 | break; |
627 | case PR_SPEC_FORCE_DISABLE: | 794 | case PR_SPEC_FORCE_DISABLE: |
628 | task_set_spec_ssb_disable(task); | 795 | task_set_spec_ssb_disable(task); |
629 | task_set_spec_ssb_force_disable(task); | 796 | task_set_spec_ssb_force_disable(task); |
630 | update = !test_and_set_tsk_thread_flag(task, TIF_SSBD); | 797 | task_update_spec_tif(task); |
631 | break; | 798 | break; |
632 | default: | 799 | default: |
633 | return -ERANGE; | 800 | return -ERANGE; |
634 | } | 801 | } |
802 | return 0; | ||
803 | } | ||
635 | 804 | ||
636 | /* | 805 | static int ib_prctl_set(struct task_struct *task, unsigned long ctrl) |
637 | * If being set on non-current task, delay setting the CPU | 806 | { |
638 | * mitigation until it is next scheduled. | 807 | switch (ctrl) { |
639 | */ | 808 | case PR_SPEC_ENABLE: |
640 | if (task == current && update) | 809 | if (spectre_v2_user == SPECTRE_V2_USER_NONE) |
641 | speculative_store_bypass_update_current(); | 810 | return 0; |
642 | 811 | /* | |
812 | * Indirect branch speculation is always disabled in strict | ||
813 | * mode. | ||
814 | */ | ||
815 | if (spectre_v2_user == SPECTRE_V2_USER_STRICT) | ||
816 | return -EPERM; | ||
817 | task_clear_spec_ib_disable(task); | ||
818 | task_update_spec_tif(task); | ||
819 | break; | ||
820 | case PR_SPEC_DISABLE: | ||
821 | case PR_SPEC_FORCE_DISABLE: | ||
822 | /* | ||
823 | * Indirect branch speculation is always allowed when | ||
824 | * mitigation is force disabled. | ||
825 | */ | ||
826 | if (spectre_v2_user == SPECTRE_V2_USER_NONE) | ||
827 | return -EPERM; | ||
828 | if (spectre_v2_user == SPECTRE_V2_USER_STRICT) | ||
829 | return 0; | ||
830 | task_set_spec_ib_disable(task); | ||
831 | if (ctrl == PR_SPEC_FORCE_DISABLE) | ||
832 | task_set_spec_ib_force_disable(task); | ||
833 | task_update_spec_tif(task); | ||
834 | break; | ||
835 | default: | ||
836 | return -ERANGE; | ||
837 | } | ||
643 | return 0; | 838 | return 0; |
644 | } | 839 | } |
645 | 840 | ||
@@ -649,6 +844,8 @@ int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, | |||
649 | switch (which) { | 844 | switch (which) { |
650 | case PR_SPEC_STORE_BYPASS: | 845 | case PR_SPEC_STORE_BYPASS: |
651 | return ssb_prctl_set(task, ctrl); | 846 | return ssb_prctl_set(task, ctrl); |
847 | case PR_SPEC_INDIRECT_BRANCH: | ||
848 | return ib_prctl_set(task, ctrl); | ||
652 | default: | 849 | default: |
653 | return -ENODEV; | 850 | return -ENODEV; |
654 | } | 851 | } |
@@ -659,6 +856,8 @@ void arch_seccomp_spec_mitigate(struct task_struct *task) | |||
659 | { | 856 | { |
660 | if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP) | 857 | if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP) |
661 | ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE); | 858 | ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE); |
859 | if (spectre_v2_user == SPECTRE_V2_USER_SECCOMP) | ||
860 | ib_prctl_set(task, PR_SPEC_FORCE_DISABLE); | ||
662 | } | 861 | } |
663 | #endif | 862 | #endif |
664 | 863 | ||
@@ -681,11 +880,35 @@ static int ssb_prctl_get(struct task_struct *task) | |||
681 | } | 880 | } |
682 | } | 881 | } |
683 | 882 | ||
883 | static int ib_prctl_get(struct task_struct *task) | ||
884 | { | ||
885 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | ||
886 | return PR_SPEC_NOT_AFFECTED; | ||
887 | |||
888 | switch (spectre_v2_user) { | ||
889 | case SPECTRE_V2_USER_NONE: | ||
890 | return PR_SPEC_ENABLE; | ||
891 | case SPECTRE_V2_USER_PRCTL: | ||
892 | case SPECTRE_V2_USER_SECCOMP: | ||
893 | if (task_spec_ib_force_disable(task)) | ||
894 | return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE; | ||
895 | if (task_spec_ib_disable(task)) | ||
896 | return PR_SPEC_PRCTL | PR_SPEC_DISABLE; | ||
897 | return PR_SPEC_PRCTL | PR_SPEC_ENABLE; | ||
898 | case SPECTRE_V2_USER_STRICT: | ||
899 | return PR_SPEC_DISABLE; | ||
900 | default: | ||
901 | return PR_SPEC_NOT_AFFECTED; | ||
902 | } | ||
903 | } | ||
904 | |||
684 | int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) | 905 | int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) |
685 | { | 906 | { |
686 | switch (which) { | 907 | switch (which) { |
687 | case PR_SPEC_STORE_BYPASS: | 908 | case PR_SPEC_STORE_BYPASS: |
688 | return ssb_prctl_get(task); | 909 | return ssb_prctl_get(task); |
910 | case PR_SPEC_INDIRECT_BRANCH: | ||
911 | return ib_prctl_get(task); | ||
689 | default: | 912 | default: |
690 | return -ENODEV; | 913 | return -ENODEV; |
691 | } | 914 | } |
@@ -823,7 +1046,7 @@ early_param("l1tf", l1tf_cmdline); | |||
823 | #define L1TF_DEFAULT_MSG "Mitigation: PTE Inversion" | 1046 | #define L1TF_DEFAULT_MSG "Mitigation: PTE Inversion" |
824 | 1047 | ||
825 | #if IS_ENABLED(CONFIG_KVM_INTEL) | 1048 | #if IS_ENABLED(CONFIG_KVM_INTEL) |
826 | static const char *l1tf_vmx_states[] = { | 1049 | static const char * const l1tf_vmx_states[] = { |
827 | [VMENTER_L1D_FLUSH_AUTO] = "auto", | 1050 | [VMENTER_L1D_FLUSH_AUTO] = "auto", |
828 | [VMENTER_L1D_FLUSH_NEVER] = "vulnerable", | 1051 | [VMENTER_L1D_FLUSH_NEVER] = "vulnerable", |
829 | [VMENTER_L1D_FLUSH_COND] = "conditional cache flushes", | 1052 | [VMENTER_L1D_FLUSH_COND] = "conditional cache flushes", |
@@ -839,13 +1062,14 @@ static ssize_t l1tf_show_state(char *buf) | |||
839 | 1062 | ||
840 | if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_EPT_DISABLED || | 1063 | if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_EPT_DISABLED || |
841 | (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_NEVER && | 1064 | (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_NEVER && |
842 | cpu_smt_control == CPU_SMT_ENABLED)) | 1065 | sched_smt_active())) { |
843 | return sprintf(buf, "%s; VMX: %s\n", L1TF_DEFAULT_MSG, | 1066 | return sprintf(buf, "%s; VMX: %s\n", L1TF_DEFAULT_MSG, |
844 | l1tf_vmx_states[l1tf_vmx_mitigation]); | 1067 | l1tf_vmx_states[l1tf_vmx_mitigation]); |
1068 | } | ||
845 | 1069 | ||
846 | return sprintf(buf, "%s; VMX: %s, SMT %s\n", L1TF_DEFAULT_MSG, | 1070 | return sprintf(buf, "%s; VMX: %s, SMT %s\n", L1TF_DEFAULT_MSG, |
847 | l1tf_vmx_states[l1tf_vmx_mitigation], | 1071 | l1tf_vmx_states[l1tf_vmx_mitigation], |
848 | cpu_smt_control == CPU_SMT_ENABLED ? "vulnerable" : "disabled"); | 1072 | sched_smt_active() ? "vulnerable" : "disabled"); |
849 | } | 1073 | } |
850 | #else | 1074 | #else |
851 | static ssize_t l1tf_show_state(char *buf) | 1075 | static ssize_t l1tf_show_state(char *buf) |
@@ -854,11 +1078,39 @@ static ssize_t l1tf_show_state(char *buf) | |||
854 | } | 1078 | } |
855 | #endif | 1079 | #endif |
856 | 1080 | ||
1081 | static char *stibp_state(void) | ||
1082 | { | ||
1083 | if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED) | ||
1084 | return ""; | ||
1085 | |||
1086 | switch (spectre_v2_user) { | ||
1087 | case SPECTRE_V2_USER_NONE: | ||
1088 | return ", STIBP: disabled"; | ||
1089 | case SPECTRE_V2_USER_STRICT: | ||
1090 | return ", STIBP: forced"; | ||
1091 | case SPECTRE_V2_USER_PRCTL: | ||
1092 | case SPECTRE_V2_USER_SECCOMP: | ||
1093 | if (static_key_enabled(&switch_to_cond_stibp)) | ||
1094 | return ", STIBP: conditional"; | ||
1095 | } | ||
1096 | return ""; | ||
1097 | } | ||
1098 | |||
1099 | static char *ibpb_state(void) | ||
1100 | { | ||
1101 | if (boot_cpu_has(X86_FEATURE_IBPB)) { | ||
1102 | if (static_key_enabled(&switch_mm_always_ibpb)) | ||
1103 | return ", IBPB: always-on"; | ||
1104 | if (static_key_enabled(&switch_mm_cond_ibpb)) | ||
1105 | return ", IBPB: conditional"; | ||
1106 | return ", IBPB: disabled"; | ||
1107 | } | ||
1108 | return ""; | ||
1109 | } | ||
1110 | |||
857 | static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, | 1111 | static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, |
858 | char *buf, unsigned int bug) | 1112 | char *buf, unsigned int bug) |
859 | { | 1113 | { |
860 | int ret; | ||
861 | |||
862 | if (!boot_cpu_has_bug(bug)) | 1114 | if (!boot_cpu_has_bug(bug)) |
863 | return sprintf(buf, "Not affected\n"); | 1115 | return sprintf(buf, "Not affected\n"); |
864 | 1116 | ||
@@ -876,13 +1128,12 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr | |||
876 | return sprintf(buf, "Mitigation: __user pointer sanitization\n"); | 1128 | return sprintf(buf, "Mitigation: __user pointer sanitization\n"); |
877 | 1129 | ||
878 | case X86_BUG_SPECTRE_V2: | 1130 | case X86_BUG_SPECTRE_V2: |
879 | ret = sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], | 1131 | return sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], |
880 | boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "", | 1132 | ibpb_state(), |
881 | boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", | 1133 | boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", |
882 | (x86_spec_ctrl_base & SPEC_CTRL_STIBP) ? ", STIBP" : "", | 1134 | stibp_state(), |
883 | boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "", | 1135 | boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "", |
884 | spectre_v2_module_string()); | 1136 | spectre_v2_module_string()); |
885 | return ret; | ||
886 | 1137 | ||
887 | case X86_BUG_SPEC_STORE_BYPASS: | 1138 | case X86_BUG_SPEC_STORE_BYPASS: |
888 | return sprintf(buf, "%s\n", ssb_strings[ssb_mode]); | 1139 | return sprintf(buf, "%s\n", ssb_strings[ssb_mode]); |