]> git.baikalelectronics.ru Git - kernel.git/commitdiff
x86/speculation: Add spectre_v2=ibrs option to support Kernel IBRS
authorPawan Gupta <pawan.kumar.gupta@linux.intel.com>
Mon, 3 Oct 2022 13:10:15 +0000 (10:10 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Oct 2022 07:16:55 +0000 (09:16 +0200)
commit 2a12d4fbd910a480ab956691b1fe84db1bc469c9 upstream.

Extend spectre_v2= boot option with Kernel IBRS.

  [jpoimboe: no STIBP with IBRS]

Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Borislav Petkov <bp@suse.de>
Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/admin-guide/kernel-parameters.txt
arch/x86/include/asm/nospec-branch.h
arch/x86/kernel/cpu/bugs.c

index e0fb1e5e5113207cd1d8997b943706d22f41c927..8f71a17ad54420c22fc51fd7cad066e8910f92ae 100644 (file)
                        eibrs             - enhanced IBRS
                        eibrs,retpoline   - enhanced IBRS + Retpolines
                        eibrs,lfence      - enhanced IBRS + LFENCE
+                       ibrs              - use IBRS to protect kernel
 
                        Not specifying this option is equivalent to
                        spectre_v2=auto.
index 2e7da90a5f7313c365e2e52e4c322de4494c2536..2de7c08fa36ee931a4b9ede51d6ff26fab9aa6d2 100644 (file)
@@ -234,6 +234,7 @@ enum spectre_v2_mitigation {
        SPECTRE_V2_EIBRS,
        SPECTRE_V2_EIBRS_RETPOLINE,
        SPECTRE_V2_EIBRS_LFENCE,
+       SPECTRE_V2_IBRS,
 };
 
 /* The indirect branch speculation control variants */
index 549d603b5f6e3331de1f2cebf52383783312bdbc..497562e78876599b9b2559ad182deb7203a640c8 100644 (file)
@@ -877,6 +877,7 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_EIBRS,
        SPECTRE_V2_CMD_EIBRS_RETPOLINE,
        SPECTRE_V2_CMD_EIBRS_LFENCE,
+       SPECTRE_V2_CMD_IBRS,
 };
 
 enum spectre_v2_user_cmd {
@@ -949,11 +950,12 @@ spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
        return SPECTRE_V2_USER_CMD_AUTO;
 }
 
-static inline bool spectre_v2_in_eibrs_mode(enum spectre_v2_mitigation mode)
+static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
 {
-       return (mode == SPECTRE_V2_EIBRS ||
-               mode == SPECTRE_V2_EIBRS_RETPOLINE ||
-               mode == SPECTRE_V2_EIBRS_LFENCE);
+       return mode == SPECTRE_V2_IBRS ||
+              mode == SPECTRE_V2_EIBRS ||
+              mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+              mode == SPECTRE_V2_EIBRS_LFENCE;
 }
 
 static void __init
@@ -1018,12 +1020,12 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
        }
 
        /*
-        * If no STIBP, enhanced IBRS is enabled or SMT impossible, STIBP is not
-        * required.
+        * If no STIBP, IBRS or enhanced IBRS is enabled, or SMT impossible,
+        * STIBP is not required.
         */
        if (!boot_cpu_has(X86_FEATURE_STIBP) ||
            !smt_possible ||
-           spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+           spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return;
 
        /*
@@ -1048,6 +1050,7 @@ static const char * const spectre_v2_strings[] = {
        [SPECTRE_V2_EIBRS]                      = "Mitigation: Enhanced IBRS",
        [SPECTRE_V2_EIBRS_LFENCE]               = "Mitigation: Enhanced IBRS + LFENCE",
        [SPECTRE_V2_EIBRS_RETPOLINE]            = "Mitigation: Enhanced IBRS + Retpolines",
+       [SPECTRE_V2_IBRS]                       = "Mitigation: IBRS",
 };
 
 static const struct {
@@ -1065,6 +1068,7 @@ static const struct {
        { "eibrs,lfence",       SPECTRE_V2_CMD_EIBRS_LFENCE,      false },
        { "eibrs,retpoline",    SPECTRE_V2_CMD_EIBRS_RETPOLINE,   false },
        { "auto",               SPECTRE_V2_CMD_AUTO,              false },
+       { "ibrs",               SPECTRE_V2_CMD_IBRS,              false },
 };
 
 static void __init spec_v2_print_cond(const char *reason, bool secure)
@@ -1127,6 +1131,24 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
                return SPECTRE_V2_CMD_AUTO;
        }
 
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+               pr_err("%s selected but not Intel CPU. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
+               pr_err("%s selected but CPU doesn't have IBRS. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_has(X86_FEATURE_XENPV)) {
+               pr_err("%s selected but running as XenPV guest. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
        spec_v2_print_cond(mitigation_options[i].option,
                           mitigation_options[i].secure);
        return cmd;
@@ -1166,6 +1188,14 @@ static void __init spectre_v2_select_mitigation(void)
                        break;
                }
 
+               if (boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+                   retbleed_cmd != RETBLEED_CMD_OFF &&
+                   boot_cpu_has(X86_FEATURE_IBRS) &&
+                   boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+                       mode = SPECTRE_V2_IBRS;
+                       break;
+               }
+
                mode = spectre_v2_select_retpoline();
                break;
 
@@ -1182,6 +1212,10 @@ static void __init spectre_v2_select_mitigation(void)
                mode = spectre_v2_select_retpoline();
                break;
 
+       case SPECTRE_V2_CMD_IBRS:
+               mode = SPECTRE_V2_IBRS;
+               break;
+
        case SPECTRE_V2_CMD_EIBRS:
                mode = SPECTRE_V2_EIBRS;
                break;
@@ -1198,7 +1232,7 @@ static void __init spectre_v2_select_mitigation(void)
        if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
                pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
 
-       if (spectre_v2_in_eibrs_mode(mode)) {
+       if (spectre_v2_in_ibrs_mode(mode)) {
                /* Force it so VMEXIT will restore correctly */
                x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
                write_spec_ctrl_current(x86_spec_ctrl_base, true);
@@ -1209,6 +1243,10 @@ static void __init spectre_v2_select_mitigation(void)
        case SPECTRE_V2_EIBRS:
                break;
 
+       case SPECTRE_V2_IBRS:
+               setup_force_cpu_cap(X86_FEATURE_KERNEL_IBRS);
+               break;
+
        case SPECTRE_V2_LFENCE:
        case SPECTRE_V2_EIBRS_LFENCE:
                setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
@@ -1235,17 +1273,17 @@ static void __init spectre_v2_select_mitigation(void)
        pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
 
        /*
-        * Retpoline means the kernel is safe because it has no indirect
-        * branches. Enhanced IBRS protects firmware too, so, enable restricted
-        * speculation around firmware calls only when Enhanced IBRS isn't
-        * supported.
+        * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
+        * and Enhanced IBRS protect firmware too, so enable IBRS around
+        * firmware calls only when IBRS / Enhanced IBRS aren't otherwise
+        * enabled.
         *
         * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
         * the user might select retpoline on the kernel command line and if
         * the CPU supports Enhanced IBRS, kernel might un-intentionally not
         * enable IBRS around firmware calls.
         */
-       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_eibrs_mode(mode)) {
+       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_ibrs_mode(mode)) {
                setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
                pr_info("Enabling Restricted Speculation for firmware calls\n");
        }
@@ -1951,7 +1989,7 @@ static ssize_t mmio_stale_data_show_state(char *buf)
 
 static char *stibp_state(void)
 {
-       if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+       if (spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return "";
 
        switch (spectre_v2_user_stibp) {