diff options
author | Will Deacon <will.deacon@arm.com> | 2019-05-01 10:34:56 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2019-05-01 10:34:56 -0400 |
commit | 50abbe19623e08e2aa34e0e526bd6115569f3dc3 (patch) | |
tree | ecaddb898d671847f70c40fcab5fd115dacc1a1e | |
parent | 9431ac2bf6b742d87cdac051adc1976308070110 (diff) | |
parent | 4ad499c94264a2ee05aacc518b9bde658318e510 (diff) |
Merge branch 'for-next/mitigations' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux into for-next/core
-rw-r--r-- | Documentation/admin-guide/kernel-parameters.rst | 1 | ||||
-rw-r--r-- | Documentation/admin-guide/kernel-parameters.txt | 42 | ||||
-rw-r--r-- | arch/arm64/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm64/include/asm/cpufeature.h | 4 | ||||
-rw-r--r-- | arch/arm64/kernel/cpu_errata.c | 243 | ||||
-rw-r--r-- | arch/arm64/kernel/cpufeature.c | 66 | ||||
-rw-r--r-- | arch/powerpc/kernel/security.c | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/nospec-branch.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 11 | ||||
-rw-r--r-- | arch/x86/mm/pti.c | 4 | ||||
-rw-r--r-- | include/linux/cpu.h | 24 | ||||
-rw-r--r-- | kernel/cpu.c | 15 |
13 files changed, 325 insertions, 97 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst index b8d0bc07ed0a..0124980dca2d 100644 --- a/Documentation/admin-guide/kernel-parameters.rst +++ b/Documentation/admin-guide/kernel-parameters.rst | |||
@@ -88,6 +88,7 @@ parameter is applicable:: | |||
88 | APIC APIC support is enabled. | 88 | APIC APIC support is enabled. |
89 | APM Advanced Power Management support is enabled. | 89 | APM Advanced Power Management support is enabled. |
90 | ARM ARM architecture is enabled. | 90 | ARM ARM architecture is enabled. |
91 | ARM64 ARM64 architecture is enabled. | ||
91 | AX25 Appropriate AX.25 support is enabled. | 92 | AX25 Appropriate AX.25 support is enabled. |
92 | CLK Common clock infrastructure is enabled. | 93 | CLK Common clock infrastructure is enabled. |
93 | CMA Contiguous Memory Area support is enabled. | 94 | CMA Contiguous Memory Area support is enabled. |
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 2b8ee90bb644..ce226f7ee566 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt | |||
@@ -2544,6 +2544,40 @@ | |||
2544 | in the "bleeding edge" mini2440 support kernel at | 2544 | in the "bleeding edge" mini2440 support kernel at |
2545 | http://repo.or.cz/w/linux-2.6/mini2440.git | 2545 | http://repo.or.cz/w/linux-2.6/mini2440.git |
2546 | 2546 | ||
2547 | mitigations= | ||
2548 | [X86,PPC,S390,ARM64] Control optional mitigations for | ||
2549 | CPU vulnerabilities. This is a set of curated, | ||
2550 | arch-independent options, each of which is an | ||
2551 | aggregation of existing arch-specific options. | ||
2552 | |||
2553 | off | ||
2554 | Disable all optional CPU mitigations. This | ||
2555 | improves system performance, but it may also | ||
2556 | expose users to several CPU vulnerabilities. | ||
2557 | Equivalent to: nopti [X86,PPC] | ||
2558 | kpti=0 [ARM64] | ||
2559 | nospectre_v1 [PPC] | ||
2560 | nobp=0 [S390] | ||
2561 | nospectre_v2 [X86,PPC,S390,ARM64] | ||
2562 | spectre_v2_user=off [X86] | ||
2563 | spec_store_bypass_disable=off [X86,PPC] | ||
2564 | ssbd=force-off [ARM64] | ||
2565 | l1tf=off [X86] | ||
2566 | |||
2567 | auto (default) | ||
2568 | Mitigate all CPU vulnerabilities, but leave SMT | ||
2569 | enabled, even if it's vulnerable. This is for | ||
2570 | users who don't want to be surprised by SMT | ||
2571 | getting disabled across kernel upgrades, or who | ||
2572 | have other ways of avoiding SMT-based attacks. | ||
2573 | Equivalent to: (default behavior) | ||
2574 | |||
2575 | auto,nosmt | ||
2576 | Mitigate all CPU vulnerabilities, disabling SMT | ||
2577 | if needed. This is for users who always want to | ||
2578 | be fully mitigated, even if it means losing SMT. | ||
2579 | Equivalent to: l1tf=flush,nosmt [X86] | ||
2580 | |||
2547 | mminit_loglevel= | 2581 | mminit_loglevel= |
2548 | [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this | 2582 | [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this |
2549 | parameter allows control of the logging verbosity for | 2583 | parameter allows control of the logging verbosity for |
@@ -2873,10 +2907,10 @@ | |||
2873 | check bypass). With this option data leaks are possible | 2907 | check bypass). With this option data leaks are possible |
2874 | in the system. | 2908 | in the system. |
2875 | 2909 | ||
2876 | nospectre_v2 [X86,PPC_FSL_BOOK3E] Disable all mitigations for the Spectre variant 2 | 2910 | nospectre_v2 [X86,PPC_FSL_BOOK3E,ARM64] Disable all mitigations for |
2877 | (indirect branch prediction) vulnerability. System may | 2911 | the Spectre variant 2 (indirect branch prediction) |
2878 | allow data leaks with this option, which is equivalent | 2912 | vulnerability. System may allow data leaks with this |
2879 | to spectre_v2=off. | 2913 | option. |
2880 | 2914 | ||
2881 | nospec_store_bypass_disable | 2915 | nospec_store_bypass_disable |
2882 | [HW] Disable all mitigations for the Speculative Store Bypass vulnerability | 2916 | [HW] Disable all mitigations for the Speculative Store Bypass vulnerability |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index d28f12e9c160..b5c6943225ce 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
@@ -90,6 +90,7 @@ config ARM64 | |||
90 | select GENERIC_CLOCKEVENTS | 90 | select GENERIC_CLOCKEVENTS |
91 | select GENERIC_CLOCKEVENTS_BROADCAST | 91 | select GENERIC_CLOCKEVENTS_BROADCAST |
92 | select GENERIC_CPU_AUTOPROBE | 92 | select GENERIC_CPU_AUTOPROBE |
93 | select GENERIC_CPU_VULNERABILITIES | ||
93 | select GENERIC_EARLY_IOREMAP | 94 | select GENERIC_EARLY_IOREMAP |
94 | select GENERIC_IDLE_POLL_SETUP | 95 | select GENERIC_IDLE_POLL_SETUP |
95 | select GENERIC_IRQ_MULTI_HANDLER | 96 | select GENERIC_IRQ_MULTI_HANDLER |
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index a3f028f82def..f210bcf096f7 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h | |||
@@ -633,11 +633,7 @@ static inline int arm64_get_ssbd_state(void) | |||
633 | #endif | 633 | #endif |
634 | } | 634 | } |
635 | 635 | ||
636 | #ifdef CONFIG_ARM64_SSBD | ||
637 | void arm64_set_ssbd_mitigation(bool state); | 636 | void arm64_set_ssbd_mitigation(bool state); |
638 | #else | ||
639 | static inline void arm64_set_ssbd_mitigation(bool state) {} | ||
640 | #endif | ||
641 | 637 | ||
642 | extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); | 638 | extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); |
643 | 639 | ||
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 9950bb0cbd52..1b9ce0fdd81d 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/arm-smccc.h> | 19 | #include <linux/arm-smccc.h> |
20 | #include <linux/psci.h> | 20 | #include <linux/psci.h> |
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/cpu.h> | ||
22 | #include <asm/cpu.h> | 23 | #include <asm/cpu.h> |
23 | #include <asm/cputype.h> | 24 | #include <asm/cputype.h> |
24 | #include <asm/cpufeature.h> | 25 | #include <asm/cpufeature.h> |
@@ -109,7 +110,6 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused) | |||
109 | 110 | ||
110 | atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1); | 111 | atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1); |
111 | 112 | ||
112 | #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR | ||
113 | #include <asm/mmu_context.h> | 113 | #include <asm/mmu_context.h> |
114 | #include <asm/cacheflush.h> | 114 | #include <asm/cacheflush.h> |
115 | 115 | ||
@@ -131,9 +131,9 @@ static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, | |||
131 | __flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); | 131 | __flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); |
132 | } | 132 | } |
133 | 133 | ||
134 | static void __install_bp_hardening_cb(bp_hardening_cb_t fn, | 134 | static void install_bp_hardening_cb(bp_hardening_cb_t fn, |
135 | const char *hyp_vecs_start, | 135 | const char *hyp_vecs_start, |
136 | const char *hyp_vecs_end) | 136 | const char *hyp_vecs_end) |
137 | { | 137 | { |
138 | static DEFINE_RAW_SPINLOCK(bp_lock); | 138 | static DEFINE_RAW_SPINLOCK(bp_lock); |
139 | int cpu, slot = -1; | 139 | int cpu, slot = -1; |
@@ -169,7 +169,7 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, | |||
169 | #define __smccc_workaround_1_smc_start NULL | 169 | #define __smccc_workaround_1_smc_start NULL |
170 | #define __smccc_workaround_1_smc_end NULL | 170 | #define __smccc_workaround_1_smc_end NULL |
171 | 171 | ||
172 | static void __install_bp_hardening_cb(bp_hardening_cb_t fn, | 172 | static void install_bp_hardening_cb(bp_hardening_cb_t fn, |
173 | const char *hyp_vecs_start, | 173 | const char *hyp_vecs_start, |
174 | const char *hyp_vecs_end) | 174 | const char *hyp_vecs_end) |
175 | { | 175 | { |
@@ -177,23 +177,6 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, | |||
177 | } | 177 | } |
178 | #endif /* CONFIG_KVM_INDIRECT_VECTORS */ | 178 | #endif /* CONFIG_KVM_INDIRECT_VECTORS */ |
179 | 179 | ||
180 | static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, | ||
181 | bp_hardening_cb_t fn, | ||
182 | const char *hyp_vecs_start, | ||
183 | const char *hyp_vecs_end) | ||
184 | { | ||
185 | u64 pfr0; | ||
186 | |||
187 | if (!entry->matches(entry, SCOPE_LOCAL_CPU)) | ||
188 | return; | ||
189 | |||
190 | pfr0 = read_cpuid(ID_AA64PFR0_EL1); | ||
191 | if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT)) | ||
192 | return; | ||
193 | |||
194 | __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); | ||
195 | } | ||
196 | |||
197 | #include <uapi/linux/psci.h> | 180 | #include <uapi/linux/psci.h> |
198 | #include <linux/arm-smccc.h> | 181 | #include <linux/arm-smccc.h> |
199 | #include <linux/psci.h> | 182 | #include <linux/psci.h> |
@@ -220,60 +203,83 @@ static void qcom_link_stack_sanitization(void) | |||
220 | : "=&r" (tmp)); | 203 | : "=&r" (tmp)); |
221 | } | 204 | } |
222 | 205 | ||
223 | static void | 206 | static bool __nospectre_v2; |
224 | enable_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry) | 207 | static int __init parse_nospectre_v2(char *str) |
208 | { | ||
209 | __nospectre_v2 = true; | ||
210 | return 0; | ||
211 | } | ||
212 | early_param("nospectre_v2", parse_nospectre_v2); | ||
213 | |||
214 | /* | ||
215 | * -1: No workaround | ||
216 | * 0: No workaround required | ||
217 | * 1: Workaround installed | ||
218 | */ | ||
219 | static int detect_harden_bp_fw(void) | ||
225 | { | 220 | { |
226 | bp_hardening_cb_t cb; | 221 | bp_hardening_cb_t cb; |
227 | void *smccc_start, *smccc_end; | 222 | void *smccc_start, *smccc_end; |
228 | struct arm_smccc_res res; | 223 | struct arm_smccc_res res; |
229 | u32 midr = read_cpuid_id(); | 224 | u32 midr = read_cpuid_id(); |
230 | 225 | ||
231 | if (!entry->matches(entry, SCOPE_LOCAL_CPU)) | ||
232 | return; | ||
233 | |||
234 | if (psci_ops.smccc_version == SMCCC_VERSION_1_0) | 226 | if (psci_ops.smccc_version == SMCCC_VERSION_1_0) |
235 | return; | 227 | return -1; |
236 | 228 | ||
237 | switch (psci_ops.conduit) { | 229 | switch (psci_ops.conduit) { |
238 | case PSCI_CONDUIT_HVC: | 230 | case PSCI_CONDUIT_HVC: |
239 | arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, | 231 | arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, |
240 | ARM_SMCCC_ARCH_WORKAROUND_1, &res); | 232 | ARM_SMCCC_ARCH_WORKAROUND_1, &res); |
241 | if ((int)res.a0 < 0) | 233 | switch ((int)res.a0) { |
242 | return; | 234 | case 1: |
243 | cb = call_hvc_arch_workaround_1; | 235 | /* Firmware says we're just fine */ |
244 | /* This is a guest, no need to patch KVM vectors */ | 236 | return 0; |
245 | smccc_start = NULL; | 237 | case 0: |
246 | smccc_end = NULL; | 238 | cb = call_hvc_arch_workaround_1; |
239 | /* This is a guest, no need to patch KVM vectors */ | ||
240 | smccc_start = NULL; | ||
241 | smccc_end = NULL; | ||
242 | break; | ||
243 | default: | ||
244 | return -1; | ||
245 | } | ||
247 | break; | 246 | break; |
248 | 247 | ||
249 | case PSCI_CONDUIT_SMC: | 248 | case PSCI_CONDUIT_SMC: |
250 | arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, | 249 | arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, |
251 | ARM_SMCCC_ARCH_WORKAROUND_1, &res); | 250 | ARM_SMCCC_ARCH_WORKAROUND_1, &res); |
252 | if ((int)res.a0 < 0) | 251 | switch ((int)res.a0) { |
253 | return; | 252 | case 1: |
254 | cb = call_smc_arch_workaround_1; | 253 | /* Firmware says we're just fine */ |
255 | smccc_start = __smccc_workaround_1_smc_start; | 254 | return 0; |
256 | smccc_end = __smccc_workaround_1_smc_end; | 255 | case 0: |
256 | cb = call_smc_arch_workaround_1; | ||
257 | smccc_start = __smccc_workaround_1_smc_start; | ||
258 | smccc_end = __smccc_workaround_1_smc_end; | ||
259 | break; | ||
260 | default: | ||
261 | return -1; | ||
262 | } | ||
257 | break; | 263 | break; |
258 | 264 | ||
259 | default: | 265 | default: |
260 | return; | 266 | return -1; |
261 | } | 267 | } |
262 | 268 | ||
263 | if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) || | 269 | if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) || |
264 | ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)) | 270 | ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)) |
265 | cb = qcom_link_stack_sanitization; | 271 | cb = qcom_link_stack_sanitization; |
266 | 272 | ||
267 | install_bp_hardening_cb(entry, cb, smccc_start, smccc_end); | 273 | if (IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR)) |
274 | install_bp_hardening_cb(cb, smccc_start, smccc_end); | ||
268 | 275 | ||
269 | return; | 276 | return 1; |
270 | } | 277 | } |
271 | #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ | ||
272 | 278 | ||
273 | #ifdef CONFIG_ARM64_SSBD | ||
274 | DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); | 279 | DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); |
275 | 280 | ||
276 | int ssbd_state __read_mostly = ARM64_SSBD_KERNEL; | 281 | int ssbd_state __read_mostly = ARM64_SSBD_KERNEL; |
282 | static bool __ssb_safe = true; | ||
277 | 283 | ||
278 | static const struct ssbd_options { | 284 | static const struct ssbd_options { |
279 | const char *str; | 285 | const char *str; |
@@ -343,6 +349,11 @@ void __init arm64_enable_wa2_handling(struct alt_instr *alt, | |||
343 | 349 | ||
344 | void arm64_set_ssbd_mitigation(bool state) | 350 | void arm64_set_ssbd_mitigation(bool state) |
345 | { | 351 | { |
352 | if (!IS_ENABLED(CONFIG_ARM64_SSBD)) { | ||
353 | pr_info_once("SSBD disabled by kernel configuration\n"); | ||
354 | return; | ||
355 | } | ||
356 | |||
346 | if (this_cpu_has_cap(ARM64_SSBS)) { | 357 | if (this_cpu_has_cap(ARM64_SSBS)) { |
347 | if (state) | 358 | if (state) |
348 | asm volatile(SET_PSTATE_SSBS(0)); | 359 | asm volatile(SET_PSTATE_SSBS(0)); |
@@ -372,16 +383,28 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, | |||
372 | struct arm_smccc_res res; | 383 | struct arm_smccc_res res; |
373 | bool required = true; | 384 | bool required = true; |
374 | s32 val; | 385 | s32 val; |
386 | bool this_cpu_safe = false; | ||
375 | 387 | ||
376 | WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); | 388 | WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); |
377 | 389 | ||
390 | if (cpu_mitigations_off()) | ||
391 | ssbd_state = ARM64_SSBD_FORCE_DISABLE; | ||
392 | |||
393 | /* delay setting __ssb_safe until we get a firmware response */ | ||
394 | if (is_midr_in_range_list(read_cpuid_id(), entry->midr_range_list)) | ||
395 | this_cpu_safe = true; | ||
396 | |||
378 | if (this_cpu_has_cap(ARM64_SSBS)) { | 397 | if (this_cpu_has_cap(ARM64_SSBS)) { |
398 | if (!this_cpu_safe) | ||
399 | __ssb_safe = false; | ||
379 | required = false; | 400 | required = false; |
380 | goto out_printmsg; | 401 | goto out_printmsg; |
381 | } | 402 | } |
382 | 403 | ||
383 | if (psci_ops.smccc_version == SMCCC_VERSION_1_0) { | 404 | if (psci_ops.smccc_version == SMCCC_VERSION_1_0) { |
384 | ssbd_state = ARM64_SSBD_UNKNOWN; | 405 | ssbd_state = ARM64_SSBD_UNKNOWN; |
406 | if (!this_cpu_safe) | ||
407 | __ssb_safe = false; | ||
385 | return false; | 408 | return false; |
386 | } | 409 | } |
387 | 410 | ||
@@ -398,6 +421,8 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, | |||
398 | 421 | ||
399 | default: | 422 | default: |
400 | ssbd_state = ARM64_SSBD_UNKNOWN; | 423 | ssbd_state = ARM64_SSBD_UNKNOWN; |
424 | if (!this_cpu_safe) | ||
425 | __ssb_safe = false; | ||
401 | return false; | 426 | return false; |
402 | } | 427 | } |
403 | 428 | ||
@@ -406,14 +431,18 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, | |||
406 | switch (val) { | 431 | switch (val) { |
407 | case SMCCC_RET_NOT_SUPPORTED: | 432 | case SMCCC_RET_NOT_SUPPORTED: |
408 | ssbd_state = ARM64_SSBD_UNKNOWN; | 433 | ssbd_state = ARM64_SSBD_UNKNOWN; |
434 | if (!this_cpu_safe) | ||
435 | __ssb_safe = false; | ||
409 | return false; | 436 | return false; |
410 | 437 | ||
438 | /* machines with mixed mitigation requirements must not return this */ | ||
411 | case SMCCC_RET_NOT_REQUIRED: | 439 | case SMCCC_RET_NOT_REQUIRED: |
412 | pr_info_once("%s mitigation not required\n", entry->desc); | 440 | pr_info_once("%s mitigation not required\n", entry->desc); |
413 | ssbd_state = ARM64_SSBD_MITIGATED; | 441 | ssbd_state = ARM64_SSBD_MITIGATED; |
414 | return false; | 442 | return false; |
415 | 443 | ||
416 | case SMCCC_RET_SUCCESS: | 444 | case SMCCC_RET_SUCCESS: |
445 | __ssb_safe = false; | ||
417 | required = true; | 446 | required = true; |
418 | break; | 447 | break; |
419 | 448 | ||
@@ -423,6 +452,8 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, | |||
423 | 452 | ||
424 | default: | 453 | default: |
425 | WARN_ON(1); | 454 | WARN_ON(1); |
455 | if (!this_cpu_safe) | ||
456 | __ssb_safe = false; | ||
426 | return false; | 457 | return false; |
427 | } | 458 | } |
428 | 459 | ||
@@ -462,7 +493,14 @@ out_printmsg: | |||
462 | 493 | ||
463 | return required; | 494 | return required; |
464 | } | 495 | } |
465 | #endif /* CONFIG_ARM64_SSBD */ | 496 | |
497 | /* known invulnerable cores */ | ||
498 | static const struct midr_range arm64_ssb_cpus[] = { | ||
499 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A35), | ||
500 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), | ||
501 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), | ||
502 | {}, | ||
503 | }; | ||
466 | 504 | ||
467 | static void __maybe_unused | 505 | static void __maybe_unused |
468 | cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused) | 506 | cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused) |
@@ -507,26 +545,67 @@ cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused) | |||
507 | .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \ | 545 | .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \ |
508 | CAP_MIDR_RANGE_LIST(midr_list) | 546 | CAP_MIDR_RANGE_LIST(midr_list) |
509 | 547 | ||
510 | #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR | 548 | /* Track overall mitigation state. We are only mitigated if all cores are ok */ |
549 | static bool __hardenbp_enab = true; | ||
550 | static bool __spectrev2_safe = true; | ||
511 | 551 | ||
512 | /* | 552 | /* |
513 | * List of CPUs where we need to issue a psci call to | 553 | * List of CPUs that do not need any Spectre-v2 mitigation at all. |
514 | * harden the branch predictor. | ||
515 | */ | 554 | */ |
516 | static const struct midr_range arm64_bp_harden_smccc_cpus[] = { | 555 | static const struct midr_range spectre_v2_safe_list[] = { |
517 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), | 556 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A35), |
518 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), | 557 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), |
519 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), | 558 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), |
520 | MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), | 559 | { /* sentinel */ } |
521 | MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN), | ||
522 | MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2), | ||
523 | MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1), | ||
524 | MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR), | ||
525 | MIDR_ALL_VERSIONS(MIDR_NVIDIA_DENVER), | ||
526 | {}, | ||
527 | }; | 560 | }; |
528 | 561 | ||
529 | #endif | 562 | /* |
563 | * Track overall bp hardening for all heterogeneous cores in the machine. | ||
564 | * We are only considered "safe" if all booted cores are known safe. | ||
565 | */ | ||
566 | static bool __maybe_unused | ||
567 | check_branch_predictor(const struct arm64_cpu_capabilities *entry, int scope) | ||
568 | { | ||
569 | int need_wa; | ||
570 | |||
571 | WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); | ||
572 | |||
573 | /* If the CPU has CSV2 set, we're safe */ | ||
574 | if (cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64PFR0_EL1), | ||
575 | ID_AA64PFR0_CSV2_SHIFT)) | ||
576 | return false; | ||
577 | |||
578 | /* Alternatively, we have a list of unaffected CPUs */ | ||
579 | if (is_midr_in_range_list(read_cpuid_id(), spectre_v2_safe_list)) | ||
580 | return false; | ||
581 | |||
582 | /* Fallback to firmware detection */ | ||
583 | need_wa = detect_harden_bp_fw(); | ||
584 | if (!need_wa) | ||
585 | return false; | ||
586 | |||
587 | __spectrev2_safe = false; | ||
588 | |||
589 | if (!IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR)) { | ||
590 | pr_warn_once("spectrev2 mitigation disabled by kernel configuration\n"); | ||
591 | __hardenbp_enab = false; | ||
592 | return false; | ||
593 | } | ||
594 | |||
595 | /* forced off */ | ||
596 | if (__nospectre_v2 || cpu_mitigations_off()) { | ||
597 | pr_info_once("spectrev2 mitigation disabled by command line option\n"); | ||
598 | __hardenbp_enab = false; | ||
599 | return false; | ||
600 | } | ||
601 | |||
602 | if (need_wa < 0) { | ||
603 | pr_warn_once("ARM_SMCCC_ARCH_WORKAROUND_1 missing from firmware\n"); | ||
604 | __hardenbp_enab = false; | ||
605 | } | ||
606 | |||
607 | return (need_wa > 0); | ||
608 | } | ||
530 | 609 | ||
531 | #ifdef CONFIG_HARDEN_EL2_VECTORS | 610 | #ifdef CONFIG_HARDEN_EL2_VECTORS |
532 | 611 | ||
@@ -701,13 +780,11 @@ const struct arm64_cpu_capabilities arm64_errata[] = { | |||
701 | ERRATA_MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), | 780 | ERRATA_MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), |
702 | }, | 781 | }, |
703 | #endif | 782 | #endif |
704 | #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR | ||
705 | { | 783 | { |
706 | .capability = ARM64_HARDEN_BRANCH_PREDICTOR, | 784 | .capability = ARM64_HARDEN_BRANCH_PREDICTOR, |
707 | .cpu_enable = enable_smccc_arch_workaround_1, | 785 | .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, |
708 | ERRATA_MIDR_RANGE_LIST(arm64_bp_harden_smccc_cpus), | 786 | .matches = check_branch_predictor, |
709 | }, | 787 | }, |
710 | #endif | ||
711 | #ifdef CONFIG_HARDEN_EL2_VECTORS | 788 | #ifdef CONFIG_HARDEN_EL2_VECTORS |
712 | { | 789 | { |
713 | .desc = "EL2 vector hardening", | 790 | .desc = "EL2 vector hardening", |
@@ -715,14 +792,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = { | |||
715 | ERRATA_MIDR_RANGE_LIST(arm64_harden_el2_vectors), | 792 | ERRATA_MIDR_RANGE_LIST(arm64_harden_el2_vectors), |
716 | }, | 793 | }, |
717 | #endif | 794 | #endif |
718 | #ifdef CONFIG_ARM64_SSBD | ||
719 | { | 795 | { |
720 | .desc = "Speculative Store Bypass Disable", | 796 | .desc = "Speculative Store Bypass Disable", |
721 | .capability = ARM64_SSBD, | 797 | .capability = ARM64_SSBD, |
722 | .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, | 798 | .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, |
723 | .matches = has_ssbd_mitigation, | 799 | .matches = has_ssbd_mitigation, |
800 | .midr_range_list = arm64_ssb_cpus, | ||
724 | }, | 801 | }, |
725 | #endif | ||
726 | #ifdef CONFIG_ARM64_ERRATUM_1188873 | 802 | #ifdef CONFIG_ARM64_ERRATUM_1188873 |
727 | { | 803 | { |
728 | /* Cortex-A76 r0p0 to r2p0 */ | 804 | /* Cortex-A76 r0p0 to r2p0 */ |
@@ -742,3 +818,38 @@ const struct arm64_cpu_capabilities arm64_errata[] = { | |||
742 | { | 818 | { |
743 | } | 819 | } |
744 | }; | 820 | }; |
821 | |||
822 | ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, | ||
823 | char *buf) | ||
824 | { | ||
825 | return sprintf(buf, "Mitigation: __user pointer sanitization\n"); | ||
826 | } | ||
827 | |||
828 | ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, | ||
829 | char *buf) | ||
830 | { | ||
831 | if (__spectrev2_safe) | ||
832 | return sprintf(buf, "Not affected\n"); | ||
833 | |||
834 | if (__hardenbp_enab) | ||
835 | return sprintf(buf, "Mitigation: Branch predictor hardening\n"); | ||
836 | |||
837 | return sprintf(buf, "Vulnerable\n"); | ||
838 | } | ||
839 | |||
840 | ssize_t cpu_show_spec_store_bypass(struct device *dev, | ||
841 | struct device_attribute *attr, char *buf) | ||
842 | { | ||
843 | if (__ssb_safe) | ||
844 | return sprintf(buf, "Not affected\n"); | ||
845 | |||
846 | switch (ssbd_state) { | ||
847 | case ARM64_SSBD_KERNEL: | ||
848 | case ARM64_SSBD_FORCE_ENABLE: | ||
849 | if (IS_ENABLED(CONFIG_ARM64_SSBD)) | ||
850 | return sprintf(buf, | ||
851 | "Mitigation: Speculative Store Bypass disabled via prctl\n"); | ||
852 | } | ||
853 | |||
854 | return sprintf(buf, "Vulnerable\n"); | ||
855 | } | ||
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index d856c55445a2..2b807f129e60 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/stop_machine.h> | 25 | #include <linux/stop_machine.h> |
26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/cpu.h> | ||
28 | #include <asm/cpu.h> | 29 | #include <asm/cpu.h> |
29 | #include <asm/cpufeature.h> | 30 | #include <asm/cpufeature.h> |
30 | #include <asm/cpu_ops.h> | 31 | #include <asm/cpu_ops.h> |
@@ -956,7 +957,7 @@ has_useable_cnp(const struct arm64_cpu_capabilities *entry, int scope) | |||
956 | return has_cpuid_feature(entry, scope); | 957 | return has_cpuid_feature(entry, scope); |
957 | } | 958 | } |
958 | 959 | ||
959 | #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 | 960 | static bool __meltdown_safe = true; |
960 | static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ | 961 | static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ |
961 | 962 | ||
962 | static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, | 963 | static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, |
@@ -975,7 +976,17 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, | |||
975 | MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), | 976 | MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), |
976 | { /* sentinel */ } | 977 | { /* sentinel */ } |
977 | }; | 978 | }; |
978 | char const *str = "command line option"; | 979 | char const *str = "kpti command line option"; |
980 | bool meltdown_safe; | ||
981 | |||
982 | meltdown_safe = is_midr_in_range_list(read_cpuid_id(), kpti_safe_list); | ||
983 | |||
984 | /* Defer to CPU feature registers */ | ||
985 | if (has_cpuid_feature(entry, scope)) | ||
986 | meltdown_safe = true; | ||
987 | |||
988 | if (!meltdown_safe) | ||
989 | __meltdown_safe = false; | ||
979 | 990 | ||
980 | /* | 991 | /* |
981 | * For reasons that aren't entirely clear, enabling KPTI on Cavium | 992 | * For reasons that aren't entirely clear, enabling KPTI on Cavium |
@@ -987,6 +998,24 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, | |||
987 | __kpti_forced = -1; | 998 | __kpti_forced = -1; |
988 | } | 999 | } |
989 | 1000 | ||
1001 | /* Useful for KASLR robustness */ | ||
1002 | if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset() > 0) { | ||
1003 | if (!__kpti_forced) { | ||
1004 | str = "KASLR"; | ||
1005 | __kpti_forced = 1; | ||
1006 | } | ||
1007 | } | ||
1008 | |||
1009 | if (cpu_mitigations_off() && !__kpti_forced) { | ||
1010 | str = "mitigations=off"; | ||
1011 | __kpti_forced = -1; | ||
1012 | } | ||
1013 | |||
1014 | if (!IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) { | ||
1015 | pr_info_once("kernel page table isolation disabled by kernel configuration\n"); | ||
1016 | return false; | ||
1017 | } | ||
1018 | |||
990 | /* Forced? */ | 1019 | /* Forced? */ |
991 | if (__kpti_forced) { | 1020 | if (__kpti_forced) { |
992 | pr_info_once("kernel page table isolation forced %s by %s\n", | 1021 | pr_info_once("kernel page table isolation forced %s by %s\n", |
@@ -994,18 +1023,10 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, | |||
994 | return __kpti_forced > 0; | 1023 | return __kpti_forced > 0; |
995 | } | 1024 | } |
996 | 1025 | ||
997 | /* Useful for KASLR robustness */ | 1026 | return !meltdown_safe; |
998 | if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) | ||
999 | return kaslr_offset() > 0; | ||
1000 | |||
1001 | /* Don't force KPTI for CPUs that are not vulnerable */ | ||
1002 | if (is_midr_in_range_list(read_cpuid_id(), kpti_safe_list)) | ||
1003 | return false; | ||
1004 | |||
1005 | /* Defer to CPU feature registers */ | ||
1006 | return !has_cpuid_feature(entry, scope); | ||
1007 | } | 1027 | } |
1008 | 1028 | ||
1029 | #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 | ||
1009 | static void | 1030 | static void |
1010 | kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) | 1031 | kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) |
1011 | { | 1032 | { |
@@ -1035,6 +1056,12 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) | |||
1035 | 1056 | ||
1036 | return; | 1057 | return; |
1037 | } | 1058 | } |
1059 | #else | ||
1060 | static void | ||
1061 | kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) | ||
1062 | { | ||
1063 | } | ||
1064 | #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ | ||
1038 | 1065 | ||
1039 | static int __init parse_kpti(char *str) | 1066 | static int __init parse_kpti(char *str) |
1040 | { | 1067 | { |
@@ -1048,7 +1075,6 @@ static int __init parse_kpti(char *str) | |||
1048 | return 0; | 1075 | return 0; |
1049 | } | 1076 | } |
1050 | early_param("kpti", parse_kpti); | 1077 | early_param("kpti", parse_kpti); |
1051 | #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ | ||
1052 | 1078 | ||
1053 | #ifdef CONFIG_ARM64_HW_AFDBM | 1079 | #ifdef CONFIG_ARM64_HW_AFDBM |
1054 | static inline void __cpu_enable_hw_dbm(void) | 1080 | static inline void __cpu_enable_hw_dbm(void) |
@@ -1315,7 +1341,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { | |||
1315 | .field_pos = ID_AA64PFR0_EL0_SHIFT, | 1341 | .field_pos = ID_AA64PFR0_EL0_SHIFT, |
1316 | .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT, | 1342 | .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT, |
1317 | }, | 1343 | }, |
1318 | #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 | ||
1319 | { | 1344 | { |
1320 | .desc = "Kernel page table isolation (KPTI)", | 1345 | .desc = "Kernel page table isolation (KPTI)", |
1321 | .capability = ARM64_UNMAP_KERNEL_AT_EL0, | 1346 | .capability = ARM64_UNMAP_KERNEL_AT_EL0, |
@@ -1331,7 +1356,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { | |||
1331 | .matches = unmap_kernel_at_el0, | 1356 | .matches = unmap_kernel_at_el0, |
1332 | .cpu_enable = kpti_install_ng_mappings, | 1357 | .cpu_enable = kpti_install_ng_mappings, |
1333 | }, | 1358 | }, |
1334 | #endif | ||
1335 | { | 1359 | { |
1336 | /* FP/SIMD is not implemented */ | 1360 | /* FP/SIMD is not implemented */ |
1337 | .capability = ARM64_HAS_NO_FPSIMD, | 1361 | .capability = ARM64_HAS_NO_FPSIMD, |
@@ -2156,3 +2180,15 @@ static int __init enable_mrs_emulation(void) | |||
2156 | } | 2180 | } |
2157 | 2181 | ||
2158 | core_initcall(enable_mrs_emulation); | 2182 | core_initcall(enable_mrs_emulation); |
2183 | |||
2184 | ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, | ||
2185 | char *buf) | ||
2186 | { | ||
2187 | if (__meltdown_safe) | ||
2188 | return sprintf(buf, "Not affected\n"); | ||
2189 | |||
2190 | if (arm64_kernel_unmapped_at_el0()) | ||
2191 | return sprintf(buf, "Mitigation: PTI\n"); | ||
2192 | |||
2193 | return sprintf(buf, "Vulnerable\n"); | ||
2194 | } | ||
diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index b33bafb8fcea..70568ccbd9fd 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c | |||
@@ -57,7 +57,7 @@ void setup_barrier_nospec(void) | |||
57 | enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && | 57 | enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && |
58 | security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); | 58 | security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); |
59 | 59 | ||
60 | if (!no_nospec) | 60 | if (!no_nospec && !cpu_mitigations_off()) |
61 | enable_barrier_nospec(enable); | 61 | enable_barrier_nospec(enable); |
62 | } | 62 | } |
63 | 63 | ||
@@ -116,7 +116,7 @@ static int __init handle_nospectre_v2(char *p) | |||
116 | early_param("nospectre_v2", handle_nospectre_v2); | 116 | early_param("nospectre_v2", handle_nospectre_v2); |
117 | void setup_spectre_v2(void) | 117 | void setup_spectre_v2(void) |
118 | { | 118 | { |
119 | if (no_spectrev2) | 119 | if (no_spectrev2 || cpu_mitigations_off()) |
120 | do_btb_flush_fixups(); | 120 | do_btb_flush_fixups(); |
121 | else | 121 | else |
122 | btb_flush_enabled = true; | 122 | btb_flush_enabled = true; |
@@ -300,7 +300,7 @@ void setup_stf_barrier(void) | |||
300 | 300 | ||
301 | stf_enabled_flush_types = type; | 301 | stf_enabled_flush_types = type; |
302 | 302 | ||
303 | if (!no_stf_barrier) | 303 | if (!no_stf_barrier && !cpu_mitigations_off()) |
304 | stf_barrier_enable(enable); | 304 | stf_barrier_enable(enable); |
305 | } | 305 | } |
306 | 306 | ||
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index ba404dd9ce1d..4f49e1a3594c 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -932,7 +932,7 @@ void setup_rfi_flush(enum l1d_flush_type types, bool enable) | |||
932 | 932 | ||
933 | enabled_flush_types = types; | 933 | enabled_flush_types = types; |
934 | 934 | ||
935 | if (!no_rfi_flush) | 935 | if (!no_rfi_flush && !cpu_mitigations_off()) |
936 | rfi_flush_enable(enable); | 936 | rfi_flush_enable(enable); |
937 | } | 937 | } |
938 | 938 | ||
diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index bdddaae96559..649135cbedd5 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c | |||
@@ -1,6 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/module.h> | 2 | #include <linux/module.h> |
3 | #include <linux/device.h> | 3 | #include <linux/device.h> |
4 | #include <linux/cpu.h> | ||
4 | #include <asm/nospec-branch.h> | 5 | #include <asm/nospec-branch.h> |
5 | 6 | ||
6 | static int __init nobp_setup_early(char *str) | 7 | static int __init nobp_setup_early(char *str) |
@@ -58,7 +59,7 @@ early_param("nospectre_v2", nospectre_v2_setup_early); | |||
58 | 59 | ||
59 | void __init nospec_auto_detect(void) | 60 | void __init nospec_auto_detect(void) |
60 | { | 61 | { |
61 | if (test_facility(156)) { | 62 | if (test_facility(156) || cpu_mitigations_off()) { |
62 | /* | 63 | /* |
63 | * The machine supports etokens. | 64 | * The machine supports etokens. |
64 | * Disable expolines and disable nobp. | 65 | * Disable expolines and disable nobp. |
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 2da82eff0eb4..8043a21f36be 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c | |||
@@ -440,7 +440,8 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) | |||
440 | char arg[20]; | 440 | char arg[20]; |
441 | int ret, i; | 441 | int ret, i; |
442 | 442 | ||
443 | if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) | 443 | if (cmdline_find_option_bool(boot_command_line, "nospectre_v2") || |
444 | cpu_mitigations_off()) | ||
444 | return SPECTRE_V2_CMD_NONE; | 445 | return SPECTRE_V2_CMD_NONE; |
445 | 446 | ||
446 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg)); | 447 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg)); |
@@ -672,7 +673,8 @@ static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void) | |||
672 | char arg[20]; | 673 | char arg[20]; |
673 | int ret, i; | 674 | int ret, i; |
674 | 675 | ||
675 | if (cmdline_find_option_bool(boot_command_line, "nospec_store_bypass_disable")) { | 676 | if (cmdline_find_option_bool(boot_command_line, "nospec_store_bypass_disable") || |
677 | cpu_mitigations_off()) { | ||
676 | return SPEC_STORE_BYPASS_CMD_NONE; | 678 | return SPEC_STORE_BYPASS_CMD_NONE; |
677 | } else { | 679 | } else { |
678 | ret = cmdline_find_option(boot_command_line, "spec_store_bypass_disable", | 680 | ret = cmdline_find_option(boot_command_line, "spec_store_bypass_disable", |
@@ -1008,6 +1010,11 @@ static void __init l1tf_select_mitigation(void) | |||
1008 | if (!boot_cpu_has_bug(X86_BUG_L1TF)) | 1010 | if (!boot_cpu_has_bug(X86_BUG_L1TF)) |
1009 | return; | 1011 | return; |
1010 | 1012 | ||
1013 | if (cpu_mitigations_off()) | ||
1014 | l1tf_mitigation = L1TF_MITIGATION_OFF; | ||
1015 | else if (cpu_mitigations_auto_nosmt()) | ||
1016 | l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOSMT; | ||
1017 | |||
1011 | override_cache_bits(&boot_cpu_data); | 1018 | override_cache_bits(&boot_cpu_data); |
1012 | 1019 | ||
1013 | switch (l1tf_mitigation) { | 1020 | switch (l1tf_mitigation) { |
diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index 139b28a01ce4..d0255d64edce 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
36 | #include <linux/mm.h> | 36 | #include <linux/mm.h> |
37 | #include <linux/uaccess.h> | 37 | #include <linux/uaccess.h> |
38 | #include <linux/cpu.h> | ||
38 | 39 | ||
39 | #include <asm/cpufeature.h> | 40 | #include <asm/cpufeature.h> |
40 | #include <asm/hypervisor.h> | 41 | #include <asm/hypervisor.h> |
@@ -115,7 +116,8 @@ void __init pti_check_boottime_disable(void) | |||
115 | } | 116 | } |
116 | } | 117 | } |
117 | 118 | ||
118 | if (cmdline_find_option_bool(boot_command_line, "nopti")) { | 119 | if (cmdline_find_option_bool(boot_command_line, "nopti") || |
120 | cpu_mitigations_off()) { | ||
119 | pti_mode = PTI_FORCE_OFF; | 121 | pti_mode = PTI_FORCE_OFF; |
120 | pti_print_if_insecure("disabled on command line."); | 122 | pti_print_if_insecure("disabled on command line."); |
121 | return; | 123 | return; |
diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 5041357d0297..2d9c6f4b78f5 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h | |||
@@ -187,4 +187,28 @@ static inline void cpu_smt_disable(bool force) { } | |||
187 | static inline void cpu_smt_check_topology(void) { } | 187 | static inline void cpu_smt_check_topology(void) { } |
188 | #endif | 188 | #endif |
189 | 189 | ||
190 | /* | ||
191 | * These are used for a global "mitigations=" cmdline option for toggling | ||
192 | * optional CPU mitigations. | ||
193 | */ | ||
194 | enum cpu_mitigations { | ||
195 | CPU_MITIGATIONS_OFF, | ||
196 | CPU_MITIGATIONS_AUTO, | ||
197 | CPU_MITIGATIONS_AUTO_NOSMT, | ||
198 | }; | ||
199 | |||
200 | extern enum cpu_mitigations cpu_mitigations; | ||
201 | |||
202 | /* mitigations=off */ | ||
203 | static inline bool cpu_mitigations_off(void) | ||
204 | { | ||
205 | return cpu_mitigations == CPU_MITIGATIONS_OFF; | ||
206 | } | ||
207 | |||
208 | /* mitigations=auto,nosmt */ | ||
209 | static inline bool cpu_mitigations_auto_nosmt(void) | ||
210 | { | ||
211 | return cpu_mitigations == CPU_MITIGATIONS_AUTO_NOSMT; | ||
212 | } | ||
213 | |||
190 | #endif /* _LINUX_CPU_H_ */ | 214 | #endif /* _LINUX_CPU_H_ */ |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 6754f3ecfd94..43e741e88691 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -2304,3 +2304,18 @@ void __init boot_cpu_hotplug_init(void) | |||
2304 | #endif | 2304 | #endif |
2305 | this_cpu_write(cpuhp_state.state, CPUHP_ONLINE); | 2305 | this_cpu_write(cpuhp_state.state, CPUHP_ONLINE); |
2306 | } | 2306 | } |
2307 | |||
2308 | enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO; | ||
2309 | |||
2310 | static int __init mitigations_parse_cmdline(char *arg) | ||
2311 | { | ||
2312 | if (!strcmp(arg, "off")) | ||
2313 | cpu_mitigations = CPU_MITIGATIONS_OFF; | ||
2314 | else if (!strcmp(arg, "auto")) | ||
2315 | cpu_mitigations = CPU_MITIGATIONS_AUTO; | ||
2316 | else if (!strcmp(arg, "auto,nosmt")) | ||
2317 | cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT; | ||
2318 | |||
2319 | return 0; | ||
2320 | } | ||
2321 | early_param("mitigations", mitigations_parse_cmdline); | ||