Skip to content

Commit b9baf5c

Browse files
author
Russell King (Oracle)
committed
ARM: Spectre-BHB workaround
Workaround the Spectre BHB issues for Cortex-A15, Cortex-A57, Cortex-A72, Cortex-A73 and Cortex-A75. We also include Brahma B15 as well to be safe, which is affected by Spectre V2 in the same ways as Cortex-A15. Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]>
1 parent 8d9d651 commit b9baf5c

File tree

9 files changed

+254
-9
lines changed

9 files changed

+254
-9
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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,19 @@ enum {
1414
__SPECTRE_V2_METHOD_ICIALLU,
1515
__SPECTRE_V2_METHOD_SMC,
1616
__SPECTRE_V2_METHOD_HVC,
17+
__SPECTRE_V2_METHOD_LOOP8,
1718
};
1819

1920
enum {
2021
SPECTRE_V2_METHOD_BPIALL = BIT(__SPECTRE_V2_METHOD_BPIALL),
2122
SPECTRE_V2_METHOD_ICIALLU = BIT(__SPECTRE_V2_METHOD_ICIALLU),
2223
SPECTRE_V2_METHOD_SMC = BIT(__SPECTRE_V2_METHOD_SMC),
2324
SPECTRE_V2_METHOD_HVC = BIT(__SPECTRE_V2_METHOD_HVC),
25+
SPECTRE_V2_METHOD_LOOP8 = BIT(__SPECTRE_V2_METHOD_LOOP8),
2426
};
2527

2628
void spectre_v2_update_state(unsigned int state, unsigned int methods);
2729

30+
int spectre_bhb_update_vectors(unsigned int method);
31+
2832
#endif

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,23 @@
116116
*/
117117
#define ARM_VECTORS \
118118
__vectors_lma = .; \
119-
.vectors 0xffff0000 : AT(__vectors_start) { \
120-
*(.vectors) \
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+
} \
121129
} \
122130
ARM_LMA(__vectors, .vectors); \
123-
. = __vectors_lma + SIZEOF(.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); \
124136
\
125137
__stubs_lma = .; \
126138
.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) { \

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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
4545
method = "Firmware call";
4646
break;
4747

48+
case SPECTRE_V2_METHOD_LOOP8:
49+
method = "History overwrite";
50+
break;
51+
4852
default:
4953
method = "Multiple mitigations";
5054
break;

arch/arm/kernel/traps.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/atomic.h>
3131
#include <asm/cacheflush.h>
3232
#include <asm/exception.h>
33+
#include <asm/spectre.h>
3334
#include <asm/unistd.h>
3435
#include <asm/traps.h>
3536
#include <asm/ptrace.h>
@@ -801,6 +802,43 @@ static void flush_vectors(void *vma, size_t offset, size_t size)
801802
flush_icache_range(start, end);
802803
}
803804

805+
#ifdef CONFIG_HARDEN_BRANCH_HISTORY
806+
int spectre_bhb_update_vectors(unsigned int method)
807+
{
808+
extern char __vectors_bhb_bpiall_start[], __vectors_bhb_bpiall_end[];
809+
extern char __vectors_bhb_loop8_start[], __vectors_bhb_loop8_end[];
810+
void *vec_start, *vec_end;
811+
812+
if (system_state >= SYSTEM_FREEING_INITMEM) {
813+
pr_err("CPU%u: Spectre BHB workaround too late - system vulnerable\n",
814+
smp_processor_id());
815+
return SPECTRE_VULNERABLE;
816+
}
817+
818+
switch (method) {
819+
case SPECTRE_V2_METHOD_LOOP8:
820+
vec_start = __vectors_bhb_loop8_start;
821+
vec_end = __vectors_bhb_loop8_end;
822+
break;
823+
824+
case SPECTRE_V2_METHOD_BPIALL:
825+
vec_start = __vectors_bhb_bpiall_start;
826+
vec_end = __vectors_bhb_bpiall_end;
827+
break;
828+
829+
default:
830+
pr_err("CPU%u: unknown Spectre BHB state %d\n",
831+
smp_processor_id(), method);
832+
return SPECTRE_VULNERABLE;
833+
}
834+
835+
copy_from_lma(vectors_page, vec_start, vec_end);
836+
flush_vectors(vectors_page, 0, vec_end - vec_start);
837+
838+
return SPECTRE_MITIGATED;
839+
}
840+
#endif
841+
804842
void __init early_trap_init(void *vectors_base)
805843
{
806844
extern char __stubs_start[], __stubs_end[];

arch/arm/mm/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,16 @@ config HARDEN_BRANCH_PREDICTOR
851851

852852
If unsure, say Y.
853853

854+
config HARDEN_BRANCH_HISTORY
855+
bool "Harden Spectre style attacks against branch history" if EXPERT
856+
depends on CPU_SPECTRE
857+
default y
858+
help
859+
Speculation attacks against some high-performance processors can
860+
make use of branch history to influence future speculation. When
861+
taking an exception, a sequence of branches overwrites the branch
862+
history, or branch history is invalidated.
863+
854864
config TLS_REG_EMUL
855865
bool
856866
select NEED_KUSER_HELPERS

arch/arm/mm/proc-v7-bugs.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,81 @@ static void cpu_v7_spectre_v2_init(void)
177177
spectre_v2_update_state(state, method);
178178
}
179179

180+
#ifdef CONFIG_HARDEN_BRANCH_HISTORY
181+
static int spectre_bhb_method;
182+
183+
static const char *spectre_bhb_method_name(int method)
184+
{
185+
switch (method) {
186+
case SPECTRE_V2_METHOD_LOOP8:
187+
return "loop";
188+
189+
case SPECTRE_V2_METHOD_BPIALL:
190+
return "BPIALL";
191+
192+
default:
193+
return "unknown";
194+
}
195+
}
196+
197+
static int spectre_bhb_install_workaround(int method)
198+
{
199+
if (spectre_bhb_method != method) {
200+
if (spectre_bhb_method) {
201+
pr_err("CPU%u: Spectre BHB: method disagreement, system vulnerable\n",
202+
smp_processor_id());
203+
204+
return SPECTRE_VULNERABLE;
205+
}
206+
207+
if (spectre_bhb_update_vectors(method) == SPECTRE_VULNERABLE)
208+
return SPECTRE_VULNERABLE;
209+
210+
spectre_bhb_method = method;
211+
}
212+
213+
pr_info("CPU%u: Spectre BHB: using %s workaround\n",
214+
smp_processor_id(), spectre_bhb_method_name(method));
215+
216+
return SPECTRE_MITIGATED;
217+
}
218+
#else
219+
static int spectre_bhb_install_workaround(int method)
220+
{
221+
return SPECTRE_VULNERABLE;
222+
}
223+
#endif
224+
225+
static void cpu_v7_spectre_bhb_init(void)
226+
{
227+
unsigned int state, method = 0;
228+
229+
switch (read_cpuid_part()) {
230+
case ARM_CPU_PART_CORTEX_A15:
231+
case ARM_CPU_PART_BRAHMA_B15:
232+
case ARM_CPU_PART_CORTEX_A57:
233+
case ARM_CPU_PART_CORTEX_A72:
234+
state = SPECTRE_MITIGATED;
235+
method = SPECTRE_V2_METHOD_LOOP8;
236+
break;
237+
238+
case ARM_CPU_PART_CORTEX_A73:
239+
case ARM_CPU_PART_CORTEX_A75:
240+
state = SPECTRE_MITIGATED;
241+
method = SPECTRE_V2_METHOD_BPIALL;
242+
break;
243+
244+
default:
245+
state = SPECTRE_UNAFFECTED;
246+
break;
247+
}
248+
249+
if (state == SPECTRE_MITIGATED)
250+
state = spectre_bhb_install_workaround(method);
251+
252+
spectre_v2_update_state(state, method);
253+
}
254+
180255
static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
181256
u32 mask, const char *msg)
182257
{
@@ -217,4 +292,5 @@ void cpu_v7_ca15_ibe(void)
217292
void cpu_v7_bugs_init(void)
218293
{
219294
cpu_v7_spectre_v2_init();
295+
cpu_v7_spectre_bhb_init();
220296
}

0 commit comments

Comments
 (0)