arm64: Add support for speculation barrier instruction (SB)
cover arm64: Add support for speculation barrier instruction (SB)
Hi all,
As part of the fallout from specdown and meltre, Armv8.5 introduces an architected Speculation Barrier (SB) instruction. Unlike CSDB, this is not retrofitted to existing CPUs, so we need to plumb in an HWCAP and make use of the alternatives framework to patch it over our current DSB; ISB sequence on CPUs that support it.
Cheers,
Will
--->8
Will Deacon (3):
arm64: Add support for SB barrier and patch in over DSB; ISB sequences
arm64: entry: Place an SB sequence following an ERET instruction
arm64: entry: Remove confusing comment
arch/arm64/include/asm/assembler.h | 13 +++++++++++++ arch/arm64/include/asm/barrier.h | 4 ++++ arch/arm64/include/asm/cpucaps.h | 3 ++- arch/arm64/include/asm/sysreg.h | 6 ++++++ arch/arm64/include/asm/uaccess.h | 3 +-- arch/arm64/include/uapi/asm/hwcap.h | 1 + arch/arm64/kernel/cpufeature.c | 12 ++++++++++++ arch/arm64/kernel/cpuinfo.c | 1 + arch/arm64/kernel/entry.S | 6 ++---- arch/arm64/kvm/hyp/entry.S | 1 + arch/arm64/kvm/hyp/hyp-entry.S | 4 ++++ 11 files changed, 47 insertions(+), 7 deletions(-)
Signature · 1 line
2.1.4
PATCH 1/3 arm64: Add support for SB barrier and patch in over DSB; ISB sequences
We currently use a DSB; ISB sequence to inhibit speculation in set_fs(). Whilst this works for current CPUs, future CPUs may implement a new SB barrier instruction which acts as an architected speculation barrier.
On CPUs that support it, patch in an SB; NOP sequence over the DSB; ISB sequence and advertise the presence of the new instruction to userspace.
--- arch/arm64/include/asm/assembler.h | 13 +++++++++++++ arch/arm64/include/asm/barrier.h | 4 ++++ arch/arm64/include/asm/cpucaps.h | 3 ++- arch/arm64/include/asm/sysreg.h | 6 ++++++ arch/arm64/include/asm/uaccess.h | 3 +-- arch/arm64/include/uapi/asm/hwcap.h | 1 + arch/arm64/kernel/cpufeature.c | 12 ++++++++++++ arch/arm64/kernel/cpuinfo.c | 1 + 8 files changed, 40 insertions(+), 3 deletions(-)
arch/arm64/include/asm/assembler.h +13 -0
@@ -123,6 +123,19 @@ .endm /* + * Speculation barrier + */ + .macro sb +alternative_if_not ARM64_HAS_SB + dsb nsh +isb +alternative_else +SB_BARRIER_INSN + nop +alternative_endif + .endm + +/* * Sanitise a 64-bit bounded index wrt speculation, returning zero if out * of bounds. */
arch/arm64/include/asm/barrier.h +4 -0
@@ -34,6 +34,10 @@#define psb_csync () asm volatile("hint #17" : : : "memory")#define csdb () asm volatile("hint #20" : : : "memory") +#define sb () asm volatile(ALTERNATIVE("dsb nsh\nisb\n", \ + SB_BARRIER_INSN"nop\n", \ + ARM64_HAS_SB)) +#define mb () dsb(sy)#define rmb () dsb(ld)#define wmb () dsb(st)
arch/arm64/include/asm/cpucaps.h +2 -1
@@ -54,7 +54,8 @@#define ARM64_HAS_CRC32 33#define ARM64_SSBS 34#define ARM64_WORKAROUND_1188873 35 +#define ARM64_HAS_SB 36 -#define ARM64_NCAPS 36 +#define ARM64_NCAPS 37#endif /* __ASM_CPUCAPS_H */
arch/arm64/include/asm/sysreg.h +6 -0
@@ -104,6 +104,11 @@#define SET_PSTATE_UAO (x) __emit_inst(0xd500401f | PSTATE_UAO | ((!!x) << PSTATE_Imm_shift))#define SET_PSTATE_SSBS (x) __emit_inst(0xd500401f | PSTATE_SSBS | ((!!x) << PSTATE_Imm_shift)) +#define __SYS_BARRIER_INSN (CRm, op2, Rt) \ + __emit_inst(0xd5000000 | sys_insn(0, 3, 3, (CRm), (op2)) | ((Rt) & 0x1f)) + +#define SB_BARRIER_INSN __SYS_BARRIER_INSN(0, 7, 31) +#define SYS_DC_ISW sys_insn(1, 0, 7, 6, 2)#define SYS_DC_CSW sys_insn(1, 0, 7, 10, 2)#define SYS_DC_CISW sys_insn(1, 0, 7, 14, 2)
@@ -528,6 +533,7 @@#define ID_AA64ISAR0_AES_SHIFT 4/* id_aa64isar1 */ +#define ID_AA64ISAR1_SB_SHIFT 36#define ID_AA64ISAR1_LRCPC_SHIFT 20#define ID_AA64ISAR1_FCMA_SHIFT 16#define ID_AA64ISAR1_JSCVT_SHIFT 12
arch/arm64/include/asm/uaccess.h +1 -2
@@ -45,8 +45,7 @@ static inline void set_fs(mm_segment_t fs)* Prevent a mispredicted conditional call to set_fs from forwarding * the wrong address limit to access_ok under speculation. */ -dsb (nsh); -isb (); +sb ();/* On user-mode return, check fs is correct */ set_thread_flag (TIF_FSCHECK );
arch/arm64/include/uapi/asm/hwcap.h +1 -0
@@ -49,5 +49,6 @@#define HWCAP_ILRCPC (1 << 26)#define HWCAP_FLAGM (1 << 27)#define HWCAP_SSBS (1 << 28) +#define HWCAP_SB (1 << 29)#endif /* _UAPI__ASM_HWCAP_H */
arch/arm64/kernel/cpufeature.c +12 -0
@@ -141,6 +141,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = { };static const struct arm64_ftr_bits ftr_id_aa64isar1[] = { +ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_LOWER_SAFE ,ID_AA64ISAR1_SB_SHIFT ,4 ,0 ),ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_LOWER_SAFE ,ID_AA64ISAR1_LRCPC_SHIFT ,4 ,0 ),ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_LOWER_SAFE ,ID_AA64ISAR1_FCMA_SHIFT ,4 ,0 ),ARM64_FTR_BITS (FTR_VISIBLE ,FTR_STRICT ,FTR_LOWER_SAFE ,ID_AA64ISAR1_JSCVT_SHIFT ,4 ,0 ),
@@ -1368,6 +1369,16 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .cpu_enable = cpu_enable_cnp, },#endif + { + .desc = "Speculation barrier (SB)", + .capability = ARM64_HAS_SB, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_cpuid_feature, + .sys_reg = SYS_ID_AA64ISAR1_EL1, + .field_pos = ID_AA64ISAR1_SB_SHIFT, + .sign = FTR_UNSIGNED, + .min_field_value = 1, + }, {}, };
@@ -1409,6 +1420,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {HWCAP_CAP (SYS_ID_AA64ISAR1_EL1 ,ID_AA64ISAR1_FCMA_SHIFT ,FTR_UNSIGNED ,1 ,CAP_HWCAP ,HWCAP_FCMA ),HWCAP_CAP (SYS_ID_AA64ISAR1_EL1 ,ID_AA64ISAR1_LRCPC_SHIFT ,FTR_UNSIGNED ,1 ,CAP_HWCAP ,HWCAP_LRCPC ),HWCAP_CAP (SYS_ID_AA64ISAR1_EL1 ,ID_AA64ISAR1_LRCPC_SHIFT ,FTR_UNSIGNED ,2 ,CAP_HWCAP ,HWCAP_ILRCPC ), +HWCAP_CAP (SYS_ID_AA64ISAR1_EL1 ,ID_AA64ISAR1_SB_SHIFT ,FTR_UNSIGNED ,1 ,CAP_HWCAP ,HWCAP_SB ),HWCAP_CAP (SYS_ID_AA64MMFR2_EL1 ,ID_AA64MMFR2_AT_SHIFT ,FTR_UNSIGNED ,1 ,CAP_HWCAP ,HWCAP_USCAT ), #ifdef CONFIG_ARM64_SVE HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE),
arch/arm64/kernel/cpuinfo.c +1 -0
@@ -82,6 +82,7 @@ static const char *const hwcap_str[] = {"ilrcpc" ,"flagm" ,"ssbs" , +"sb" , NULL };
Signature · 1 line
2.1.4
PATCH 2/3 arm64: entry: Place an SB sequence following an ERET instruction
In reply to Will DeaconSome CPUs can speculate past an ERET instruction and potentially perform speculative accesses to memory before processing the exception return. Since the register state is often controlled by a lower privilege level at the point of an ERET, this could potentially be used as part of a side-channel attack.
This patch emits an SB sequence after each ERET so that speculation is held up on exception return.
--- arch/arm64/kernel/entry.S | 2 ++ arch/arm64/kvm/hyp/entry.S | 1 + arch/arm64/kvm/hyp/hyp-entry.S | 4 ++++ 3 files changed, 7 insertions(+)
arch/arm64/kernel/entry.S +2 -0
@@ -363,6 +363,7 @@ alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 .else eret .endif + sb .endm .macro irq_stack_entry
@@ -1006,6 +1007,7 @@ alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003 mrs x30, far_el1 .endif eret + sb .endm .align 11
arch/arm64/kvm/hyp/entry.S +1 -0
@@ -83,6 +83,7 @@ ENTRY(__guest_enter) // Do not touch any register after this! eret + sb ENDPROC(__guest_enter) ENTRY(__guest_exit)
arch/arm64/kvm/hyp/hyp-entry.S +4 -0
@@ -96,6 +96,7 @@ el1_sync: // Guest trapped into EL2 do_el2_call eret + sb el1_hvc_guest: /*
@@ -146,6 +147,7 @@ wa_epilogue: mov x0, xzr add sp, sp, #16 eret + sb el1_trap: get_vcpu_ptr x1, x0
@@ -199,6 +201,7 @@ el2_error: b.ne __hyp_panic mov x0, #(1 << ARM_EXIT_WITH_SERROR_BIT) eret + sb ENTRY(__hyp_do_panic) mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
@@ -207,6 +210,7 @@ ENTRY(__hyp_do_panic) ldr lr, =panic msr elr_el2, lr eret + sb ENDPROC(__hyp_do_panic) ENTRY(__hyp_panic)
Signature · 1 line
2.1.4
PATCH 3/3 arm64: entry: Remove confusing comment
In reply to Will DeaconThe comment about SYS_MEMBARRIER_SYNC_CORE relying on ERET being context-synchronizing is confusing and misplaced with kpti. Given that this is already documented under Documentation/ (see arch-support.txt for membarrier), remove the comment altogether.
--- arch/arm64/kernel/entry.S | 4 ---- 1 file changed, 4 deletions(-)
arch/arm64/kernel/entry.S +0 -4
@@ -344,10 +344,6 @@ alternative_else_nop_endif ldp x28, x29, [sp, #16 * 14] ldr lr, [sp, #S_LR] add sp, sp, #S_FRAME_SIZE // restore sp - /* - * ARCH_HAS_MEMBARRIER_SYNC_CORE rely on eret context synchronization - * when returning from IPI handler, and when returning to user-space. - */ .if \el == 0 alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
Signature · 1 line
2.1.4