x86/bugs: Enable STIBP for JMP2RET
authorKim Phillips <kim.phillips@amd.com>
Tue, 14 Jun 2022 21:15:51 +0000 (23:15 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Jul 2022 10:54:02 +0000 (12:54 +0200)
commit e8ec1b6e08a2102d8755ccb06fa26d540f26a2fa upstream.

For untrained return thunks to be fully effective, STIBP must be enabled
or SMT disabled.

Co-developed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Kim Phillips <kim.phillips@amd.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.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/kernel/cpu/bugs.c

index 961843a..9984205 100644 (file)
                        Speculative Code Execution with Return Instructions)
                        vulnerability.
 
-                       off         - unconditionally disable
-                       auto        - automatically select a migitation
-                       unret       - force enable untrained return thunks,
-                                     only effective on AMD Zen {1,2}
-                                     based systems.
+                       off          - no mitigation
+                       auto         - automatically select a migitation
+                       auto,nosmt   - automatically select a mitigation,
+                                      disabling SMT if necessary for
+                                      the full mitigation (only on Zen1
+                                      and older without STIBP).
+                       unret        - force enable untrained return thunks,
+                                      only effective on AMD f15h-f17h
+                                      based systems.
+                       unret,nosmt  - like unret, will disable SMT when STIBP
+                                      is not available.
 
                        Selecting 'auto' will choose a mitigation method at run
                        time according to the CPU.
index 3e01a88..27bb40a 100644 (file)
@@ -776,19 +776,34 @@ static enum retbleed_mitigation retbleed_mitigation __ro_after_init =
 static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init =
        RETBLEED_CMD_AUTO;
 
+static int __ro_after_init retbleed_nosmt = false;
+
 static int __init retbleed_parse_cmdline(char *str)
 {
        if (!str)
                return -EINVAL;
 
-       if (!strcmp(str, "off"))
-               retbleed_cmd = RETBLEED_CMD_OFF;
-       else if (!strcmp(str, "auto"))
-               retbleed_cmd = RETBLEED_CMD_AUTO;
-       else if (!strcmp(str, "unret"))
-               retbleed_cmd = RETBLEED_CMD_UNRET;
-       else
-               pr_err("Unknown retbleed option (%s). Defaulting to 'auto'\n", str);
+       while (str) {
+               char *next = strchr(str, ',');
+               if (next) {
+                       *next = 0;
+                       next++;
+               }
+
+               if (!strcmp(str, "off")) {
+                       retbleed_cmd = RETBLEED_CMD_OFF;
+               } else if (!strcmp(str, "auto")) {
+                       retbleed_cmd = RETBLEED_CMD_AUTO;
+               } else if (!strcmp(str, "unret")) {
+                       retbleed_cmd = RETBLEED_CMD_UNRET;
+               } else if (!strcmp(str, "nosmt")) {
+                       retbleed_nosmt = true;
+               } else {
+                       pr_err("Ignoring unknown retbleed option (%s).", str);
+               }
+
+               str = next;
+       }
 
        return 0;
 }
@@ -834,6 +849,10 @@ static void __init retbleed_select_mitigation(void)
                setup_force_cpu_cap(X86_FEATURE_RETHUNK);
                setup_force_cpu_cap(X86_FEATURE_UNRET);
 
+               if (!boot_cpu_has(X86_FEATURE_STIBP) &&
+                   (retbleed_nosmt || cpu_mitigations_auto_nosmt()))
+                       cpu_smt_disable(false);
+
                if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
                    boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
                        pr_err(RETBLEED_UNTRAIN_MSG);
@@ -1080,6 +1099,13 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
                mode = SPECTRE_V2_USER_STRICT_PREFERRED;
 
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+               if (mode != SPECTRE_V2_USER_STRICT &&
+                   mode != SPECTRE_V2_USER_STRICT_PREFERRED)
+                       pr_info("Selecting STIBP always-on mode to complement retbleed mitigation'\n");
+               mode = SPECTRE_V2_USER_STRICT_PREFERRED;
+       }
+
        spectre_v2_user_stibp = mode;
 
 set_mode:
@@ -2090,10 +2116,18 @@ static ssize_t srbds_show_state(char *buf)
 
 static ssize_t retbleed_show_state(char *buf)
 {
-       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET &&
-           (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
-            boot_cpu_data.x86_vendor != X86_VENDOR_HYGON))
-               return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n");
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+           if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+               boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                   return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n");
+
+           return sprintf(buf, "%s; SMT %s\n",
+                          retbleed_strings[retbleed_mitigation],
+                          !sched_smt_active() ? "disabled" :
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ?
+                          "enabled with STIBP protection" : "vulnerable");
+       }
 
        return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]);
 }