Skip to content

Commit f5fe12b

Browse files
author
Russell King
committed
ARM: spectre-v2: harden user aborts in kernel space
In order to prevent aliasing attacks on the branch predictor, invalidate the BTB or instruction cache on CPUs that are known to be affected when taking an abort on a address that is outside of a user task limit: Cortex A8, A9, A12, A17, A73, A75: flush BTB. Cortex A15, Brahma B15: invalidate icache. If the IBE bit is not set, then there is little point to enabling the workaround. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Boot-tested-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Tony Lindgren <tony@atomide.com>
1 parent e388b80 commit f5fe12b

File tree

5 files changed

+94
-8
lines changed

5 files changed

+94
-8
lines changed

arch/arm/include/asm/cp15.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
#define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v)))
6666
#define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__)
6767

68+
#define BPIALL __ACCESS_CP15(c7, 0, c5, 6)
69+
#define ICIALLU __ACCESS_CP15(c7, 0, c5, 0)
70+
6871
extern unsigned long cr_alignment; /* defined in entry-armv.S */
6972

7073
static inline unsigned long get_cr(void)

arch/arm/include/asm/system_misc.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,28 @@
88
#include <linux/linkage.h>
99
#include <linux/irqflags.h>
1010
#include <linux/reboot.h>
11+
#include <linux/percpu.h>
1112

1213
extern void cpu_init(void);
1314

1415
void soft_restart(unsigned long);
1516
extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
1617
extern void (*arm_pm_idle)(void);
1718

19+
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
20+
typedef void (*harden_branch_predictor_fn_t)(void);
21+
DECLARE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);
22+
static inline void harden_branch_predictor(void)
23+
{
24+
harden_branch_predictor_fn_t fn = per_cpu(harden_branch_predictor_fn,
25+
smp_processor_id());
26+
if (fn)
27+
fn();
28+
}
29+
#else
30+
#define harden_branch_predictor() do { } while (0)
31+
#endif
32+
1833
#define UDBG_UNDEFINED (1 << 0)
1934
#define UDBG_SYSCALL (1 << 1)
2035
#define UDBG_BADABORT (1 << 2)

arch/arm/mm/fault.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
163163
{
164164
struct siginfo si;
165165

166+
if (addr > TASK_SIZE)
167+
harden_branch_predictor();
168+
166169
#ifdef CONFIG_DEBUG_USER
167170
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
168171
((user_debug & UDBG_BUS) && (sig == SIGBUS))) {

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

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,61 @@
22
#include <linux/kernel.h>
33
#include <linux/smp.h>
44

5-
static __maybe_unused void cpu_v7_check_auxcr_set(bool *warned,
5+
#include <asm/cp15.h>
6+
#include <asm/cputype.h>
7+
#include <asm/system_misc.h>
8+
9+
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
10+
DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);
11+
12+
static void harden_branch_predictor_bpiall(void)
13+
{
14+
write_sysreg(0, BPIALL);
15+
}
16+
17+
static void harden_branch_predictor_iciallu(void)
18+
{
19+
write_sysreg(0, ICIALLU);
20+
}
21+
22+
static void cpu_v7_spectre_init(void)
23+
{
24+
const char *spectre_v2_method = NULL;
25+
int cpu = smp_processor_id();
26+
27+
if (per_cpu(harden_branch_predictor_fn, cpu))
28+
return;
29+
30+
switch (read_cpuid_part()) {
31+
case ARM_CPU_PART_CORTEX_A8:
32+
case ARM_CPU_PART_CORTEX_A9:
33+
case ARM_CPU_PART_CORTEX_A12:
34+
case ARM_CPU_PART_CORTEX_A17:
35+
case ARM_CPU_PART_CORTEX_A73:
36+
case ARM_CPU_PART_CORTEX_A75:
37+
per_cpu(harden_branch_predictor_fn, cpu) =
38+
harden_branch_predictor_bpiall;
39+
spectre_v2_method = "BPIALL";
40+
break;
41+
42+
case ARM_CPU_PART_CORTEX_A15:
43+
case ARM_CPU_PART_BRAHMA_B15:
44+
per_cpu(harden_branch_predictor_fn, cpu) =
45+
harden_branch_predictor_iciallu;
46+
spectre_v2_method = "ICIALLU";
47+
break;
48+
}
49+
if (spectre_v2_method)
50+
pr_info("CPU%u: Spectre v2: using %s workaround\n",
51+
smp_processor_id(), spectre_v2_method);
52+
}
53+
#else
54+
static void cpu_v7_spectre_init(void)
55+
{
56+
}
57+
#endif
58+
59+
static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
660
u32 mask, const char *msg)
761
{
862
u32 aux_cr;
@@ -13,24 +67,33 @@ static __maybe_unused void cpu_v7_check_auxcr_set(bool *warned,
1367
if (!*warned)
1468
pr_err("CPU%u: %s", smp_processor_id(), msg);
1569
*warned = true;
70+
return false;
1671
}
72+
return true;
1773
}
1874

1975
static DEFINE_PER_CPU(bool, spectre_warned);
2076

21-
static void check_spectre_auxcr(bool *warned, u32 bit)
77+
static bool check_spectre_auxcr(bool *warned, u32 bit)
2278
{
23-
if (IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR) &&
79+
return IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR) &&
2480
cpu_v7_check_auxcr_set(warned, bit,
2581
"Spectre v2: firmware did not set auxiliary control register IBE bit, system vulnerable\n");
2682
}
2783

2884
void cpu_v7_ca8_ibe(void)
2985
{
30-
check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6));
86+
if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6)))
87+
cpu_v7_spectre_init();
3188
}
3289

3390
void cpu_v7_ca15_ibe(void)
3491
{
35-
check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0));
92+
if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0)))
93+
cpu_v7_spectre_init();
94+
}
95+
96+
void cpu_v7_bugs_init(void)
97+
{
98+
cpu_v7_spectre_init();
3699
}

arch/arm/mm/proc-v7.S

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,10 @@ __v7_setup_stack:
532532

533533
__INITDATA
534534

535+
.weak cpu_v7_bugs_init
536+
535537
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
536-
define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
538+
define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
537539

538540
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
539541
@ generic v7 bpiall on context switch
@@ -548,7 +550,7 @@ __v7_setup_stack:
548550
globl_equ cpu_v7_bpiall_do_suspend, cpu_v7_do_suspend
549551
globl_equ cpu_v7_bpiall_do_resume, cpu_v7_do_resume
550552
#endif
551-
define_processor_functions v7_bpiall, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
553+
define_processor_functions v7_bpiall, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
552554

553555
#define HARDENED_BPIALL_PROCESSOR_FUNCTIONS v7_bpiall_processor_functions
554556
#else
@@ -584,7 +586,7 @@ __v7_setup_stack:
584586
globl_equ cpu_ca9mp_switch_mm, cpu_v7_switch_mm
585587
#endif
586588
globl_equ cpu_ca9mp_set_pte_ext, cpu_v7_set_pte_ext
587-
define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
589+
define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
588590
#endif
589591

590592
@ Cortex-A15 - needs iciallu switch_mm for hardening

0 commit comments

Comments
 (0)