diff options
author | David S. Miller <davem@davemloft.net> | 2018-01-17 00:00:25 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-17 00:10:42 -0500 |
commit | c02b3741eb99a1ec733e6134c53ba59e43e19e97 (patch) | |
tree | ff7dd96c32dec2abe530e7101378443dabcb8962 /arch/x86/kernel/cpu/bugs.c | |
parent | 7018d1b3f20fb4308ed9bc577160cb8ffb79b62a (diff) | |
parent | 8cbab92dff778e516064c13113ca15d4869ec883 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Overlapping changes all over.
The mini-qdisc bits were a little bit tricky, however.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/x86/kernel/cpu/bugs.c')
-rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index ba0b2424c9b0..e4dc26185aa7 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c | |||
@@ -10,6 +10,10 @@ | |||
10 | */ | 10 | */ |
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> | ||
14 | |||
15 | #include <asm/nospec-branch.h> | ||
16 | #include <asm/cmdline.h> | ||
13 | #include <asm/bugs.h> | 17 | #include <asm/bugs.h> |
14 | #include <asm/processor.h> | 18 | #include <asm/processor.h> |
15 | #include <asm/processor-flags.h> | 19 | #include <asm/processor-flags.h> |
@@ -20,6 +24,8 @@ | |||
20 | #include <asm/pgtable.h> | 24 | #include <asm/pgtable.h> |
21 | #include <asm/set_memory.h> | 25 | #include <asm/set_memory.h> |
22 | 26 | ||
27 | static void __init spectre_v2_select_mitigation(void); | ||
28 | |||
23 | void __init check_bugs(void) | 29 | void __init check_bugs(void) |
24 | { | 30 | { |
25 | identify_boot_cpu(); | 31 | identify_boot_cpu(); |
@@ -29,6 +35,9 @@ void __init check_bugs(void) | |||
29 | print_cpu_info(&boot_cpu_data); | 35 | print_cpu_info(&boot_cpu_data); |
30 | } | 36 | } |
31 | 37 | ||
38 | /* Select the proper spectre mitigation before patching alternatives */ | ||
39 | spectre_v2_select_mitigation(); | ||
40 | |||
32 | #ifdef CONFIG_X86_32 | 41 | #ifdef CONFIG_X86_32 |
33 | /* | 42 | /* |
34 | * Check whether we are able to run this kernel safely on SMP. | 43 | * Check whether we are able to run this kernel safely on SMP. |
@@ -60,3 +69,179 @@ void __init check_bugs(void) | |||
60 | set_memory_4k((unsigned long)__va(0), 1); | 69 | set_memory_4k((unsigned long)__va(0), 1); |
61 | #endif | 70 | #endif |
62 | } | 71 | } |
72 | |||
73 | /* The kernel command line selection */ | ||
74 | enum spectre_v2_mitigation_cmd { | ||
75 | SPECTRE_V2_CMD_NONE, | ||
76 | SPECTRE_V2_CMD_AUTO, | ||
77 | SPECTRE_V2_CMD_FORCE, | ||
78 | SPECTRE_V2_CMD_RETPOLINE, | ||
79 | SPECTRE_V2_CMD_RETPOLINE_GENERIC, | ||
80 | SPECTRE_V2_CMD_RETPOLINE_AMD, | ||
81 | }; | ||
82 | |||
83 | static const char *spectre_v2_strings[] = { | ||
84 | [SPECTRE_V2_NONE] = "Vulnerable", | ||
85 | [SPECTRE_V2_RETPOLINE_MINIMAL] = "Vulnerable: Minimal generic ASM retpoline", | ||
86 | [SPECTRE_V2_RETPOLINE_MINIMAL_AMD] = "Vulnerable: Minimal AMD ASM retpoline", | ||
87 | [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", | ||
88 | [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline", | ||
89 | }; | ||
90 | |||
91 | #undef pr_fmt | ||
92 | #define pr_fmt(fmt) "Spectre V2 mitigation: " fmt | ||
93 | |||
94 | static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; | ||
95 | |||
96 | static void __init spec2_print_if_insecure(const char *reason) | ||
97 | { | ||
98 | if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | ||
99 | pr_info("%s\n", reason); | ||
100 | } | ||
101 | |||
102 | static void __init spec2_print_if_secure(const char *reason) | ||
103 | { | ||
104 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | ||
105 | pr_info("%s\n", reason); | ||
106 | } | ||
107 | |||
108 | static inline bool retp_compiler(void) | ||
109 | { | ||
110 | return __is_defined(RETPOLINE); | ||
111 | } | ||
112 | |||
113 | static inline bool match_option(const char *arg, int arglen, const char *opt) | ||
114 | { | ||
115 | int len = strlen(opt); | ||
116 | |||
117 | return len == arglen && !strncmp(arg, opt, len); | ||
118 | } | ||
119 | |||
120 | static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) | ||
121 | { | ||
122 | char arg[20]; | ||
123 | int ret; | ||
124 | |||
125 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, | ||
126 | sizeof(arg)); | ||
127 | if (ret > 0) { | ||
128 | if (match_option(arg, ret, "off")) { | ||
129 | goto disable; | ||
130 | } else if (match_option(arg, ret, "on")) { | ||
131 | spec2_print_if_secure("force enabled on command line."); | ||
132 | return SPECTRE_V2_CMD_FORCE; | ||
133 | } else if (match_option(arg, ret, "retpoline")) { | ||
134 | spec2_print_if_insecure("retpoline selected on command line."); | ||
135 | return SPECTRE_V2_CMD_RETPOLINE; | ||
136 | } else if (match_option(arg, ret, "retpoline,amd")) { | ||
137 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { | ||
138 | pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n"); | ||
139 | return SPECTRE_V2_CMD_AUTO; | ||
140 | } | ||
141 | spec2_print_if_insecure("AMD retpoline selected on command line."); | ||
142 | return SPECTRE_V2_CMD_RETPOLINE_AMD; | ||
143 | } else if (match_option(arg, ret, "retpoline,generic")) { | ||
144 | spec2_print_if_insecure("generic retpoline selected on command line."); | ||
145 | return SPECTRE_V2_CMD_RETPOLINE_GENERIC; | ||
146 | } else if (match_option(arg, ret, "auto")) { | ||
147 | return SPECTRE_V2_CMD_AUTO; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2")) | ||
152 | return SPECTRE_V2_CMD_AUTO; | ||
153 | disable: | ||
154 | spec2_print_if_insecure("disabled on command line."); | ||
155 | return SPECTRE_V2_CMD_NONE; | ||
156 | } | ||
157 | |||
158 | static void __init spectre_v2_select_mitigation(void) | ||
159 | { | ||
160 | enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); | ||
161 | enum spectre_v2_mitigation mode = SPECTRE_V2_NONE; | ||
162 | |||
163 | /* | ||
164 | * If the CPU is not affected and the command line mode is NONE or AUTO | ||
165 | * then nothing to do. | ||
166 | */ | ||
167 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) && | ||
168 | (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO)) | ||
169 | return; | ||
170 | |||
171 | switch (cmd) { | ||
172 | case SPECTRE_V2_CMD_NONE: | ||
173 | return; | ||
174 | |||
175 | case SPECTRE_V2_CMD_FORCE: | ||
176 | /* FALLTRHU */ | ||
177 | case SPECTRE_V2_CMD_AUTO: | ||
178 | goto retpoline_auto; | ||
179 | |||
180 | case SPECTRE_V2_CMD_RETPOLINE_AMD: | ||
181 | if (IS_ENABLED(CONFIG_RETPOLINE)) | ||
182 | goto retpoline_amd; | ||
183 | break; | ||
184 | case SPECTRE_V2_CMD_RETPOLINE_GENERIC: | ||
185 | if (IS_ENABLED(CONFIG_RETPOLINE)) | ||
186 | goto retpoline_generic; | ||
187 | break; | ||
188 | case SPECTRE_V2_CMD_RETPOLINE: | ||
189 | if (IS_ENABLED(CONFIG_RETPOLINE)) | ||
190 | goto retpoline_auto; | ||
191 | break; | ||
192 | } | ||
193 | pr_err("kernel not compiled with retpoline; no mitigation available!"); | ||
194 | return; | ||
195 | |||
196 | retpoline_auto: | ||
197 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { | ||
198 | retpoline_amd: | ||
199 | if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) { | ||
200 | pr_err("LFENCE not serializing. Switching to generic retpoline\n"); | ||
201 | goto retpoline_generic; | ||
202 | } | ||
203 | mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD : | ||
204 | SPECTRE_V2_RETPOLINE_MINIMAL_AMD; | ||
205 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); | ||
206 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); | ||
207 | } else { | ||
208 | retpoline_generic: | ||
209 | mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC : | ||
210 | SPECTRE_V2_RETPOLINE_MINIMAL; | ||
211 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); | ||
212 | } | ||
213 | |||
214 | spectre_v2_enabled = mode; | ||
215 | pr_info("%s\n", spectre_v2_strings[mode]); | ||
216 | } | ||
217 | |||
218 | #undef pr_fmt | ||
219 | |||
220 | #ifdef CONFIG_SYSFS | ||
221 | ssize_t cpu_show_meltdown(struct device *dev, | ||
222 | struct device_attribute *attr, char *buf) | ||
223 | { | ||
224 | if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) | ||
225 | return sprintf(buf, "Not affected\n"); | ||
226 | if (boot_cpu_has(X86_FEATURE_PTI)) | ||
227 | return sprintf(buf, "Mitigation: PTI\n"); | ||
228 | return sprintf(buf, "Vulnerable\n"); | ||
229 | } | ||
230 | |||
231 | ssize_t cpu_show_spectre_v1(struct device *dev, | ||
232 | struct device_attribute *attr, char *buf) | ||
233 | { | ||
234 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) | ||
235 | return sprintf(buf, "Not affected\n"); | ||
236 | return sprintf(buf, "Vulnerable\n"); | ||
237 | } | ||
238 | |||
239 | ssize_t cpu_show_spectre_v2(struct device *dev, | ||
240 | struct device_attribute *attr, char *buf) | ||
241 | { | ||
242 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | ||
243 | return sprintf(buf, "Not affected\n"); | ||
244 | |||
245 | return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]); | ||
246 | } | ||
247 | #endif | ||