Re: [PATCH 08/14] ARM: spectre-v2: harden user aborts in kernel space

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 21/05/18 12:45, Russell King wrote:
> 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.
> 
> Signed-off-by: Russell King <rmk+kernel@xxxxxxxxxxxxxxx>
> Reviewed-by: Florian Fainelli <f.fainelli@xxxxxxxxx>
> ---
>  arch/arm/include/asm/cp15.h        |  3 +++
>  arch/arm/include/asm/system_misc.h |  8 ++++++
>  arch/arm/mm/fault.c                |  3 +++
>  arch/arm/mm/proc-v7-bugs.c         | 51 ++++++++++++++++++++++++++++++++++++++
>  arch/arm/mm/proc-v7.S              |  8 +++---
>  5 files changed, 70 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h
> index 4c9fa72b59f5..07e27f212dc7 100644
> --- a/arch/arm/include/asm/cp15.h
> +++ b/arch/arm/include/asm/cp15.h
> @@ -65,6 +65,9 @@
>  #define __write_sysreg(v, r, w, c, t)	asm volatile(w " " c : : "r" ((t)(v)))
>  #define write_sysreg(v, ...)		__write_sysreg(v, __VA_ARGS__)
>  
> +#define BPIALL				__ACCESS_CP15(c7, 0, c5, 6)
> +#define ICIALLU				__ACCESS_CP15(c7, 0, c5, 0)
> +
>  extern unsigned long cr_alignment;	/* defined in entry-armv.S */
>  
>  static inline unsigned long get_cr(void)
> diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
> index 78f6db114faf..3cfe010c5734 100644
> --- a/arch/arm/include/asm/system_misc.h
> +++ b/arch/arm/include/asm/system_misc.h
> @@ -15,6 +15,14 @@ void soft_restart(unsigned long);
>  extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
>  extern void (*arm_pm_idle)(void);
>  
> +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
> +extern void (*harden_branch_predictor)(void);
> +#define harden_branch_predictor() \
> +	do { if (harden_branch_predictor) harden_branch_predictor(); } while (0)
> +#else
> +#define harden_branch_predictor() do { } while (0)
> +#endif
> +
>  #define UDBG_UNDEFINED	(1 << 0)
>  #define UDBG_SYSCALL	(1 << 1)
>  #define UDBG_BADABORT	(1 << 2)
> diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
> index b75eada23d0a..3b1ba003c4f9 100644
> --- a/arch/arm/mm/fault.c
> +++ b/arch/arm/mm/fault.c
> @@ -163,6 +163,9 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
>  {
>  	struct siginfo si;
>  
> +	if (addr > TASK_SIZE)
> +		harden_branch_predictor();
> +
>  #ifdef CONFIG_DEBUG_USER
>  	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
>  	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
> diff --git a/arch/arm/mm/proc-v7-bugs.c b/arch/arm/mm/proc-v7-bugs.c
> index a32ce13479d9..65a9b8141f86 100644
> --- a/arch/arm/mm/proc-v7-bugs.c
> +++ b/arch/arm/mm/proc-v7-bugs.c
> @@ -2,6 +2,12 @@
>  #include <linux/kernel.h>
>  #include <linux/smp.h>
>  
> +#include <asm/cp15.h>
> +#include <asm/cputype.h>
> +#include <asm/system_misc.h>
> +
> +void cpu_v7_bugs_init(void);
> +
>  static __maybe_unused void cpu_v7_check_auxcr_set(u32 mask, const char *msg)
>  {
>  	u32 aux_cr;
> @@ -21,9 +27,54 @@ static void check_spectre_auxcr(u32 bit)
>  void cpu_v7_ca8_ibe(void)
>  {
>  	check_spectre_auxcr(BIT(6));
> +	cpu_v7_bugs_init();
>  }
>  
>  void cpu_v7_ca15_ibe(void)
>  {
>  	check_spectre_auxcr(BIT(0));
> +	cpu_v7_bugs_init();
> +}
> +
> +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
> +void (*harden_branch_predictor)(void);
> +
> +static void harden_branch_predictor_bpiall(void)
> +{
> +	write_sysreg(0, BPIALL);
> +}
> +
> +static void harden_branch_predictor_iciallu(void)
> +{
> +	write_sysreg(0, ICIALLU);
> +}
> +
> +void cpu_v7_bugs_init(void)
> +{
> +	const char *spectre_v2_method = NULL;
> +
> +	if (harden_branch_predictor)
> +		return;

How does it work on a big-little systems where two CPUs have diverging
mitigation methods? Let's say an hypothetical A15/A17 system? Or even a
more common A15/A7 system, where the small core doesn't require the
mitigation?

> +
> +	switch (read_cpuid_part()) {
> +	case ARM_CPU_PART_CORTEX_A8:
> +	case ARM_CPU_PART_CORTEX_A9:
> +	case ARM_CPU_PART_CORTEX_A12:
> +	case ARM_CPU_PART_CORTEX_A17:
> +	case ARM_CPU_PART_CORTEX_A73:
> +	case ARM_CPU_PART_CORTEX_A75:
> +		harden_branch_predictor = harden_branch_predictor_bpiall;
> +		spectre_v2_method = "BPIALL";
> +		break;

You don't seem to take into account the PFR0.CSV2 field which indicates
that the CPU has a branch predictor that is immune to Spectre-v2.

See for example the Cortex-A75 r3p0 TRM[1].

> +
> +	case ARM_CPU_PART_CORTEX_A15:
> +	case ARM_CPU_PART_BRAHMA_B15:
> +		harden_branch_predictor = harden_branch_predictor_iciallu;
> +		spectre_v2_method = "ICIALLU";
> +		break;
> +	}
> +	if (spectre_v2_method)
> +		pr_info("CPU: Spectre v2: using %s workaround\n",
> +			spectre_v2_method);
>  }
> +#endif
> diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
> index fa9214036fb3..79510011e7eb 100644
> --- a/arch/arm/mm/proc-v7.S
> +++ b/arch/arm/mm/proc-v7.S
> @@ -532,8 +532,10 @@ ENDPROC(__v7_setup)
>  
>  	__INITDATA
>  
> +	.weak cpu_v7_bugs_init
> +
>  	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
> -	define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
> +	define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
>  
>  #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
>  	@ generic v7 bpiall on context switch
> @@ -548,7 +550,7 @@ ENDPROC(__v7_setup)
>  	globl_equ	cpu_v7_bpiall_do_suspend,	cpu_v7_do_suspend
>  	globl_equ	cpu_v7_bpiall_do_resume,	cpu_v7_do_resume
>  #endif
> -	define_processor_functions v7_bpiall, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
> +	define_processor_functions v7_bpiall, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
>  
>  #define HARDENED_BPIALL_PROCESSOR_FUNCTIONS v7_bpiall_processor_functions
>  #else
> @@ -584,7 +586,7 @@ ENDPROC(__v7_setup)
>  	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_switch_mm
>  #endif
>  	globl_equ	cpu_ca9mp_set_pte_ext,	cpu_v7_set_pte_ext
> -	define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
> +	define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
>  #endif
>  
>  	@ Cortex-A15 - needs iciallu switch_mm for hardening
> 

Thanks,

	M.

[1]
http://infocenter.arm.com/help/topic/com.arm.doc.100403_0300_00_en/axa1518783469631.html
-- 
Jazz is not dead. It just smells funny...
_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm



[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux