1 |
From foo@baz Tue Mar 8 08:32:37 PM CET 2022 |
2 |
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> |
3 |
Date: Fri, 11 Feb 2022 16:45:54 +0000 |
4 |
Subject: ARM: report Spectre v2 status through sysfs |
5 |
|
6 |
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk> |
7 |
|
8 |
commit 9dd78194a3722fa6712192cdd4f7032d45112a9a upstream. |
9 |
|
10 |
As per other architectures, add support for reporting the Spectre |
11 |
vulnerability status via sysfs CPU. |
12 |
|
13 |
Acked-by: Catalin Marinas <catalin.marinas@arm.com> |
14 |
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> |
15 |
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
16 |
--- |
17 |
arch/arm/include/asm/spectre.h | 28 ++++++++ |
18 |
arch/arm/kernel/Makefile | 2 |
19 |
arch/arm/kernel/spectre.c | 54 +++++++++++++++ |
20 |
arch/arm/mm/Kconfig | 1 |
21 |
arch/arm/mm/proc-v7-bugs.c | 141 +++++++++++++++++++++++++++++------------ |
22 |
5 files changed, 187 insertions(+), 39 deletions(-) |
23 |
create mode 100644 arch/arm/include/asm/spectre.h |
24 |
create mode 100644 arch/arm/kernel/spectre.c |
25 |
|
26 |
--- /dev/null |
27 |
+++ b/arch/arm/include/asm/spectre.h |
28 |
@@ -0,0 +1,28 @@ |
29 |
+/* SPDX-License-Identifier: GPL-2.0-only */ |
30 |
+ |
31 |
+#ifndef __ASM_SPECTRE_H |
32 |
+#define __ASM_SPECTRE_H |
33 |
+ |
34 |
+enum { |
35 |
+ SPECTRE_UNAFFECTED, |
36 |
+ SPECTRE_MITIGATED, |
37 |
+ SPECTRE_VULNERABLE, |
38 |
+}; |
39 |
+ |
40 |
+enum { |
41 |
+ __SPECTRE_V2_METHOD_BPIALL, |
42 |
+ __SPECTRE_V2_METHOD_ICIALLU, |
43 |
+ __SPECTRE_V2_METHOD_SMC, |
44 |
+ __SPECTRE_V2_METHOD_HVC, |
45 |
+}; |
46 |
+ |
47 |
+enum { |
48 |
+ SPECTRE_V2_METHOD_BPIALL = BIT(__SPECTRE_V2_METHOD_BPIALL), |
49 |
+ SPECTRE_V2_METHOD_ICIALLU = BIT(__SPECTRE_V2_METHOD_ICIALLU), |
50 |
+ SPECTRE_V2_METHOD_SMC = BIT(__SPECTRE_V2_METHOD_SMC), |
51 |
+ SPECTRE_V2_METHOD_HVC = BIT(__SPECTRE_V2_METHOD_HVC), |
52 |
+}; |
53 |
+ |
54 |
+void spectre_v2_update_state(unsigned int state, unsigned int methods); |
55 |
+ |
56 |
+#endif |
57 |
--- a/arch/arm/kernel/Makefile |
58 |
+++ b/arch/arm/kernel/Makefile |
59 |
@@ -106,4 +106,6 @@ endif |
60 |
|
61 |
obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o |
62 |
|
63 |
+obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += spectre.o |
64 |
+ |
65 |
extra-y := $(head-y) vmlinux.lds |
66 |
--- /dev/null |
67 |
+++ b/arch/arm/kernel/spectre.c |
68 |
@@ -0,0 +1,54 @@ |
69 |
+// SPDX-License-Identifier: GPL-2.0-only |
70 |
+#include <linux/cpu.h> |
71 |
+#include <linux/device.h> |
72 |
+ |
73 |
+#include <asm/spectre.h> |
74 |
+ |
75 |
+ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, |
76 |
+ char *buf) |
77 |
+{ |
78 |
+ return sprintf(buf, "Mitigation: __user pointer sanitization\n"); |
79 |
+} |
80 |
+ |
81 |
+static unsigned int spectre_v2_state; |
82 |
+static unsigned int spectre_v2_methods; |
83 |
+ |
84 |
+void spectre_v2_update_state(unsigned int state, unsigned int method) |
85 |
+{ |
86 |
+ if (state > spectre_v2_state) |
87 |
+ spectre_v2_state = state; |
88 |
+ spectre_v2_methods |= method; |
89 |
+} |
90 |
+ |
91 |
+ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, |
92 |
+ char *buf) |
93 |
+{ |
94 |
+ const char *method; |
95 |
+ |
96 |
+ if (spectre_v2_state == SPECTRE_UNAFFECTED) |
97 |
+ return sprintf(buf, "%s\n", "Not affected"); |
98 |
+ |
99 |
+ if (spectre_v2_state != SPECTRE_MITIGATED) |
100 |
+ return sprintf(buf, "%s\n", "Vulnerable"); |
101 |
+ |
102 |
+ switch (spectre_v2_methods) { |
103 |
+ case SPECTRE_V2_METHOD_BPIALL: |
104 |
+ method = "Branch predictor hardening"; |
105 |
+ break; |
106 |
+ |
107 |
+ case SPECTRE_V2_METHOD_ICIALLU: |
108 |
+ method = "I-cache invalidation"; |
109 |
+ break; |
110 |
+ |
111 |
+ case SPECTRE_V2_METHOD_SMC: |
112 |
+ case SPECTRE_V2_METHOD_HVC: |
113 |
+ method = "Firmware call"; |
114 |
+ break; |
115 |
+ |
116 |
+ default: |
117 |
+ method = "Multiple mitigations"; |
118 |
+ break; |
119 |
+ } |
120 |
+ |
121 |
+ return sprintf(buf, "Mitigation: %s\n", method); |
122 |
+} |
123 |
--- a/arch/arm/mm/Kconfig |
124 |
+++ b/arch/arm/mm/Kconfig |
125 |
@@ -830,6 +830,7 @@ config CPU_BPREDICT_DISABLE |
126 |
|
127 |
config CPU_SPECTRE |
128 |
bool |
129 |
+ select GENERIC_CPU_VULNERABILITIES |
130 |
|
131 |
config HARDEN_BRANCH_PREDICTOR |
132 |
bool "Harden the branch predictor against aliasing attacks" if EXPERT |
133 |
--- a/arch/arm/mm/proc-v7-bugs.c |
134 |
+++ b/arch/arm/mm/proc-v7-bugs.c |
135 |
@@ -6,8 +6,35 @@ |
136 |
#include <asm/cp15.h> |
137 |
#include <asm/cputype.h> |
138 |
#include <asm/proc-fns.h> |
139 |
+#include <asm/spectre.h> |
140 |
#include <asm/system_misc.h> |
141 |
|
142 |
+#ifdef CONFIG_ARM_PSCI |
143 |
+static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void) |
144 |
+{ |
145 |
+ struct arm_smccc_res res; |
146 |
+ |
147 |
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, |
148 |
+ ARM_SMCCC_ARCH_WORKAROUND_1, &res); |
149 |
+ |
150 |
+ switch ((int)res.a0) { |
151 |
+ case SMCCC_RET_SUCCESS: |
152 |
+ return SPECTRE_MITIGATED; |
153 |
+ |
154 |
+ case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED: |
155 |
+ return SPECTRE_UNAFFECTED; |
156 |
+ |
157 |
+ default: |
158 |
+ return SPECTRE_VULNERABLE; |
159 |
+ } |
160 |
+} |
161 |
+#else |
162 |
+static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void) |
163 |
+{ |
164 |
+ return SPECTRE_VULNERABLE; |
165 |
+} |
166 |
+#endif |
167 |
+ |
168 |
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR |
169 |
DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn); |
170 |
|
171 |
@@ -36,13 +63,60 @@ static void __maybe_unused call_hvc_arch |
172 |
arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); |
173 |
} |
174 |
|
175 |
-static void cpu_v7_spectre_init(void) |
176 |
+static unsigned int spectre_v2_install_workaround(unsigned int method) |
177 |
{ |
178 |
const char *spectre_v2_method = NULL; |
179 |
int cpu = smp_processor_id(); |
180 |
|
181 |
if (per_cpu(harden_branch_predictor_fn, cpu)) |
182 |
- return; |
183 |
+ return SPECTRE_MITIGATED; |
184 |
+ |
185 |
+ switch (method) { |
186 |
+ case SPECTRE_V2_METHOD_BPIALL: |
187 |
+ per_cpu(harden_branch_predictor_fn, cpu) = |
188 |
+ harden_branch_predictor_bpiall; |
189 |
+ spectre_v2_method = "BPIALL"; |
190 |
+ break; |
191 |
+ |
192 |
+ case SPECTRE_V2_METHOD_ICIALLU: |
193 |
+ per_cpu(harden_branch_predictor_fn, cpu) = |
194 |
+ harden_branch_predictor_iciallu; |
195 |
+ spectre_v2_method = "ICIALLU"; |
196 |
+ break; |
197 |
+ |
198 |
+ case SPECTRE_V2_METHOD_HVC: |
199 |
+ per_cpu(harden_branch_predictor_fn, cpu) = |
200 |
+ call_hvc_arch_workaround_1; |
201 |
+ cpu_do_switch_mm = cpu_v7_hvc_switch_mm; |
202 |
+ spectre_v2_method = "hypervisor"; |
203 |
+ break; |
204 |
+ |
205 |
+ case SPECTRE_V2_METHOD_SMC: |
206 |
+ per_cpu(harden_branch_predictor_fn, cpu) = |
207 |
+ call_smc_arch_workaround_1; |
208 |
+ cpu_do_switch_mm = cpu_v7_smc_switch_mm; |
209 |
+ spectre_v2_method = "firmware"; |
210 |
+ break; |
211 |
+ } |
212 |
+ |
213 |
+ if (spectre_v2_method) |
214 |
+ pr_info("CPU%u: Spectre v2: using %s workaround\n", |
215 |
+ smp_processor_id(), spectre_v2_method); |
216 |
+ |
217 |
+ return SPECTRE_MITIGATED; |
218 |
+} |
219 |
+#else |
220 |
+static unsigned int spectre_v2_install_workaround(unsigned int method) |
221 |
+{ |
222 |
+ pr_info("CPU%u: Spectre V2: workarounds disabled by configuration\n"); |
223 |
+ |
224 |
+ return SPECTRE_VULNERABLE; |
225 |
+} |
226 |
+#endif |
227 |
+ |
228 |
+static void cpu_v7_spectre_v2_init(void) |
229 |
+{ |
230 |
+ unsigned int state, method = 0; |
231 |
|
232 |
switch (read_cpuid_part()) { |
233 |
case ARM_CPU_PART_CORTEX_A8: |
234 |
@@ -51,68 +125,57 @@ static void cpu_v7_spectre_init(void) |
235 |
case ARM_CPU_PART_CORTEX_A17: |
236 |
case ARM_CPU_PART_CORTEX_A73: |
237 |
case ARM_CPU_PART_CORTEX_A75: |
238 |
- per_cpu(harden_branch_predictor_fn, cpu) = |
239 |
- harden_branch_predictor_bpiall; |
240 |
- spectre_v2_method = "BPIALL"; |
241 |
+ state = SPECTRE_MITIGATED; |
242 |
+ method = SPECTRE_V2_METHOD_BPIALL; |
243 |
break; |
244 |
|
245 |
case ARM_CPU_PART_CORTEX_A15: |
246 |
case ARM_CPU_PART_BRAHMA_B15: |
247 |
- per_cpu(harden_branch_predictor_fn, cpu) = |
248 |
- harden_branch_predictor_iciallu; |
249 |
- spectre_v2_method = "ICIALLU"; |
250 |
+ state = SPECTRE_MITIGATED; |
251 |
+ method = SPECTRE_V2_METHOD_ICIALLU; |
252 |
break; |
253 |
|
254 |
-#ifdef CONFIG_ARM_PSCI |
255 |
case ARM_CPU_PART_BRAHMA_B53: |
256 |
/* Requires no workaround */ |
257 |
+ state = SPECTRE_UNAFFECTED; |
258 |
break; |
259 |
+ |
260 |
default: |
261 |
/* Other ARM CPUs require no workaround */ |
262 |
- if (read_cpuid_implementor() == ARM_CPU_IMP_ARM) |
263 |
+ if (read_cpuid_implementor() == ARM_CPU_IMP_ARM) { |
264 |
+ state = SPECTRE_UNAFFECTED; |
265 |
break; |
266 |
+ } |
267 |
+ |
268 |
fallthrough; |
269 |
- /* Cortex A57/A72 require firmware workaround */ |
270 |
- case ARM_CPU_PART_CORTEX_A57: |
271 |
- case ARM_CPU_PART_CORTEX_A72: { |
272 |
- struct arm_smccc_res res; |
273 |
|
274 |
- arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, |
275 |
- ARM_SMCCC_ARCH_WORKAROUND_1, &res); |
276 |
- if ((int)res.a0 != 0) |
277 |
- return; |
278 |
+ /* Cortex A57/A72 require firmware workaround */ |
279 |
+ case ARM_CPU_PART_CORTEX_A57: |
280 |
+ case ARM_CPU_PART_CORTEX_A72: |
281 |
+ state = spectre_v2_get_cpu_fw_mitigation_state(); |
282 |
+ if (state != SPECTRE_MITIGATED) |
283 |
+ break; |
284 |
|
285 |
switch (arm_smccc_1_1_get_conduit()) { |
286 |
case SMCCC_CONDUIT_HVC: |
287 |
- per_cpu(harden_branch_predictor_fn, cpu) = |
288 |
- call_hvc_arch_workaround_1; |
289 |
- cpu_do_switch_mm = cpu_v7_hvc_switch_mm; |
290 |
- spectre_v2_method = "hypervisor"; |
291 |
+ method = SPECTRE_V2_METHOD_HVC; |
292 |
break; |
293 |
|
294 |
case SMCCC_CONDUIT_SMC: |
295 |
- per_cpu(harden_branch_predictor_fn, cpu) = |
296 |
- call_smc_arch_workaround_1; |
297 |
- cpu_do_switch_mm = cpu_v7_smc_switch_mm; |
298 |
- spectre_v2_method = "firmware"; |
299 |
+ method = SPECTRE_V2_METHOD_SMC; |
300 |
break; |
301 |
|
302 |
default: |
303 |
+ state = SPECTRE_VULNERABLE; |
304 |
break; |
305 |
} |
306 |
} |
307 |
-#endif |
308 |
- } |
309 |
|
310 |
- if (spectre_v2_method) |
311 |
- pr_info("CPU%u: Spectre v2: using %s workaround\n", |
312 |
- smp_processor_id(), spectre_v2_method); |
313 |
-} |
314 |
-#else |
315 |
-static void cpu_v7_spectre_init(void) |
316 |
-{ |
317 |
+ if (state == SPECTRE_MITIGATED) |
318 |
+ state = spectre_v2_install_workaround(method); |
319 |
+ |
320 |
+ spectre_v2_update_state(state, method); |
321 |
} |
322 |
-#endif |
323 |
|
324 |
static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned, |
325 |
u32 mask, const char *msg) |
326 |
@@ -142,16 +205,16 @@ static bool check_spectre_auxcr(bool *wa |
327 |
void cpu_v7_ca8_ibe(void) |
328 |
{ |
329 |
if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6))) |
330 |
- cpu_v7_spectre_init(); |
331 |
+ cpu_v7_spectre_v2_init(); |
332 |
} |
333 |
|
334 |
void cpu_v7_ca15_ibe(void) |
335 |
{ |
336 |
if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0))) |
337 |
- cpu_v7_spectre_init(); |
338 |
+ cpu_v7_spectre_v2_init(); |
339 |
} |
340 |
|
341 |
void cpu_v7_bugs_init(void) |
342 |
{ |
343 |
- cpu_v7_spectre_init(); |
344 |
+ cpu_v7_spectre_v2_init(); |
345 |
} |