diff options
Diffstat (limited to 'arch/x86/kernel/cpu/bugs.c')
-rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 134 |
1 files changed, 98 insertions, 36 deletions
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 390b3dc3d438..71949bf2de5a 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/utsname.h> | 12 | #include <linux/utsname.h> |
13 | #include <linux/cpu.h> | 13 | #include <linux/cpu.h> |
14 | #include <linux/module.h> | ||
14 | 15 | ||
15 | #include <asm/nospec-branch.h> | 16 | #include <asm/nospec-branch.h> |
16 | #include <asm/cmdline.h> | 17 | #include <asm/cmdline.h> |
@@ -90,20 +91,41 @@ static const char *spectre_v2_strings[] = { | |||
90 | }; | 91 | }; |
91 | 92 | ||
92 | #undef pr_fmt | 93 | #undef pr_fmt |
93 | #define pr_fmt(fmt) "Spectre V2 mitigation: " fmt | 94 | #define pr_fmt(fmt) "Spectre V2 : " fmt |
94 | 95 | ||
95 | static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; | 96 | static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; |
96 | 97 | ||
98 | #ifdef RETPOLINE | ||
99 | static bool spectre_v2_bad_module; | ||
100 | |||
101 | bool retpoline_module_ok(bool has_retpoline) | ||
102 | { | ||
103 | if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline) | ||
104 | return true; | ||
105 | |||
106 | pr_err("System may be vulnerable to spectre v2\n"); | ||
107 | spectre_v2_bad_module = true; | ||
108 | return false; | ||
109 | } | ||
110 | |||
111 | static inline const char *spectre_v2_module_string(void) | ||
112 | { | ||
113 | return spectre_v2_bad_module ? " - vulnerable module loaded" : ""; | ||
114 | } | ||
115 | #else | ||
116 | static inline const char *spectre_v2_module_string(void) { return ""; } | ||
117 | #endif | ||
118 | |||
97 | static void __init spec2_print_if_insecure(const char *reason) | 119 | static void __init spec2_print_if_insecure(const char *reason) |
98 | { | 120 | { |
99 | if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | 121 | if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) |
100 | pr_info("%s\n", reason); | 122 | pr_info("%s selected on command line.\n", reason); |
101 | } | 123 | } |
102 | 124 | ||
103 | static void __init spec2_print_if_secure(const char *reason) | 125 | static void __init spec2_print_if_secure(const char *reason) |
104 | { | 126 | { |
105 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | 127 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) |
106 | pr_info("%s\n", reason); | 128 | pr_info("%s selected on command line.\n", reason); |
107 | } | 129 | } |
108 | 130 | ||
109 | static inline bool retp_compiler(void) | 131 | static inline bool retp_compiler(void) |
@@ -118,42 +140,68 @@ static inline bool match_option(const char *arg, int arglen, const char *opt) | |||
118 | return len == arglen && !strncmp(arg, opt, len); | 140 | return len == arglen && !strncmp(arg, opt, len); |
119 | } | 141 | } |
120 | 142 | ||
143 | static const struct { | ||
144 | const char *option; | ||
145 | enum spectre_v2_mitigation_cmd cmd; | ||
146 | bool secure; | ||
147 | } mitigation_options[] = { | ||
148 | { "off", SPECTRE_V2_CMD_NONE, false }, | ||
149 | { "on", SPECTRE_V2_CMD_FORCE, true }, | ||
150 | { "retpoline", SPECTRE_V2_CMD_RETPOLINE, false }, | ||
151 | { "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_AMD, false }, | ||
152 | { "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false }, | ||
153 | { "auto", SPECTRE_V2_CMD_AUTO, false }, | ||
154 | }; | ||
155 | |||
121 | static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) | 156 | static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) |
122 | { | 157 | { |
123 | char arg[20]; | 158 | char arg[20]; |
124 | int ret; | 159 | int ret, i; |
125 | 160 | enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO; | |
126 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, | 161 | |
127 | sizeof(arg)); | 162 | if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) |
128 | if (ret > 0) { | 163 | return SPECTRE_V2_CMD_NONE; |
129 | if (match_option(arg, ret, "off")) { | 164 | else { |
130 | goto disable; | 165 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, |
131 | } else if (match_option(arg, ret, "on")) { | 166 | sizeof(arg)); |
132 | spec2_print_if_secure("force enabled on command line."); | 167 | if (ret < 0) |
133 | return SPECTRE_V2_CMD_FORCE; | 168 | return SPECTRE_V2_CMD_AUTO; |
134 | } else if (match_option(arg, ret, "retpoline")) { | 169 | |
135 | spec2_print_if_insecure("retpoline selected on command line."); | 170 | for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) { |
136 | return SPECTRE_V2_CMD_RETPOLINE; | 171 | if (!match_option(arg, ret, mitigation_options[i].option)) |
137 | } else if (match_option(arg, ret, "retpoline,amd")) { | 172 | continue; |
138 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { | 173 | cmd = mitigation_options[i].cmd; |
139 | pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n"); | 174 | break; |
140 | return SPECTRE_V2_CMD_AUTO; | 175 | } |
141 | } | 176 | |
142 | spec2_print_if_insecure("AMD retpoline selected on command line."); | 177 | if (i >= ARRAY_SIZE(mitigation_options)) { |
143 | return SPECTRE_V2_CMD_RETPOLINE_AMD; | 178 | pr_err("unknown option (%s). Switching to AUTO select\n", |
144 | } else if (match_option(arg, ret, "retpoline,generic")) { | 179 | mitigation_options[i].option); |
145 | spec2_print_if_insecure("generic retpoline selected on command line."); | ||
146 | return SPECTRE_V2_CMD_RETPOLINE_GENERIC; | ||
147 | } else if (match_option(arg, ret, "auto")) { | ||
148 | return SPECTRE_V2_CMD_AUTO; | 180 | return SPECTRE_V2_CMD_AUTO; |
149 | } | 181 | } |
150 | } | 182 | } |
151 | 183 | ||
152 | if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2")) | 184 | if ((cmd == SPECTRE_V2_CMD_RETPOLINE || |
185 | cmd == SPECTRE_V2_CMD_RETPOLINE_AMD || | ||
186 | cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) && | ||
187 | !IS_ENABLED(CONFIG_RETPOLINE)) { | ||
188 | pr_err("%s selected but not compiled in. Switching to AUTO select\n", | ||
189 | mitigation_options[i].option); | ||
153 | return SPECTRE_V2_CMD_AUTO; | 190 | return SPECTRE_V2_CMD_AUTO; |
154 | disable: | 191 | } |
155 | spec2_print_if_insecure("disabled on command line."); | 192 | |
156 | return SPECTRE_V2_CMD_NONE; | 193 | if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD && |
194 | boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { | ||
195 | pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n"); | ||
196 | return SPECTRE_V2_CMD_AUTO; | ||
197 | } | ||
198 | |||
199 | if (mitigation_options[i].secure) | ||
200 | spec2_print_if_secure(mitigation_options[i].option); | ||
201 | else | ||
202 | spec2_print_if_insecure(mitigation_options[i].option); | ||
203 | |||
204 | return cmd; | ||
157 | } | 205 | } |
158 | 206 | ||
159 | /* Check for Skylake-like CPUs (for RSB handling) */ | 207 | /* Check for Skylake-like CPUs (for RSB handling) */ |
@@ -191,10 +239,10 @@ static void __init spectre_v2_select_mitigation(void) | |||
191 | return; | 239 | return; |
192 | 240 | ||
193 | case SPECTRE_V2_CMD_FORCE: | 241 | case SPECTRE_V2_CMD_FORCE: |
194 | /* FALLTRHU */ | ||
195 | case SPECTRE_V2_CMD_AUTO: | 242 | case SPECTRE_V2_CMD_AUTO: |
196 | goto retpoline_auto; | 243 | if (IS_ENABLED(CONFIG_RETPOLINE)) |
197 | 244 | goto retpoline_auto; | |
245 | break; | ||
198 | case SPECTRE_V2_CMD_RETPOLINE_AMD: | 246 | case SPECTRE_V2_CMD_RETPOLINE_AMD: |
199 | if (IS_ENABLED(CONFIG_RETPOLINE)) | 247 | if (IS_ENABLED(CONFIG_RETPOLINE)) |
200 | goto retpoline_amd; | 248 | goto retpoline_amd; |
@@ -249,6 +297,12 @@ retpoline_auto: | |||
249 | setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); | 297 | setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); |
250 | pr_info("Filling RSB on context switch\n"); | 298 | pr_info("Filling RSB on context switch\n"); |
251 | } | 299 | } |
300 | |||
301 | /* Initialize Indirect Branch Prediction Barrier if supported */ | ||
302 | if (boot_cpu_has(X86_FEATURE_IBPB)) { | ||
303 | setup_force_cpu_cap(X86_FEATURE_USE_IBPB); | ||
304 | pr_info("Enabling Indirect Branch Prediction Barrier\n"); | ||
305 | } | ||
252 | } | 306 | } |
253 | 307 | ||
254 | #undef pr_fmt | 308 | #undef pr_fmt |
@@ -269,7 +323,7 @@ ssize_t cpu_show_spectre_v1(struct device *dev, | |||
269 | { | 323 | { |
270 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) | 324 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) |
271 | return sprintf(buf, "Not affected\n"); | 325 | return sprintf(buf, "Not affected\n"); |
272 | return sprintf(buf, "Vulnerable\n"); | 326 | return sprintf(buf, "Mitigation: __user pointer sanitization\n"); |
273 | } | 327 | } |
274 | 328 | ||
275 | ssize_t cpu_show_spectre_v2(struct device *dev, | 329 | ssize_t cpu_show_spectre_v2(struct device *dev, |
@@ -278,6 +332,14 @@ ssize_t cpu_show_spectre_v2(struct device *dev, | |||
278 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | 332 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) |
279 | return sprintf(buf, "Not affected\n"); | 333 | return sprintf(buf, "Not affected\n"); |
280 | 334 | ||
281 | return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]); | 335 | return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], |
336 | boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "", | ||
337 | spectre_v2_module_string()); | ||
282 | } | 338 | } |
283 | #endif | 339 | #endif |
340 | |||
341 | void __ibp_barrier(void) | ||
342 | { | ||
343 | __wrmsr(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, 0); | ||
344 | } | ||
345 | EXPORT_SYMBOL_GPL(__ibp_barrier); | ||