Loading Documentation/admin-guide/kernel-parameters.rst +1 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ parameter is applicable:: APIC APIC support is enabled. APM Advanced Power Management support is enabled. ARM ARM architecture is enabled. ARM64 ARM64 architecture is enabled. AX25 Appropriate AX.25 support is enabled. CLK Common clock infrastructure is enabled. CMA Contiguous Memory Area support is enabled. Loading Documentation/admin-guide/kernel-parameters.txt +38 −4 Original line number Diff line number Diff line Loading @@ -2544,6 +2544,40 @@ in the "bleeding edge" mini2440 support kernel at http://repo.or.cz/w/linux-2.6/mini2440.git mitigations= [X86,PPC,S390,ARM64] Control optional mitigations for CPU vulnerabilities. This is a set of curated, arch-independent options, each of which is an aggregation of existing arch-specific options. off Disable all optional CPU mitigations. This improves system performance, but it may also expose users to several CPU vulnerabilities. Equivalent to: nopti [X86,PPC] kpti=0 [ARM64] nospectre_v1 [PPC] nobp=0 [S390] nospectre_v2 [X86,PPC,S390,ARM64] spectre_v2_user=off [X86] spec_store_bypass_disable=off [X86,PPC] ssbd=force-off [ARM64] l1tf=off [X86] auto (default) Mitigate all CPU vulnerabilities, but leave SMT enabled, even if it's vulnerable. This is for users who don't want to be surprised by SMT getting disabled across kernel upgrades, or who have other ways of avoiding SMT-based attacks. Equivalent to: (default behavior) auto,nosmt Mitigate all CPU vulnerabilities, disabling SMT if needed. This is for users who always want to be fully mitigated, even if it means losing SMT. Equivalent to: l1tf=flush,nosmt [X86] mminit_loglevel= [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this parameter allows control of the logging verbosity for Loading Loading @@ -2873,10 +2907,10 @@ check bypass). With this option data leaks are possible in the system. nospectre_v2 [X86,PPC_FSL_BOOK3E] Disable all mitigations for the Spectre variant 2 (indirect branch prediction) vulnerability. System may allow data leaks with this option, which is equivalent to spectre_v2=off. nospectre_v2 [X86,PPC_FSL_BOOK3E,ARM64] Disable all mitigations for the Spectre variant 2 (indirect branch prediction) vulnerability. System may allow data leaks with this option. nospec_store_bypass_disable [HW] Disable all mitigations for the Speculative Store Bypass vulnerability Loading arch/arm64/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ config ARM64 select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS_BROADCAST select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_IDLE_POLL_SETUP select GENERIC_IRQ_MULTI_HANDLER Loading arch/arm64/include/asm/cpufeature.h +0 −4 Original line number Diff line number Diff line Loading @@ -633,11 +633,7 @@ static inline int arm64_get_ssbd_state(void) #endif } #ifdef CONFIG_ARM64_SSBD void arm64_set_ssbd_mitigation(bool state); #else static inline void arm64_set_ssbd_mitigation(bool state) {} #endif extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); Loading arch/arm64/kernel/cpu_errata.c +177 −66 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/arm-smccc.h> #include <linux/psci.h> #include <linux/types.h> #include <linux/cpu.h> #include <asm/cpu.h> #include <asm/cputype.h> #include <asm/cpufeature.h> Loading Loading @@ -109,7 +110,6 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused) atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1); #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR #include <asm/mmu_context.h> #include <asm/cacheflush.h> Loading @@ -131,7 +131,7 @@ static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, __flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); } static void __install_bp_hardening_cb(bp_hardening_cb_t fn, static void install_bp_hardening_cb(bp_hardening_cb_t fn, const char *hyp_vecs_start, const char *hyp_vecs_end) { Loading Loading @@ -169,7 +169,7 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, #define __smccc_workaround_1_smc_start NULL #define __smccc_workaround_1_smc_end NULL static void __install_bp_hardening_cb(bp_hardening_cb_t fn, static void install_bp_hardening_cb(bp_hardening_cb_t fn, const char *hyp_vecs_start, const char *hyp_vecs_end) { Loading @@ -177,23 +177,6 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, } #endif /* CONFIG_KVM_INDIRECT_VECTORS */ static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, bp_hardening_cb_t fn, const char *hyp_vecs_start, const char *hyp_vecs_end) { u64 pfr0; if (!entry->matches(entry, SCOPE_LOCAL_CPU)) return; pfr0 = read_cpuid(ID_AA64PFR0_EL1); if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT)) return; __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); } #include <uapi/linux/psci.h> #include <linux/arm-smccc.h> #include <linux/psci.h> Loading @@ -220,60 +203,83 @@ static void qcom_link_stack_sanitization(void) : "=&r" (tmp)); } static void enable_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry) static bool __nospectre_v2; static int __init parse_nospectre_v2(char *str) { __nospectre_v2 = true; return 0; } early_param("nospectre_v2", parse_nospectre_v2); /* * -1: No workaround * 0: No workaround required * 1: Workaround installed */ static int detect_harden_bp_fw(void) { bp_hardening_cb_t cb; void *smccc_start, *smccc_end; struct arm_smccc_res res; u32 midr = read_cpuid_id(); if (!entry->matches(entry, SCOPE_LOCAL_CPU)) return; if (psci_ops.smccc_version == SMCCC_VERSION_1_0) return; return -1; switch (psci_ops.conduit) { case PSCI_CONDUIT_HVC: arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); if ((int)res.a0 < 0) return; switch ((int)res.a0) { case 1: /* Firmware says we're just fine */ return 0; case 0: cb = call_hvc_arch_workaround_1; /* This is a guest, no need to patch KVM vectors */ smccc_start = NULL; smccc_end = NULL; break; default: return -1; } break; case PSCI_CONDUIT_SMC: arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); if ((int)res.a0 < 0) return; switch ((int)res.a0) { case 1: /* Firmware says we're just fine */ return 0; case 0: cb = call_smc_arch_workaround_1; smccc_start = __smccc_workaround_1_smc_start; smccc_end = __smccc_workaround_1_smc_end; break; default: return -1; } break; default: return; return -1; } if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) || ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)) cb = qcom_link_stack_sanitization; install_bp_hardening_cb(entry, cb, smccc_start, smccc_end); if (IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR)) install_bp_hardening_cb(cb, smccc_start, smccc_end); return; return 1; } #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #ifdef CONFIG_ARM64_SSBD DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); int ssbd_state __read_mostly = ARM64_SSBD_KERNEL; static bool __ssb_safe = true; static const struct ssbd_options { const char *str; Loading Loading @@ -343,6 +349,11 @@ void __init arm64_enable_wa2_handling(struct alt_instr *alt, void arm64_set_ssbd_mitigation(bool state) { if (!IS_ENABLED(CONFIG_ARM64_SSBD)) { pr_info_once("SSBD disabled by kernel configuration\n"); return; } if (this_cpu_has_cap(ARM64_SSBS)) { if (state) asm volatile(SET_PSTATE_SSBS(0)); Loading Loading @@ -372,16 +383,28 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, struct arm_smccc_res res; bool required = true; s32 val; bool this_cpu_safe = false; WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); if (cpu_mitigations_off()) ssbd_state = ARM64_SSBD_FORCE_DISABLE; /* delay setting __ssb_safe until we get a firmware response */ if (is_midr_in_range_list(read_cpuid_id(), entry->midr_range_list)) this_cpu_safe = true; if (this_cpu_has_cap(ARM64_SSBS)) { if (!this_cpu_safe) __ssb_safe = false; required = false; goto out_printmsg; } if (psci_ops.smccc_version == SMCCC_VERSION_1_0) { ssbd_state = ARM64_SSBD_UNKNOWN; if (!this_cpu_safe) __ssb_safe = false; return false; } Loading @@ -398,6 +421,8 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, default: ssbd_state = ARM64_SSBD_UNKNOWN; if (!this_cpu_safe) __ssb_safe = false; return false; } Loading @@ -406,14 +431,18 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, switch (val) { case SMCCC_RET_NOT_SUPPORTED: ssbd_state = ARM64_SSBD_UNKNOWN; if (!this_cpu_safe) __ssb_safe = false; return false; /* machines with mixed mitigation requirements must not return this */ case SMCCC_RET_NOT_REQUIRED: pr_info_once("%s mitigation not required\n", entry->desc); ssbd_state = ARM64_SSBD_MITIGATED; return false; case SMCCC_RET_SUCCESS: __ssb_safe = false; required = true; break; Loading @@ -423,6 +452,8 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, default: WARN_ON(1); if (!this_cpu_safe) __ssb_safe = false; return false; } Loading Loading @@ -462,7 +493,14 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, return required; } #endif /* CONFIG_ARM64_SSBD */ /* known invulnerable cores */ static const struct midr_range arm64_ssb_cpus[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A35), MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), {}, }; static void __maybe_unused cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused) Loading Loading @@ -507,26 +545,67 @@ cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused) .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \ CAP_MIDR_RANGE_LIST(midr_list) #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR /* Track overall mitigation state. We are only mitigated if all cores are ok */ static bool __hardenbp_enab = true; static bool __spectrev2_safe = true; /* * List of CPUs where we need to issue a psci call to * harden the branch predictor. * List of CPUs that do not need any Spectre-v2 mitigation at all. */ static const struct midr_range arm64_bp_harden_smccc_cpus[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN), MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2), MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1), MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR), MIDR_ALL_VERSIONS(MIDR_NVIDIA_DENVER), {}, static const struct midr_range spectre_v2_safe_list[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A35), MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), { /* sentinel */ } }; #endif /* * Track overall bp hardening for all heterogeneous cores in the machine. * We are only considered "safe" if all booted cores are known safe. */ static bool __maybe_unused check_branch_predictor(const struct arm64_cpu_capabilities *entry, int scope) { int need_wa; WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); /* If the CPU has CSV2 set, we're safe */ if (cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64PFR0_EL1), ID_AA64PFR0_CSV2_SHIFT)) return false; /* Alternatively, we have a list of unaffected CPUs */ if (is_midr_in_range_list(read_cpuid_id(), spectre_v2_safe_list)) return false; /* Fallback to firmware detection */ need_wa = detect_harden_bp_fw(); if (!need_wa) return false; __spectrev2_safe = false; if (!IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR)) { pr_warn_once("spectrev2 mitigation disabled by kernel configuration\n"); __hardenbp_enab = false; return false; } /* forced off */ if (__nospectre_v2 || cpu_mitigations_off()) { pr_info_once("spectrev2 mitigation disabled by command line option\n"); __hardenbp_enab = false; return false; } if (need_wa < 0) { pr_warn_once("ARM_SMCCC_ARCH_WORKAROUND_1 missing from firmware\n"); __hardenbp_enab = false; } return (need_wa > 0); } #ifdef CONFIG_HARDEN_EL2_VECTORS Loading Loading @@ -701,13 +780,11 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ERRATA_MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), }, #endif #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, .cpu_enable = enable_smccc_arch_workaround_1, ERRATA_MIDR_RANGE_LIST(arm64_bp_harden_smccc_cpus), .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, .matches = check_branch_predictor, }, #endif #ifdef CONFIG_HARDEN_EL2_VECTORS { .desc = "EL2 vector hardening", Loading @@ -715,14 +792,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ERRATA_MIDR_RANGE_LIST(arm64_harden_el2_vectors), }, #endif #ifdef CONFIG_ARM64_SSBD { .desc = "Speculative Store Bypass Disable", .capability = ARM64_SSBD, .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, .matches = has_ssbd_mitigation, .midr_range_list = arm64_ssb_cpus, }, #endif #ifdef CONFIG_ARM64_ERRATUM_1188873 { /* Cortex-A76 r0p0 to r2p0 */ Loading @@ -742,3 +818,38 @@ const struct arm64_cpu_capabilities arm64_errata[] = { { } }; ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "Mitigation: __user pointer sanitization\n"); } ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) { if (__spectrev2_safe) return sprintf(buf, "Not affected\n"); if (__hardenbp_enab) return sprintf(buf, "Mitigation: Branch predictor hardening\n"); return sprintf(buf, "Vulnerable\n"); } ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) { if (__ssb_safe) return sprintf(buf, "Not affected\n"); switch (ssbd_state) { case ARM64_SSBD_KERNEL: case ARM64_SSBD_FORCE_ENABLE: if (IS_ENABLED(CONFIG_ARM64_SSBD)) return sprintf(buf, "Mitigation: Speculative Store Bypass disabled via prctl\n"); } return sprintf(buf, "Vulnerable\n"); } Loading
Documentation/admin-guide/kernel-parameters.rst +1 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ parameter is applicable:: APIC APIC support is enabled. APM Advanced Power Management support is enabled. ARM ARM architecture is enabled. ARM64 ARM64 architecture is enabled. AX25 Appropriate AX.25 support is enabled. CLK Common clock infrastructure is enabled. CMA Contiguous Memory Area support is enabled. Loading
Documentation/admin-guide/kernel-parameters.txt +38 −4 Original line number Diff line number Diff line Loading @@ -2544,6 +2544,40 @@ in the "bleeding edge" mini2440 support kernel at http://repo.or.cz/w/linux-2.6/mini2440.git mitigations= [X86,PPC,S390,ARM64] Control optional mitigations for CPU vulnerabilities. This is a set of curated, arch-independent options, each of which is an aggregation of existing arch-specific options. off Disable all optional CPU mitigations. This improves system performance, but it may also expose users to several CPU vulnerabilities. Equivalent to: nopti [X86,PPC] kpti=0 [ARM64] nospectre_v1 [PPC] nobp=0 [S390] nospectre_v2 [X86,PPC,S390,ARM64] spectre_v2_user=off [X86] spec_store_bypass_disable=off [X86,PPC] ssbd=force-off [ARM64] l1tf=off [X86] auto (default) Mitigate all CPU vulnerabilities, but leave SMT enabled, even if it's vulnerable. This is for users who don't want to be surprised by SMT getting disabled across kernel upgrades, or who have other ways of avoiding SMT-based attacks. Equivalent to: (default behavior) auto,nosmt Mitigate all CPU vulnerabilities, disabling SMT if needed. This is for users who always want to be fully mitigated, even if it means losing SMT. Equivalent to: l1tf=flush,nosmt [X86] mminit_loglevel= [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this parameter allows control of the logging verbosity for Loading Loading @@ -2873,10 +2907,10 @@ check bypass). With this option data leaks are possible in the system. nospectre_v2 [X86,PPC_FSL_BOOK3E] Disable all mitigations for the Spectre variant 2 (indirect branch prediction) vulnerability. System may allow data leaks with this option, which is equivalent to spectre_v2=off. nospectre_v2 [X86,PPC_FSL_BOOK3E,ARM64] Disable all mitigations for the Spectre variant 2 (indirect branch prediction) vulnerability. System may allow data leaks with this option. nospec_store_bypass_disable [HW] Disable all mitigations for the Speculative Store Bypass vulnerability Loading
arch/arm64/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ config ARM64 select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS_BROADCAST select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_IDLE_POLL_SETUP select GENERIC_IRQ_MULTI_HANDLER Loading
arch/arm64/include/asm/cpufeature.h +0 −4 Original line number Diff line number Diff line Loading @@ -633,11 +633,7 @@ static inline int arm64_get_ssbd_state(void) #endif } #ifdef CONFIG_ARM64_SSBD void arm64_set_ssbd_mitigation(bool state); #else static inline void arm64_set_ssbd_mitigation(bool state) {} #endif extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); Loading
arch/arm64/kernel/cpu_errata.c +177 −66 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <linux/arm-smccc.h> #include <linux/psci.h> #include <linux/types.h> #include <linux/cpu.h> #include <asm/cpu.h> #include <asm/cputype.h> #include <asm/cpufeature.h> Loading Loading @@ -109,7 +110,6 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused) atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1); #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR #include <asm/mmu_context.h> #include <asm/cacheflush.h> Loading @@ -131,7 +131,7 @@ static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, __flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); } static void __install_bp_hardening_cb(bp_hardening_cb_t fn, static void install_bp_hardening_cb(bp_hardening_cb_t fn, const char *hyp_vecs_start, const char *hyp_vecs_end) { Loading Loading @@ -169,7 +169,7 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, #define __smccc_workaround_1_smc_start NULL #define __smccc_workaround_1_smc_end NULL static void __install_bp_hardening_cb(bp_hardening_cb_t fn, static void install_bp_hardening_cb(bp_hardening_cb_t fn, const char *hyp_vecs_start, const char *hyp_vecs_end) { Loading @@ -177,23 +177,6 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, } #endif /* CONFIG_KVM_INDIRECT_VECTORS */ static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, bp_hardening_cb_t fn, const char *hyp_vecs_start, const char *hyp_vecs_end) { u64 pfr0; if (!entry->matches(entry, SCOPE_LOCAL_CPU)) return; pfr0 = read_cpuid(ID_AA64PFR0_EL1); if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT)) return; __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); } #include <uapi/linux/psci.h> #include <linux/arm-smccc.h> #include <linux/psci.h> Loading @@ -220,60 +203,83 @@ static void qcom_link_stack_sanitization(void) : "=&r" (tmp)); } static void enable_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry) static bool __nospectre_v2; static int __init parse_nospectre_v2(char *str) { __nospectre_v2 = true; return 0; } early_param("nospectre_v2", parse_nospectre_v2); /* * -1: No workaround * 0: No workaround required * 1: Workaround installed */ static int detect_harden_bp_fw(void) { bp_hardening_cb_t cb; void *smccc_start, *smccc_end; struct arm_smccc_res res; u32 midr = read_cpuid_id(); if (!entry->matches(entry, SCOPE_LOCAL_CPU)) return; if (psci_ops.smccc_version == SMCCC_VERSION_1_0) return; return -1; switch (psci_ops.conduit) { case PSCI_CONDUIT_HVC: arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); if ((int)res.a0 < 0) return; switch ((int)res.a0) { case 1: /* Firmware says we're just fine */ return 0; case 0: cb = call_hvc_arch_workaround_1; /* This is a guest, no need to patch KVM vectors */ smccc_start = NULL; smccc_end = NULL; break; default: return -1; } break; case PSCI_CONDUIT_SMC: arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); if ((int)res.a0 < 0) return; switch ((int)res.a0) { case 1: /* Firmware says we're just fine */ return 0; case 0: cb = call_smc_arch_workaround_1; smccc_start = __smccc_workaround_1_smc_start; smccc_end = __smccc_workaround_1_smc_end; break; default: return -1; } break; default: return; return -1; } if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) || ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)) cb = qcom_link_stack_sanitization; install_bp_hardening_cb(entry, cb, smccc_start, smccc_end); if (IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR)) install_bp_hardening_cb(cb, smccc_start, smccc_end); return; return 1; } #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #ifdef CONFIG_ARM64_SSBD DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); int ssbd_state __read_mostly = ARM64_SSBD_KERNEL; static bool __ssb_safe = true; static const struct ssbd_options { const char *str; Loading Loading @@ -343,6 +349,11 @@ void __init arm64_enable_wa2_handling(struct alt_instr *alt, void arm64_set_ssbd_mitigation(bool state) { if (!IS_ENABLED(CONFIG_ARM64_SSBD)) { pr_info_once("SSBD disabled by kernel configuration\n"); return; } if (this_cpu_has_cap(ARM64_SSBS)) { if (state) asm volatile(SET_PSTATE_SSBS(0)); Loading Loading @@ -372,16 +383,28 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, struct arm_smccc_res res; bool required = true; s32 val; bool this_cpu_safe = false; WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); if (cpu_mitigations_off()) ssbd_state = ARM64_SSBD_FORCE_DISABLE; /* delay setting __ssb_safe until we get a firmware response */ if (is_midr_in_range_list(read_cpuid_id(), entry->midr_range_list)) this_cpu_safe = true; if (this_cpu_has_cap(ARM64_SSBS)) { if (!this_cpu_safe) __ssb_safe = false; required = false; goto out_printmsg; } if (psci_ops.smccc_version == SMCCC_VERSION_1_0) { ssbd_state = ARM64_SSBD_UNKNOWN; if (!this_cpu_safe) __ssb_safe = false; return false; } Loading @@ -398,6 +421,8 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, default: ssbd_state = ARM64_SSBD_UNKNOWN; if (!this_cpu_safe) __ssb_safe = false; return false; } Loading @@ -406,14 +431,18 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, switch (val) { case SMCCC_RET_NOT_SUPPORTED: ssbd_state = ARM64_SSBD_UNKNOWN; if (!this_cpu_safe) __ssb_safe = false; return false; /* machines with mixed mitigation requirements must not return this */ case SMCCC_RET_NOT_REQUIRED: pr_info_once("%s mitigation not required\n", entry->desc); ssbd_state = ARM64_SSBD_MITIGATED; return false; case SMCCC_RET_SUCCESS: __ssb_safe = false; required = true; break; Loading @@ -423,6 +452,8 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, default: WARN_ON(1); if (!this_cpu_safe) __ssb_safe = false; return false; } Loading Loading @@ -462,7 +493,14 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, return required; } #endif /* CONFIG_ARM64_SSBD */ /* known invulnerable cores */ static const struct midr_range arm64_ssb_cpus[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A35), MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), {}, }; static void __maybe_unused cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused) Loading Loading @@ -507,26 +545,67 @@ cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused) .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \ CAP_MIDR_RANGE_LIST(midr_list) #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR /* Track overall mitigation state. We are only mitigated if all cores are ok */ static bool __hardenbp_enab = true; static bool __spectrev2_safe = true; /* * List of CPUs where we need to issue a psci call to * harden the branch predictor. * List of CPUs that do not need any Spectre-v2 mitigation at all. */ static const struct midr_range arm64_bp_harden_smccc_cpus[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN), MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2), MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1), MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR), MIDR_ALL_VERSIONS(MIDR_NVIDIA_DENVER), {}, static const struct midr_range spectre_v2_safe_list[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A35), MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), { /* sentinel */ } }; #endif /* * Track overall bp hardening for all heterogeneous cores in the machine. * We are only considered "safe" if all booted cores are known safe. */ static bool __maybe_unused check_branch_predictor(const struct arm64_cpu_capabilities *entry, int scope) { int need_wa; WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); /* If the CPU has CSV2 set, we're safe */ if (cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64PFR0_EL1), ID_AA64PFR0_CSV2_SHIFT)) return false; /* Alternatively, we have a list of unaffected CPUs */ if (is_midr_in_range_list(read_cpuid_id(), spectre_v2_safe_list)) return false; /* Fallback to firmware detection */ need_wa = detect_harden_bp_fw(); if (!need_wa) return false; __spectrev2_safe = false; if (!IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR)) { pr_warn_once("spectrev2 mitigation disabled by kernel configuration\n"); __hardenbp_enab = false; return false; } /* forced off */ if (__nospectre_v2 || cpu_mitigations_off()) { pr_info_once("spectrev2 mitigation disabled by command line option\n"); __hardenbp_enab = false; return false; } if (need_wa < 0) { pr_warn_once("ARM_SMCCC_ARCH_WORKAROUND_1 missing from firmware\n"); __hardenbp_enab = false; } return (need_wa > 0); } #ifdef CONFIG_HARDEN_EL2_VECTORS Loading Loading @@ -701,13 +780,11 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ERRATA_MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), }, #endif #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, .cpu_enable = enable_smccc_arch_workaround_1, ERRATA_MIDR_RANGE_LIST(arm64_bp_harden_smccc_cpus), .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, .matches = check_branch_predictor, }, #endif #ifdef CONFIG_HARDEN_EL2_VECTORS { .desc = "EL2 vector hardening", Loading @@ -715,14 +792,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ERRATA_MIDR_RANGE_LIST(arm64_harden_el2_vectors), }, #endif #ifdef CONFIG_ARM64_SSBD { .desc = "Speculative Store Bypass Disable", .capability = ARM64_SSBD, .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, .matches = has_ssbd_mitigation, .midr_range_list = arm64_ssb_cpus, }, #endif #ifdef CONFIG_ARM64_ERRATUM_1188873 { /* Cortex-A76 r0p0 to r2p0 */ Loading @@ -742,3 +818,38 @@ const struct arm64_cpu_capabilities arm64_errata[] = { { } }; ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "Mitigation: __user pointer sanitization\n"); } ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) { if (__spectrev2_safe) return sprintf(buf, "Not affected\n"); if (__hardenbp_enab) return sprintf(buf, "Mitigation: Branch predictor hardening\n"); return sprintf(buf, "Vulnerable\n"); } ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) { if (__ssb_safe) return sprintf(buf, "Not affected\n"); switch (ssbd_state) { case ARM64_SSBD_KERNEL: case ARM64_SSBD_FORCE_ENABLE: if (IS_ENABLED(CONFIG_ARM64_SSBD)) return sprintf(buf, "Mitigation: Speculative Store Bypass disabled via prctl\n"); } return sprintf(buf, "Vulnerable\n"); }