Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758546AbeAIOoI (ORCPT + 1 other); Tue, 9 Jan 2018 09:44:08 -0500 Received: from smtp-fw-6002.amazon.com ([52.95.49.90]:27054 "EHLO smtp-fw-6002.amazon.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758519AbeAIOoF (ORCPT ); Tue, 9 Jan 2018 09:44:05 -0500 X-IronPort-AV: E=Sophos;i="5.46,335,1511827200"; d="scan'208";a="326202234" From: David Woodhouse To: Andi Kleen Cc: Paul Turner , LKML , Linus Torvalds , Greg Kroah-Hartman , Tim Chen , Dave Hansen , tglx@linutronix.de, Kees Cook , Rik van Riel , Peter Zijlstra , Andy Lutomirski , Jiri Kosina , gnomes@lxorguk.ukuu.org.uk, x86@kernel.org Subject: [PATCH v7 03/11] x86/spectre: Add boot time option to select Spectre v2 mitigation Date: Tue, 9 Jan 2018 14:43:09 +0000 Message-Id: <1515508997-6154-4-git-send-email-dwmw@amazon.co.uk> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1515508997-6154-1-git-send-email-dwmw@amazon.co.uk> References: <1515508997-6154-1-git-send-email-dwmw@amazon.co.uk> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Return-Path: Add a spectre_v2= option to select the mitigation used for the indirect branch speculation vulnerability. Currently, the only option available is retpoline, in its various forms. This will be expanded to cover the new IBRS/IBPB microcode features. Signed-off-by: David Woodhouse Cc: gnomes@lxorguk.ukuu.org.uk Cc: Rik van Riel Cc: Peter Zijlstra Cc: Linus Torvalds Cc: Jiri Kosina Cc: Andy Lutomirski Cc: Dave Hansen Cc: Kees Cook Cc: Tim Chen Cc: Greg Kroah-Hartman Cc: Paul Turner --- Documentation/admin-guide/kernel-parameters.txt | 28 ++++++ arch/x86/include/asm/nospec-branch.h | 2 + arch/x86/kernel/cpu/bugs.c | 122 +++++++++++++++++++++++- arch/x86/kernel/cpu/common.c | 4 - arch/x86/kernel/setup.c | 3 + 5 files changed, 154 insertions(+), 5 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 9059917..8122b5f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2599,6 +2599,11 @@ nosmt [KNL,S390] Disable symmetric multithreading (SMT). Equivalent to smt=1. + nospectre_v2 [X86] 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. + noxsave [BUGS=X86] Disables x86 extended register state save and restore using xsave. The kernel will fallback to enabling legacy floating-point and sse state. @@ -3908,6 +3913,29 @@ sonypi.*= [HW] Sony Programmable I/O Control Device driver See Documentation/laptops/sonypi.txt + spectre_v2= [X86] Control mitigation of Spectre variant 2 + (indirect branch speculation) vulnerability. + + on - unconditionally enable + off - unconditionally disable + auto - kernel detects whether your CPU model is + vulnerable + + Selecting 'on' will, and 'auto' may, choose a + mitigation method at run time according to the + CPU, the available microcode, the setting of the + CONFIG_RETPOLINE configuration option, and the + compiler with which the kernel was built. + + Specific mitigations can also be selected manually: + + retpoline - replace indirect branches + retpoline,generic - google's original retpoline + retpoline,amd - AMD-specific minimal thunk + + Not specifying this option is equivalent to + spectre_v2=auto. + spia_io_base= [HW,MTD] spia_fio_base= spia_pedr= diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index da407df..a86e845 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -108,5 +108,7 @@ # define THUNK_TARGET(addr) [thunk_target] "rm" (addr) #endif +void spectre_v2_check_boottime_disable(void); + #endif /* __ASSEMBLY__ */ #endif /* __NOSPEC_BRANCH_H__ */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 76ad6cb..b957f77 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -11,6 +11,9 @@ #include #include #include + +#include +#include #include #include #include @@ -62,6 +65,111 @@ void __init check_bugs(void) #endif } +enum spectre_v2_mitigation { + SPECTRE_V2_NONE, + SPECTRE_V2_RETPOLINE_MINIMAL, + SPECTRE_V2_RETPOLINE_MINIMAL_AMD, + SPECTRE_V2_RETPOLINE_GENERIC, + SPECTRE_V2_RETPOLINE_AMD, +}; + +#undef pr_fmt +#define pr_fmt(fmt) "Spectre V2 mitigation: " fmt + +static int spectre_v2_enabled = SPECTRE_V2_NONE; + +static void __init spec2_print_if_insecure(const char *reason) +{ + if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + pr_info("%s\n", reason); +} + +static void __init spec2_print_if_secure(const char *reason) +{ + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + pr_info("%s\n", reason); +} + +static inline bool retp_compiler(void) +{ +#ifdef RETPOLINE + return true; +#else + return false; +#endif +} + +static inline bool match_option(const char *arg, int arglen, const char *opt) +{ + int len = strlen(opt); + + return len == arglen && !strncmp(arg, opt, len); +} + +void __init spectre_v2_check_boottime_disable(void) +{ + char arg[20]; + int ret; + + ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, + sizeof(arg)); + if (ret > 0) { + if (match_option(arg, ret, "off")) { + spec2_print_if_insecure("disabled on command line."); + goto disable; + } else if (match_option(arg, ret, "on")) { + spec2_print_if_secure("force enabled on command line."); + goto force; + } else if (match_option(arg, ret, "retpoline")) { + spec2_print_if_insecure("retpoline selected on command line."); + goto retpoline; + } else if (match_option(arg, ret, "retpoline,amd")) { + spec2_print_if_insecure("AMD retpoline selected on command line."); + goto retpoline_amd; + } else if (match_option(arg, ret, "retpoline,generic")) { + spec2_print_if_insecure("generic retpoline selected on command line."); + goto retpoline_generic; + } else if (match_option(arg, ret, "auto")) { + goto autosel; + } + } + + if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) { + spec2_print_if_insecure("disabled on command line."); + goto disable; + } + +autosel: + if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) + goto disable; + +force: +#ifdef CONFIG_RETPOLINE +retpoline: + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { + retpoline_amd: + spectre_v2_enabled = retp_compiler() ? + SPECTRE_V2_RETPOLINE_AMD : SPECTRE_V2_RETPOLINE_MINIMAL_AMD; + setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); + } else { + retpoline_generic: + spectre_v2_enabled = retp_compiler() ? + SPECTRE_V2_RETPOLINE_GENERIC : SPECTRE_V2_RETPOLINE_MINIMAL; + } + setup_force_cpu_cap(X86_FEATURE_RETPOLINE); + return; +#else +retpoline: +retpoline_amd: +retpoline_generic: + pr_err("kernel not compiled with retpoline; no mitigation available!"); +#endif +disable: + setup_clear_cpu_cap(X86_FEATURE_RETPOLINE); + setup_clear_cpu_cap(X86_FEATURE_RETPOLINE_AMD); + return; +} + #ifdef CONFIG_SYSFS ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) @@ -86,6 +194,18 @@ ssize_t cpu_show_spectre_v2(struct device *dev, { if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) return sprintf(buf, "Not affected\n"); - return sprintf(buf, "Vulnerable\n"); + + switch (spectre_v2_enabled) { + case SPECTRE_V2_RETPOLINE_MINIMAL: + return sprintf(buf, "Mitigation: Minimal generic ASM retpoline\n"); + case SPECTRE_V2_RETPOLINE_MINIMAL_AMD: + return sprintf(buf, "Mitigation: Minimal AMD ASM retpoline\n"); + case SPECTRE_V2_RETPOLINE_GENERIC: + return sprintf(buf, "Mitigation: Full generic retpoline\n"); + case SPECTRE_V2_RETPOLINE_AMD: + return sprintf(buf, "Mitigation: Full AMD retpoline\n"); + default: + return sprintf(buf, "Vulnerable\n"); + } } #endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 7a671d1..372ba3f 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -905,10 +905,6 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) setup_force_cpu_bug(X86_BUG_SPECTRE_V1); setup_force_cpu_bug(X86_BUG_SPECTRE_V2); -#ifdef CONFIG_RETPOLINE - setup_force_cpu_cap(X86_FEATURE_RETPOLINE); -#endif - fpu__init_system(c); #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 0957dd7..9fb4f9d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -117,6 +117,7 @@ #include #include #include +#include /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB @@ -1321,6 +1322,8 @@ void __init setup_arch(char **cmdline_p) register_refined_jiffies(CLOCK_TICK_RATE); + spectre_v2_check_boottime_disable(); + #ifdef CONFIG_EFI if (efi_enabled(EFI_BOOT)) efi_apply_memmap_quirks(); -- 2.7.4