Commit 50abbe19 authored by Will Deacon's avatar Will Deacon

Merge branch 'for-next/mitigations' of...

Merge branch 'for-next/mitigations' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux into for-next/core
parents 9431ac2b 4ad499c9
...@@ -88,6 +88,7 @@ parameter is applicable:: ...@@ -88,6 +88,7 @@ parameter is applicable::
APIC APIC support is enabled. APIC APIC support is enabled.
APM Advanced Power Management support is enabled. APM Advanced Power Management support is enabled.
ARM ARM architecture is enabled. ARM ARM architecture is enabled.
ARM64 ARM64 architecture is enabled.
AX25 Appropriate AX.25 support is enabled. AX25 Appropriate AX.25 support is enabled.
CLK Common clock infrastructure is enabled. CLK Common clock infrastructure is enabled.
CMA Contiguous Memory Area support is enabled. CMA Contiguous Memory Area support is enabled.
......
...@@ -2544,6 +2544,40 @@ ...@@ -2544,6 +2544,40 @@
in the "bleeding edge" mini2440 support kernel at in the "bleeding edge" mini2440 support kernel at
http://repo.or.cz/w/linux-2.6/mini2440.git 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= mminit_loglevel=
[KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
parameter allows control of the logging verbosity for parameter allows control of the logging verbosity for
...@@ -2873,10 +2907,10 @@ ...@@ -2873,10 +2907,10 @@
check bypass). With this option data leaks are possible check bypass). With this option data leaks are possible
in the system. in the system.
nospectre_v2 [X86,PPC_FSL_BOOK3E] Disable all mitigations for the Spectre variant 2 nospectre_v2 [X86,PPC_FSL_BOOK3E,ARM64] Disable all mitigations for
(indirect branch prediction) vulnerability. System may the Spectre variant 2 (indirect branch prediction)
allow data leaks with this option, which is equivalent vulnerability. System may allow data leaks with this
to spectre_v2=off. option.
nospec_store_bypass_disable nospec_store_bypass_disable
[HW] Disable all mitigations for the Speculative Store Bypass vulnerability [HW] Disable all mitigations for the Speculative Store Bypass vulnerability
......
...@@ -90,6 +90,7 @@ config ARM64 ...@@ -90,6 +90,7 @@ config ARM64
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST select GENERIC_CLOCKEVENTS_BROADCAST
select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_AUTOPROBE
select GENERIC_CPU_VULNERABILITIES
select GENERIC_EARLY_IOREMAP select GENERIC_EARLY_IOREMAP
select GENERIC_IDLE_POLL_SETUP select GENERIC_IDLE_POLL_SETUP
select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_MULTI_HANDLER
......
...@@ -633,11 +633,7 @@ static inline int arm64_get_ssbd_state(void) ...@@ -633,11 +633,7 @@ static inline int arm64_get_ssbd_state(void)
#endif #endif
} }
#ifdef CONFIG_ARM64_SSBD
void arm64_set_ssbd_mitigation(bool state); 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); extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
......
This diff is collapsed.
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/stop_machine.h> #include <linux/stop_machine.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/cpu.h>
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/cpu_ops.h> #include <asm/cpu_ops.h>
...@@ -956,7 +957,7 @@ has_useable_cnp(const struct arm64_cpu_capabilities *entry, int scope) ...@@ -956,7 +957,7 @@ has_useable_cnp(const struct arm64_cpu_capabilities *entry, int scope)
return has_cpuid_feature(entry, scope); return has_cpuid_feature(entry, scope);
} }
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 static bool __meltdown_safe = true;
static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */
static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, 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,7 +976,17 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
{ /* sentinel */ } { /* sentinel */ }
}; };
char const *str = "command line option"; char const *str = "kpti command line option";
bool meltdown_safe;
meltdown_safe = is_midr_in_range_list(read_cpuid_id(), kpti_safe_list);
/* Defer to CPU feature registers */
if (has_cpuid_feature(entry, scope))
meltdown_safe = true;
if (!meltdown_safe)
__meltdown_safe = false;
/* /*
* For reasons that aren't entirely clear, enabling KPTI on Cavium * 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,6 +998,24 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
__kpti_forced = -1; __kpti_forced = -1;
} }
/* Useful for KASLR robustness */
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset() > 0) {
if (!__kpti_forced) {
str = "KASLR";
__kpti_forced = 1;
}
}
if (cpu_mitigations_off() && !__kpti_forced) {
str = "mitigations=off";
__kpti_forced = -1;
}
if (!IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) {
pr_info_once("kernel page table isolation disabled by kernel configuration\n");
return false;
}
/* Forced? */ /* Forced? */
if (__kpti_forced) { if (__kpti_forced) {
pr_info_once("kernel page table isolation forced %s by %s\n", 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,18 +1023,10 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
return __kpti_forced > 0; return __kpti_forced > 0;
} }
/* Useful for KASLR robustness */ return !meltdown_safe;
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
return kaslr_offset() > 0;
/* Don't force KPTI for CPUs that are not vulnerable */
if (is_midr_in_range_list(read_cpuid_id(), kpti_safe_list))
return false;
/* Defer to CPU feature registers */
return !has_cpuid_feature(entry, scope);
} }
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
static void static void
kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
{ {
...@@ -1035,6 +1056,12 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) ...@@ -1035,6 +1056,12 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
return; return;
} }
#else
static void
kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
{
}
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
static int __init parse_kpti(char *str) static int __init parse_kpti(char *str)
{ {
...@@ -1048,7 +1075,6 @@ static int __init parse_kpti(char *str) ...@@ -1048,7 +1075,6 @@ static int __init parse_kpti(char *str)
return 0; return 0;
} }
early_param("kpti", parse_kpti); early_param("kpti", parse_kpti);
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
#ifdef CONFIG_ARM64_HW_AFDBM #ifdef CONFIG_ARM64_HW_AFDBM
static inline void __cpu_enable_hw_dbm(void) static inline void __cpu_enable_hw_dbm(void)
...@@ -1315,7 +1341,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { ...@@ -1315,7 +1341,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.field_pos = ID_AA64PFR0_EL0_SHIFT, .field_pos = ID_AA64PFR0_EL0_SHIFT,
.min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT, .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT,
}, },
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
{ {
.desc = "Kernel page table isolation (KPTI)", .desc = "Kernel page table isolation (KPTI)",
.capability = ARM64_UNMAP_KERNEL_AT_EL0, .capability = ARM64_UNMAP_KERNEL_AT_EL0,
...@@ -1331,7 +1356,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { ...@@ -1331,7 +1356,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.matches = unmap_kernel_at_el0, .matches = unmap_kernel_at_el0,
.cpu_enable = kpti_install_ng_mappings, .cpu_enable = kpti_install_ng_mappings,
}, },
#endif
{ {
/* FP/SIMD is not implemented */ /* FP/SIMD is not implemented */
.capability = ARM64_HAS_NO_FPSIMD, .capability = ARM64_HAS_NO_FPSIMD,
...@@ -2156,3 +2180,15 @@ static int __init enable_mrs_emulation(void) ...@@ -2156,3 +2180,15 @@ static int __init enable_mrs_emulation(void)
} }
core_initcall(enable_mrs_emulation); core_initcall(enable_mrs_emulation);
ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr,
char *buf)
{
if (__meltdown_safe)
return sprintf(buf, "Not affected\n");
if (arm64_kernel_unmapped_at_el0())
return sprintf(buf, "Mitigation: PTI\n");
return sprintf(buf, "Vulnerable\n");
}
...@@ -57,7 +57,7 @@ void setup_barrier_nospec(void) ...@@ -57,7 +57,7 @@ void setup_barrier_nospec(void)
enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&
security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR);
if (!no_nospec) if (!no_nospec && !cpu_mitigations_off())
enable_barrier_nospec(enable); enable_barrier_nospec(enable);
} }
...@@ -116,7 +116,7 @@ static int __init handle_nospectre_v2(char *p) ...@@ -116,7 +116,7 @@ static int __init handle_nospectre_v2(char *p)
early_param("nospectre_v2", handle_nospectre_v2); early_param("nospectre_v2", handle_nospectre_v2);
void setup_spectre_v2(void) void setup_spectre_v2(void)
{ {
if (no_spectrev2) if (no_spectrev2 || cpu_mitigations_off())
do_btb_flush_fixups(); do_btb_flush_fixups();
else else
btb_flush_enabled = true; btb_flush_enabled = true;
...@@ -300,7 +300,7 @@ void setup_stf_barrier(void) ...@@ -300,7 +300,7 @@ void setup_stf_barrier(void)
stf_enabled_flush_types = type; stf_enabled_flush_types = type;
if (!no_stf_barrier) if (!no_stf_barrier && !cpu_mitigations_off())
stf_barrier_enable(enable); stf_barrier_enable(enable);
} }
......
...@@ -932,7 +932,7 @@ void setup_rfi_flush(enum l1d_flush_type types, bool enable) ...@@ -932,7 +932,7 @@ void setup_rfi_flush(enum l1d_flush_type types, bool enable)
enabled_flush_types = types; enabled_flush_types = types;
if (!no_rfi_flush) if (!no_rfi_flush && !cpu_mitigations_off())
rfi_flush_enable(enable); rfi_flush_enable(enable);
} }
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/cpu.h>
#include <asm/nospec-branch.h> #include <asm/nospec-branch.h>
static int __init nobp_setup_early(char *str) static int __init nobp_setup_early(char *str)
...@@ -58,7 +59,7 @@ early_param("nospectre_v2", nospectre_v2_setup_early); ...@@ -58,7 +59,7 @@ early_param("nospectre_v2", nospectre_v2_setup_early);
void __init nospec_auto_detect(void) void __init nospec_auto_detect(void)
{ {
if (test_facility(156)) { if (test_facility(156) || cpu_mitigations_off()) {
/* /*
* The machine supports etokens. * The machine supports etokens.
* Disable expolines and disable nobp. * Disable expolines and disable nobp.
......
...@@ -440,7 +440,8 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) ...@@ -440,7 +440,8 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
char arg[20]; char arg[20];
int ret, i; int ret, i;
if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) if (cmdline_find_option_bool(boot_command_line, "nospectre_v2") ||
cpu_mitigations_off())
return SPECTRE_V2_CMD_NONE; return SPECTRE_V2_CMD_NONE;
ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg)); 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,7 +673,8 @@ static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void)
char arg[20]; char arg[20];
int ret, i; int ret, i;
if (cmdline_find_option_bool(boot_command_line, "nospec_store_bypass_disable")) { if (cmdline_find_option_bool(boot_command_line, "nospec_store_bypass_disable") ||
cpu_mitigations_off()) {
return SPEC_STORE_BYPASS_CMD_NONE; return SPEC_STORE_BYPASS_CMD_NONE;
} else { } else {
ret = cmdline_find_option(boot_command_line, "spec_store_bypass_disable", ret = cmdline_find_option(boot_command_line, "spec_store_bypass_disable",
...@@ -1008,6 +1010,11 @@ static void __init l1tf_select_mitigation(void) ...@@ -1008,6 +1010,11 @@ static void __init l1tf_select_mitigation(void)
if (!boot_cpu_has_bug(X86_BUG_L1TF)) if (!boot_cpu_has_bug(X86_BUG_L1TF))
return; return;
if (cpu_mitigations_off())
l1tf_mitigation = L1TF_MITIGATION_OFF;
else if (cpu_mitigations_auto_nosmt())
l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOSMT;
override_cache_bits(&boot_cpu_data); override_cache_bits(&boot_cpu_data);
switch (l1tf_mitigation) { switch (l1tf_mitigation) {
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/cpu.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/hypervisor.h> #include <asm/hypervisor.h>
...@@ -115,7 +116,8 @@ void __init pti_check_boottime_disable(void) ...@@ -115,7 +116,8 @@ void __init pti_check_boottime_disable(void)
} }
} }
if (cmdline_find_option_bool(boot_command_line, "nopti")) { if (cmdline_find_option_bool(boot_command_line, "nopti") ||
cpu_mitigations_off()) {
pti_mode = PTI_FORCE_OFF; pti_mode = PTI_FORCE_OFF;
pti_print_if_insecure("disabled on command line."); pti_print_if_insecure("disabled on command line.");
return; return;
......
...@@ -187,4 +187,28 @@ static inline void cpu_smt_disable(bool force) { } ...@@ -187,4 +187,28 @@ static inline void cpu_smt_disable(bool force) { }
static inline void cpu_smt_check_topology(void) { } static inline void cpu_smt_check_topology(void) { }
#endif #endif
/*
* These are used for a global "mitigations=" cmdline option for toggling
* optional CPU mitigations.
*/
enum cpu_mitigations {
CPU_MITIGATIONS_OFF,
CPU_MITIGATIONS_AUTO,
CPU_MITIGATIONS_AUTO_NOSMT,
};
extern enum cpu_mitigations cpu_mitigations;
/* mitigations=off */
static inline bool cpu_mitigations_off(void)
{
return cpu_mitigations == CPU_MITIGATIONS_OFF;
}
/* mitigations=auto,nosmt */
static inline bool cpu_mitigations_auto_nosmt(void)
{
return cpu_mitigations == CPU_MITIGATIONS_AUTO_NOSMT;
}
#endif /* _LINUX_CPU_H_ */ #endif /* _LINUX_CPU_H_ */
...@@ -2304,3 +2304,18 @@ void __init boot_cpu_hotplug_init(void) ...@@ -2304,3 +2304,18 @@ void __init boot_cpu_hotplug_init(void)
#endif #endif
this_cpu_write(cpuhp_state.state, CPUHP_ONLINE); this_cpu_write(cpuhp_state.state, CPUHP_ONLINE);
} }
enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO;
static int __init mitigations_parse_cmdline(char *arg)
{
if (!strcmp(arg, "off"))
cpu_mitigations = CPU_MITIGATIONS_OFF;
else if (!strcmp(arg, "auto"))
cpu_mitigations = CPU_MITIGATIONS_AUTO;
else if (!strcmp(arg, "auto,nosmt"))
cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT;
return 0;
}
early_param("mitigations", mitigations_parse_cmdline);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment