For untrained return thunks to be fully effective, STIBP must be enabled or SMT disabled.
Unified · Split
| @@ -5201,11 +5201,17 @@ · 5200 unmodified lines | |||
| 5201 | Speculative Code Execution with Return Instructions) | 5201 | Speculative Code Execution with Return Instructions) |
| 5202 | vulnerability. | 5202 | vulnerability. |
| 5203 | 5203 | ||
| 5204 | off - unconditionally disable | 5204 | off - no mitigation |
| 5205 | auto - automatically select a migitation | 5205 | auto - automatically select a migitation |
| 5206 | unret - force enable untrained return thunks, | 5206 | auto,nosmt - automatically select a mitigation, |
| 5207 | only effective on AMD Zen {1,2} | 5207 | disabling SMT if necessary for |
| 5208 | based systems. | 5208 | the full mitigation (only on Zen1 |
| 5209 | and older without STIBP). | ||
| 5210 | unret - force enable untrained return thunks, | ||
| 5211 | only effective on AMD f15h-f17h | ||
| 5212 | based systems. | ||
| 5213 | unret,nosmt - like unret, will disable SMT when STIBP | ||
| 5214 | is not available. | ||
| 5209 | 5215 | ||
| 5210 | Selecting 'auto' will choose a mitigation method at run | 5216 | Selecting 'auto' will choose a mitigation method at run |
| 5211 | time according to the CPU. | 5217 | time according to the CPU. |
| @@ -783,19 +783,34 @@ static enum retbleed_mitigation retbleed_mitigation __ro_after_init = · 782 unmodified lines | |||
| 783 | static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init = | 783 | static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init = |
| 784 | RETBLEED_CMD_AUTO; | 784 | RETBLEED_CMD_AUTO; |
| 785 | 785 | ||
| 786 | static int __ro_after_init retbleed_nosmt = false; | ||
| 787 | |||
| 786 | static int __init retbleed_parse_cmdline(char *str) | 788 | static int __init retbleed_parse_cmdline(char *str) |
| 787 | { | 789 | { |
| 788 | if (!str) | 790 | if (!str) |
| 789 | return -EINVAL; | 791 | return -EINVAL; |
| 790 | 792 | ||
| 791 | if (!strcmp(str, "off")) | 793 | while (str) { |
| 792 | retbleed_cmd = RETBLEED_CMD_OFF; | 794 | char *next = strchr(str, ','); |
| 793 | else if (!strcmp(str, "auto")) | 795 | if (next) { |
| 794 | retbleed_cmd = RETBLEED_CMD_AUTO; | 796 | *next = 0; |
| 795 | else if (!strcmp(str, "unret")) | 797 | next++; |
| 796 | retbleed_cmd = RETBLEED_CMD_UNRET; | 798 | } |
| 797 | else | 799 | |
| 798 | pr_err("Unknown retbleed option (%s). Defaulting to 'auto'\n", str); | 800 | if (!strcmp(str, "off")) { |
| 801 | retbleed_cmd = RETBLEED_CMD_OFF; | ||
| 802 | } else if (!strcmp(str, "auto")) { | ||
| 803 | retbleed_cmd = RETBLEED_CMD_AUTO; | ||
| 804 | } else if (!strcmp(str, "unret")) { | ||
| 805 | retbleed_cmd = RETBLEED_CMD_UNRET; | ||
| 806 | } else if (!strcmp(str, "nosmt")) { | ||
| 807 | retbleed_nosmt = true; | ||
| 808 | } else { | ||
| 809 | pr_err("Ignoring unknown retbleed option (%s).", str); | ||
| 810 | } | ||
| 811 | |||
| 812 | str = next; | ||
| 813 | } | ||
| 799 | 814 | ||
| 800 | return 0; | 815 | return 0; |
| 801 | } | 816 | } |
| @@ -841,6 +856,10 @@ static void __init retbleed_select_mitigation(void) · 39 unmodified lines | |||
| 841 | setup_force_cpu_cap(X86_FEATURE_RETHUNK); | 856 | setup_force_cpu_cap(X86_FEATURE_RETHUNK); |
| 842 | setup_force_cpu_cap(X86_FEATURE_UNRET); | 857 | setup_force_cpu_cap(X86_FEATURE_UNRET); |
| 843 | 858 | ||
| 859 | if (!boot_cpu_has(X86_FEATURE_STIBP) && | ||
| 860 | (retbleed_nosmt || cpu_mitigations_auto_nosmt())) | ||
| 861 | cpu_smt_disable(false); | ||
| 862 | |||
| 844 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && | 863 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && |
| 845 | boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) | 864 | boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) |
| 846 | pr_err(RETBLEED_UNTRAIN_MSG); | 865 | pr_err(RETBLEED_UNTRAIN_MSG); |
| @@ -1087,6 +1106,13 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd) · 240 unmodified lines | |||
| 1087 | boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON)) | 1106 | boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON)) |
| 1088 | mode = SPECTRE_V2_USER_STRICT_PREFERRED; | 1107 | mode = SPECTRE_V2_USER_STRICT_PREFERRED; |
| 1089 | 1108 | ||
| 1109 | if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) { | ||
| 1110 | if (mode != SPECTRE_V2_USER_STRICT && | ||
| 1111 | mode != SPECTRE_V2_USER_STRICT_PREFERRED) | ||
| 1112 | pr_info("Selecting STIBP always-on mode to complement retbleed mitigation'\n"); | ||
| 1113 | mode = SPECTRE_V2_USER_STRICT_PREFERRED; | ||
| 1114 | } | ||
| 1115 | |||
| 1090 | spectre_v2_user_stibp = mode; | 1116 | spectre_v2_user_stibp = mode; |
| 1091 | 1117 | ||
| 1092 | set_mode: | 1118 | set_mode: |
| @@ -2097,10 +2123,18 @@ static ssize_t srbds_show_state(char *buf) · 1004 unmodified lines | |||
| 2097 | 2123 | ||
| 2098 | static ssize_t retbleed_show_state(char *buf) | 2124 | static ssize_t retbleed_show_state(char *buf) |
| 2099 | { | 2125 | { |
| 2100 | if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET && | 2126 | if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) { |
| 2101 | (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && | 2127 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && |
| 2102 | boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)) | 2128 | boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) |
| 2103 | return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n"); | 2129 | return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n"); |
| 2130 | |||
| 2131 | return sprintf(buf, "%s; SMT %s\n", | ||
| 2132 | retbleed_strings[retbleed_mitigation], | ||
| 2133 | !sched_smt_active() ? "disabled" : | ||
| 2134 | spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT || | ||
| 2135 | spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ? | ||
| 2136 | "enabled with STIBP protection" : "vulnerable"); | ||
| 2137 | } | ||
| 2104 | 2138 | ||
| 2105 | return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]); | 2139 | return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]); |
| 2106 | } | 2140 | } |