Skip to content

Commit 558c303

Browse files
author
James Morse
committed
arm64: Mitigate spectre style branch history side channels
Speculation attacks against some high-performance processors can make use of branch history to influence future speculation. When taking an exception from user-space, a sequence of branches or a firmware call overwrites or invalidates the branch history. The sequence of branches is added to the vectors, and should appear before the first indirect branch. For systems using KPTI the sequence is added to the kpti trampoline where it has a free register as the exit from the trampoline is via a 'ret'. For systems not using KPTI, the same register tricks are used to free up a register in the vectors. For the firmware call, arch-workaround-3 clobbers 4 registers, so there is no choice but to save them to the EL1 stack. This only happens for entry from EL0, so if we take an exception due to the stack access, it will not become re-entrant. For KVM, the existing branch-predictor-hardening vectors are used. When a spectre version of these vectors is in use, the firmware call is sufficient to mitigate against Spectre-BHB. For the non-spectre versions, the sequence of branches is added to the indirect vector. Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: James Morse <[email protected]>
1 parent dee435b commit 558c303

File tree

12 files changed

+352
-2
lines changed

12 files changed

+352
-2
lines changed

arch/arm64/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,15 @@ config UNMAP_KERNEL_AT_EL0
13821382

13831383
If unsure, say Y.
13841384

1385+
config MITIGATE_SPECTRE_BRANCH_HISTORY
1386+
bool "Mitigate Spectre style attacks against branch history" if EXPERT
1387+
default y
1388+
help
1389+
Speculation attacks against some high-performance processors can
1390+
make use of branch history to influence future speculation.
1391+
When taking an exception from user-space, a sequence of branches
1392+
or a firmware call overwrites the branch history.
1393+
13851394
config RODATA_FULL_DEFAULT_ENABLED
13861395
bool "Apply r/o permissions of VM areas also to their linear aliases"
13871396
default y

arch/arm64/include/asm/assembler.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,9 @@ alternative_endif
852852

853853
.macro __mitigate_spectre_bhb_loop tmp
854854
#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
855-
mov \tmp, #32
855+
alternative_cb spectre_bhb_patch_loop_iter
856+
mov \tmp, #32 // Patched to correct the immediate
857+
alternative_cb_end
856858
.Lspectre_bhb_loop\@:
857859
b . + 4
858860
subs \tmp, \tmp, #1
@@ -861,6 +863,16 @@ alternative_endif
861863
#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
862864
.endm
863865

866+
.macro mitigate_spectre_bhb_loop tmp
867+
#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
868+
alternative_cb spectre_bhb_patch_loop_mitigation_enable
869+
b .L_spectre_bhb_loop_done\@ // Patched to NOP
870+
alternative_cb_end
871+
__mitigate_spectre_bhb_loop \tmp
872+
.L_spectre_bhb_loop_done\@:
873+
#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
874+
.endm
875+
864876
/* Save/restores x0-x3 to the stack */
865877
.macro __mitigate_spectre_bhb_fw
866878
#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY

arch/arm64/include/asm/cpufeature.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,22 @@ static inline bool cpu_supports_mixed_endian_el0(void)
637637
return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
638638
}
639639

640+
641+
static inline bool supports_csv2p3(int scope)
642+
{
643+
u64 pfr0;
644+
u8 csv2_val;
645+
646+
if (scope == SCOPE_LOCAL_CPU)
647+
pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
648+
else
649+
pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
650+
651+
csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
652+
ID_AA64PFR0_CSV2_SHIFT);
653+
return csv2_val == 3;
654+
}
655+
640656
const struct cpumask *system_32bit_el0_cpumask(void);
641657
DECLARE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
642658

arch/arm64/include/asm/cputype.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,14 @@
7373
#define ARM_CPU_PART_CORTEX_A76 0xD0B
7474
#define ARM_CPU_PART_NEOVERSE_N1 0xD0C
7575
#define ARM_CPU_PART_CORTEX_A77 0xD0D
76+
#define ARM_CPU_PART_NEOVERSE_V1 0xD40
77+
#define ARM_CPU_PART_CORTEX_A78 0xD41
78+
#define ARM_CPU_PART_CORTEX_X1 0xD44
7679
#define ARM_CPU_PART_CORTEX_A510 0xD46
7780
#define ARM_CPU_PART_CORTEX_A710 0xD47
7881
#define ARM_CPU_PART_CORTEX_X2 0xD48
7982
#define ARM_CPU_PART_NEOVERSE_N2 0xD49
83+
#define ARM_CPU_PART_CORTEX_A78C 0xD4B
8084

8185
#define APM_CPU_PART_POTENZA 0x000
8286

@@ -117,10 +121,14 @@
117121
#define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
118122
#define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
119123
#define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
124+
#define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
125+
#define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
126+
#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
120127
#define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
121128
#define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
122129
#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
123130
#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
131+
#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
124132
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
125133
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
126134
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)

arch/arm64/include/asm/spectre.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ void spectre_v4_enable_task_mitigation(struct task_struct *tsk);
9494
enum mitigation_state arm64_get_meltdown_state(void);
9595

9696
enum mitigation_state arm64_get_spectre_bhb_state(void);
97-
97+
bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
98+
u8 spectre_bhb_loop_affected(int scope);
99+
void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
98100
#endif /* __ASSEMBLY__ */
99101
#endif /* __ASM_SPECTRE_H */

arch/arm64/include/asm/sysreg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@
904904
#endif
905905

906906
/* id_aa64mmfr1 */
907+
#define ID_AA64MMFR1_ECBHB_SHIFT 60
907908
#define ID_AA64MMFR1_AFP_SHIFT 44
908909
#define ID_AA64MMFR1_ETS_SHIFT 36
909910
#define ID_AA64MMFR1_TWED_SHIFT 32

arch/arm64/include/asm/vectors.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ enum arm64_bp_harden_el1_vectors {
4040
EL1_VECTOR_KPTI,
4141
};
4242

43+
#ifndef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
44+
#define EL1_VECTOR_BHB_LOOP -1
45+
#define EL1_VECTOR_BHB_FW -1
46+
#endif /* !CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
47+
4348
/* The vectors to use on return from EL0. e.g. to remap the kernel */
4449
DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector);
4550

arch/arm64/kernel/cpu_errata.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
502502
.matches = has_spectre_v4,
503503
.cpu_enable = spectre_v4_enable_mitigation,
504504
},
505+
{
506+
.desc = "Spectre-BHB",
507+
.capability = ARM64_SPECTRE_BHB,
508+
.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
509+
.matches = is_spectre_bhb_affected,
510+
.cpu_enable = spectre_bhb_enable_mitigation,
511+
},
505512
#ifdef CONFIG_ARM64_ERRATUM_1418040
506513
{
507514
.desc = "ARM erratum 1418040",

arch/arm64/kernel/image-vars.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ KVM_NVHE_ALIAS(kvm_patch_vector_branch);
6666
KVM_NVHE_ALIAS(kvm_update_va_mask);
6767
KVM_NVHE_ALIAS(kvm_get_kimage_voffset);
6868
KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0);
69+
KVM_NVHE_ALIAS(spectre_bhb_patch_loop_iter);
70+
KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);
71+
KVM_NVHE_ALIAS(spectre_bhb_patch_wa3);
6972

7073
/* Global kernel state accessed by nVHE hyp code. */
7174
KVM_NVHE_ALIAS(kvm_vgic_global_state);

0 commit comments

Comments
 (0)