Skip to content

Commit fc55c23

Browse files
committed
Merge tag 'for-linus-bhb' of git://git.armlinux.org.uk/~rmk/linux-arm
Pull ARM spectre fixes from Russell King: "ARM Spectre BHB mitigations. These patches add Spectre BHB migitations for the following Arm CPUs to the 32-bit ARM kernels: - Cortex A15 - Cortex A57 - Cortex A72 - Cortex A73 - Cortex A75 - Brahma B15 for CVE-2022-23960" * tag 'for-linus-bhb' of git://git.armlinux.org.uk/~rmk/linux-arm: ARM: include unprivileged BPF status in Spectre V2 reporting ARM: Spectre-BHB workaround ARM: use LOADADDR() to get load address of sections ARM: early traps initialisation ARM: report Spectre v2 status through sysfs
2 parents 4a01e74 + 25875aa commit fc55c23

File tree

10 files changed

+481
-55
lines changed

10 files changed

+481
-55
lines changed

arch/arm/include/asm/assembler.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@
107107
.endm
108108
#endif
109109

110+
#if __LINUX_ARM_ARCH__ < 7
111+
.macro dsb, args
112+
mcr p15, 0, r0, c7, c10, 4
113+
.endm
114+
115+
.macro isb, args
116+
mcr p15, 0, r0, c7, r5, 4
117+
.endm
118+
#endif
119+
110120
.macro asm_trace_hardirqs_off, save=1
111121
#if defined(CONFIG_TRACE_IRQFLAGS)
112122
.if \save

arch/arm/include/asm/spectre.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __ASM_SPECTRE_H
4+
#define __ASM_SPECTRE_H
5+
6+
enum {
7+
SPECTRE_UNAFFECTED,
8+
SPECTRE_MITIGATED,
9+
SPECTRE_VULNERABLE,
10+
};
11+
12+
enum {
13+
__SPECTRE_V2_METHOD_BPIALL,
14+
__SPECTRE_V2_METHOD_ICIALLU,
15+
__SPECTRE_V2_METHOD_SMC,
16+
__SPECTRE_V2_METHOD_HVC,
17+
__SPECTRE_V2_METHOD_LOOP8,
18+
};
19+
20+
enum {
21+
SPECTRE_V2_METHOD_BPIALL = BIT(__SPECTRE_V2_METHOD_BPIALL),
22+
SPECTRE_V2_METHOD_ICIALLU = BIT(__SPECTRE_V2_METHOD_ICIALLU),
23+
SPECTRE_V2_METHOD_SMC = BIT(__SPECTRE_V2_METHOD_SMC),
24+
SPECTRE_V2_METHOD_HVC = BIT(__SPECTRE_V2_METHOD_HVC),
25+
SPECTRE_V2_METHOD_LOOP8 = BIT(__SPECTRE_V2_METHOD_LOOP8),
26+
};
27+
28+
void spectre_v2_update_state(unsigned int state, unsigned int methods);
29+
30+
int spectre_bhb_update_vectors(unsigned int method);
31+
32+
#endif

arch/arm/include/asm/vmlinux.lds.h

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
#define ARM_MMU_DISCARD(x) x
2727
#endif
2828

29+
/* Set start/end symbol names to the LMA for the section */
30+
#define ARM_LMA(sym, section) \
31+
sym##_start = LOADADDR(section); \
32+
sym##_end = LOADADDR(section) + SIZEOF(section)
33+
2934
#define PROC_INFO \
3035
. = ALIGN(4); \
3136
__proc_info_begin = .; \
@@ -110,19 +115,31 @@
110115
* only thing that matters is their relative offsets
111116
*/
112117
#define ARM_VECTORS \
113-
__vectors_start = .; \
114-
.vectors 0xffff0000 : AT(__vectors_start) { \
115-
*(.vectors) \
118+
__vectors_lma = .; \
119+
OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) { \
120+
.vectors { \
121+
*(.vectors) \
122+
} \
123+
.vectors.bhb.loop8 { \
124+
*(.vectors.bhb.loop8) \
125+
} \
126+
.vectors.bhb.bpiall { \
127+
*(.vectors.bhb.bpiall) \
128+
} \
116129
} \
117-
. = __vectors_start + SIZEOF(.vectors); \
118-
__vectors_end = .; \
130+
ARM_LMA(__vectors, .vectors); \
131+
ARM_LMA(__vectors_bhb_loop8, .vectors.bhb.loop8); \
132+
ARM_LMA(__vectors_bhb_bpiall, .vectors.bhb.bpiall); \
133+
. = __vectors_lma + SIZEOF(.vectors) + \
134+
SIZEOF(.vectors.bhb.loop8) + \
135+
SIZEOF(.vectors.bhb.bpiall); \
119136
\
120-
__stubs_start = .; \
121-
.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) { \
137+
__stubs_lma = .; \
138+
.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) { \
122139
*(.stubs) \
123140
} \
124-
. = __stubs_start + SIZEOF(.stubs); \
125-
__stubs_end = .; \
141+
ARM_LMA(__stubs, .stubs); \
142+
. = __stubs_lma + SIZEOF(.stubs); \
126143
\
127144
PROVIDE(vector_fiq_offset = vector_fiq - ADDR(.vectors));
128145

arch/arm/kernel/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,6 @@ endif
106106

107107
obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o
108108

109+
obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += spectre.o
110+
109111
extra-y := $(head-y) vmlinux.lds

arch/arm/kernel/entry-armv.S

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,12 +1002,11 @@ vector_\name:
10021002
sub lr, lr, #\correction
10031003
.endif
10041004

1005-
@
1006-
@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
1007-
@ (parent CPSR)
1008-
@
1005+
@ Save r0, lr_<exception> (parent PC)
10091006
stmia sp, {r0, lr} @ save r0, lr
1010-
mrs lr, spsr
1007+
1008+
@ Save spsr_<exception> (parent CPSR)
1009+
2: mrs lr, spsr
10111010
str lr, [sp, #8] @ save spsr
10121011

10131012
@
@@ -1028,6 +1027,44 @@ vector_\name:
10281027
movs pc, lr @ branch to handler in SVC mode
10291028
ENDPROC(vector_\name)
10301029

1030+
#ifdef CONFIG_HARDEN_BRANCH_HISTORY
1031+
.subsection 1
1032+
.align 5
1033+
vector_bhb_loop8_\name:
1034+
.if \correction
1035+
sub lr, lr, #\correction
1036+
.endif
1037+
1038+
@ Save r0, lr_<exception> (parent PC)
1039+
stmia sp, {r0, lr}
1040+
1041+
@ bhb workaround
1042+
mov r0, #8
1043+
1: b . + 4
1044+
subs r0, r0, #1
1045+
bne 1b
1046+
dsb
1047+
isb
1048+
b 2b
1049+
ENDPROC(vector_bhb_loop8_\name)
1050+
1051+
vector_bhb_bpiall_\name:
1052+
.if \correction
1053+
sub lr, lr, #\correction
1054+
.endif
1055+
1056+
@ Save r0, lr_<exception> (parent PC)
1057+
stmia sp, {r0, lr}
1058+
1059+
@ bhb workaround
1060+
mcr p15, 0, r0, c7, c5, 6 @ BPIALL
1061+
@ isb not needed due to "movs pc, lr" in the vector stub
1062+
@ which gives a "context synchronisation".
1063+
b 2b
1064+
ENDPROC(vector_bhb_bpiall_\name)
1065+
.previous
1066+
#endif
1067+
10311068
.align 2
10321069
@ handler addresses follow this label
10331070
1:
@@ -1036,6 +1073,10 @@ ENDPROC(vector_\name)
10361073
.section .stubs, "ax", %progbits
10371074
@ This must be the first word
10381075
.word vector_swi
1076+
#ifdef CONFIG_HARDEN_BRANCH_HISTORY
1077+
.word vector_bhb_loop8_swi
1078+
.word vector_bhb_bpiall_swi
1079+
#endif
10391080

10401081
vector_rst:
10411082
ARM( swi SYS_ERROR0 )
@@ -1150,8 +1191,10 @@ vector_addrexcptn:
11501191
* FIQ "NMI" handler
11511192
*-----------------------------------------------------------------------------
11521193
* Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
1153-
* systems.
1194+
* systems. This must be the last vector stub, so lets place it in its own
1195+
* subsection.
11541196
*/
1197+
.subsection 2
11551198
vector_stub fiq, FIQ_MODE, 4
11561199

11571200
.long __fiq_usr @ 0 (USR_26 / USR_32)
@@ -1184,6 +1227,30 @@ vector_addrexcptn:
11841227
W(b) vector_irq
11851228
W(b) vector_fiq
11861229

1230+
#ifdef CONFIG_HARDEN_BRANCH_HISTORY
1231+
.section .vectors.bhb.loop8, "ax", %progbits
1232+
.L__vectors_bhb_loop8_start:
1233+
W(b) vector_rst
1234+
W(b) vector_bhb_loop8_und
1235+
W(ldr) pc, .L__vectors_bhb_loop8_start + 0x1004
1236+
W(b) vector_bhb_loop8_pabt
1237+
W(b) vector_bhb_loop8_dabt
1238+
W(b) vector_addrexcptn
1239+
W(b) vector_bhb_loop8_irq
1240+
W(b) vector_bhb_loop8_fiq
1241+
1242+
.section .vectors.bhb.bpiall, "ax", %progbits
1243+
.L__vectors_bhb_bpiall_start:
1244+
W(b) vector_rst
1245+
W(b) vector_bhb_bpiall_und
1246+
W(ldr) pc, .L__vectors_bhb_bpiall_start + 0x1008
1247+
W(b) vector_bhb_bpiall_pabt
1248+
W(b) vector_bhb_bpiall_dabt
1249+
W(b) vector_addrexcptn
1250+
W(b) vector_bhb_bpiall_irq
1251+
W(b) vector_bhb_bpiall_fiq
1252+
#endif
1253+
11871254
.data
11881255
.align 2
11891256

arch/arm/kernel/entry-common.S

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,37 @@ ENDPROC(ret_from_fork)
153153
*-----------------------------------------------------------------------------
154154
*/
155155

156+
.align 5
157+
#ifdef CONFIG_HARDEN_BRANCH_HISTORY
158+
ENTRY(vector_bhb_loop8_swi)
159+
sub sp, sp, #PT_REGS_SIZE
160+
stmia sp, {r0 - r12}
161+
mov r8, #8
162+
1: b 2f
163+
2: subs r8, r8, #1
164+
bne 1b
165+
dsb
166+
isb
167+
b 3f
168+
ENDPROC(vector_bhb_loop8_swi)
169+
170+
.align 5
171+
ENTRY(vector_bhb_bpiall_swi)
172+
sub sp, sp, #PT_REGS_SIZE
173+
stmia sp, {r0 - r12}
174+
mcr p15, 0, r8, c7, c5, 6 @ BPIALL
175+
isb
176+
b 3f
177+
ENDPROC(vector_bhb_bpiall_swi)
178+
#endif
156179
.align 5
157180
ENTRY(vector_swi)
158181
#ifdef CONFIG_CPU_V7M
159182
v7m_exception_entry
160183
#else
161184
sub sp, sp, #PT_REGS_SIZE
162185
stmia sp, {r0 - r12} @ Calling r0 - r12
186+
3:
163187
ARM( add r8, sp, #S_PC )
164188
ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
165189
THUMB( mov r8, sp )

arch/arm/kernel/spectre.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <linux/bpf.h>
3+
#include <linux/cpu.h>
4+
#include <linux/device.h>
5+
6+
#include <asm/spectre.h>
7+
8+
static bool _unprivileged_ebpf_enabled(void)
9+
{
10+
#ifdef CONFIG_BPF_SYSCALL
11+
return !sysctl_unprivileged_bpf_disabled;
12+
#else
13+
return false
14+
#endif
15+
}
16+
17+
ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
18+
char *buf)
19+
{
20+
return sprintf(buf, "Mitigation: __user pointer sanitization\n");
21+
}
22+
23+
static unsigned int spectre_v2_state;
24+
static unsigned int spectre_v2_methods;
25+
26+
void spectre_v2_update_state(unsigned int state, unsigned int method)
27+
{
28+
if (state > spectre_v2_state)
29+
spectre_v2_state = state;
30+
spectre_v2_methods |= method;
31+
}
32+
33+
ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
34+
char *buf)
35+
{
36+
const char *method;
37+
38+
if (spectre_v2_state == SPECTRE_UNAFFECTED)
39+
return sprintf(buf, "%s\n", "Not affected");
40+
41+
if (spectre_v2_state != SPECTRE_MITIGATED)
42+
return sprintf(buf, "%s\n", "Vulnerable");
43+
44+
if (_unprivileged_ebpf_enabled())
45+
return sprintf(buf, "Vulnerable: Unprivileged eBPF enabled\n");
46+
47+
switch (spectre_v2_methods) {
48+
case SPECTRE_V2_METHOD_BPIALL:
49+
method = "Branch predictor hardening";
50+
break;
51+
52+
case SPECTRE_V2_METHOD_ICIALLU:
53+
method = "I-cache invalidation";
54+
break;
55+
56+
case SPECTRE_V2_METHOD_SMC:
57+
case SPECTRE_V2_METHOD_HVC:
58+
method = "Firmware call";
59+
break;
60+
61+
case SPECTRE_V2_METHOD_LOOP8:
62+
method = "History overwrite";
63+
break;
64+
65+
default:
66+
method = "Multiple mitigations";
67+
break;
68+
}
69+
70+
return sprintf(buf, "Mitigation: %s\n", method);
71+
}

0 commit comments

Comments
 (0)