diff mbox series

[Xen-devel,5/5] xen/arm64: Implement branch predictor hardening for affected Cortex-A CPUs

Message ID 20180116142337.24942-6-julien.grall@linaro.org
State Accepted
Commit e730f8e41e8537f1db9770b9464f9523c28857b9
Headers show
Series xen/arm64: Branch predictor hardening (XSA-254 variant 2) | expand

Commit Message

Julien Grall Jan. 16, 2018, 2:23 p.m. UTC
Cortex-A57, A72, A73 and A75 are susceptible to branch predictor
aliasing and can theoritically be attacked by malicious code.

This patch implements a PSCI-based mitigation for these CPUs when
available. The call into firmware will invalidate the branch predictor
state, preventing any malicious entries from affection other victim
contexts.

Ported from Linux git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
branch kpti.

 Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
 Signed-off-by: Will Deacon <will.deacon@arm.com>

This is part of XSA-254.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
---
 xen/arch/arm/arm64/bpi.S | 25 ++++++++++++++++++++++++
 xen/arch/arm/cpuerrata.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+)

Comments

Stefano Stabellini Jan. 17, 2018, 12:42 a.m. UTC | #1
On Tue, 16 Jan 2018, Julien Grall wrote:
> Cortex-A57, A72, A73 and A75 are susceptible to branch predictor
> aliasing and can theoritically be attacked by malicious code.
> 
> This patch implements a PSCI-based mitigation for these CPUs when
> available. The call into firmware will invalidate the branch predictor
> state, preventing any malicious entries from affection other victim
> contexts.
> 
> Ported from Linux git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
> branch kpti.
> 
>  Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>  Signed-off-by: Will Deacon <will.deacon@arm.com>
> 
> This is part of XSA-254.
> 
> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> ---
>  xen/arch/arm/arm64/bpi.S | 25 ++++++++++++++++++++++++
>  xen/arch/arm/cpuerrata.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 74 insertions(+)
> 
> diff --git a/xen/arch/arm/arm64/bpi.S b/xen/arch/arm/arm64/bpi.S
> index 6cc2f17529..4b7f1dc21f 100644
> --- a/xen/arch/arm/arm64/bpi.S
> +++ b/xen/arch/arm/arm64/bpi.S
> @@ -56,6 +56,31 @@ ENTRY(__bp_harden_hyp_vecs_start)
>      .endr
>  ENTRY(__bp_harden_hyp_vecs_end)
>  
> +ENTRY(__psci_hyp_bp_inval_start)
> +    sub     sp, sp, #(8 * 18)
> +    stp     x16, x17, [sp, #(16 * 0)]
> +    stp     x14, x15, [sp, #(16 * 1)]
> +    stp     x12, x13, [sp, #(16 * 2)]
> +    stp     x10, x11, [sp, #(16 * 3)]
> +    stp     x8, x9, [sp, #(16 * 4)]
> +    stp     x6, x7, [sp, #(16 * 5)]
> +    stp     x4, x5, [sp, #(16 * 6)]
> +    stp     x2, x3, [sp, #(16 * 7)]
> +    stp     x0, x1, [sp, #(16 * 8)]
> +    mov     x0, #0x84000000
> +    smc     #0
> +    ldp     x16, x17, [sp, #(16 * 0)]
> +    ldp     x14, x15, [sp, #(16 * 1)]
> +    ldp     x12, x13, [sp, #(16 * 2)]
> +    ldp     x10, x11, [sp, #(16 * 3)]
> +    ldp     x8, x9, [sp, #(16 * 4)]
> +    ldp     x6, x7, [sp, #(16 * 5)]
> +    ldp     x4, x5, [sp, #(16 * 6)]
> +    ldp     x2, x3, [sp, #(16 * 7)]
> +    ldp     x0, x1, [sp, #(16 * 8)]
> +    add     sp, sp, #(8 * 18)
> +ENTRY(__psci_hyp_bp_inval_end)
> +
>  /*
>   * Local variables:
>   * mode: ASM
> diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c
> index 76d98e771d..f1ea7f3c5b 100644
> --- a/xen/arch/arm/cpuerrata.c
> +++ b/xen/arch/arm/cpuerrata.c
> @@ -4,8 +4,10 @@
>  #include <xen/smp.h>
>  #include <xen/spinlock.h>
>  #include <xen/vmap.h>
> +#include <xen/warning.h>
>  #include <asm/cpufeature.h>
>  #include <asm/cpuerrata.h>
> +#include <asm/psci.h>
>  
>  /* Override macros from asm/page.h to make them work with mfn_t */
>  #undef virt_to_mfn
> @@ -141,6 +143,31 @@ install_bp_hardening_vec(const struct arm_cpu_capabilities *entry,
>      return ret;
>  }
>  
> +extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
> +
> +static int enable_psci_bp_hardening(void *data)
> +{
> +    bool ret = true;
> +    static bool warned = false;
> +
> +    /*
> +     * The mitigation is using PSCI version function to invalidate the
> +     * branch predictor. This function is only available with PSCI 0.2
> +     * and later.
> +     */
> +    if ( psci_ver >= PSCI_VERSION(0, 2) )
> +        ret = install_bp_hardening_vec(data, __psci_hyp_bp_inval_start,
> +                                       __psci_hyp_bp_inval_end);
> +    else if ( !warned )
> +    {
> +        ASSERT(system_state < SYS_STATE_active);
> +        warning_add("PSCI 0.2 or later is required for the branch predictor hardening.\n");
> +        warned = true;
> +    }
> +
> +    return !ret;
> +}
> +
>  #endif /* CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR */
>  
>  #define MIDR_RANGE(model, min, max)     \
> @@ -205,6 +232,28 @@ static const struct arm_cpu_capabilities arm_errata[] = {
>                     (1 << MIDR_VARIANT_SHIFT) | 2),
>      },
>  #endif
> +#ifdef CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR
> +    {
> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
> +        .enable = enable_psci_bp_hardening,
> +    },
> +    {
> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
> +        .enable = enable_psci_bp_hardening,
> +    },
> +    {
> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
> +        .enable = enable_psci_bp_hardening,
> +    },
> +    {
> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
> +        .enable = enable_psci_bp_hardening,
> +    },

We need to add a basic description in the desc field as it is printed by
update_cpu_capabilities.


> +#endif
>      {},
>  };
>  
> -- 
> 2.11.0
>
Julien Grall Jan. 17, 2018, 10:52 a.m. UTC | #2
Hi Stefano,

On 17/01/18 00:42, Stefano Stabellini wrote:
> On Tue, 16 Jan 2018, Julien Grall wrote:
>>   #define MIDR_RANGE(model, min, max)     \
>> @@ -205,6 +232,28 @@ static const struct arm_cpu_capabilities arm_errata[] = {
>>                      (1 << MIDR_VARIANT_SHIFT) | 2),
>>       },
>>   #endif
>> +#ifdef CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR
>> +    {
>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
>> +        .enable = enable_psci_bp_hardening,
>> +    },
>> +    {
>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
>> +        .enable = enable_psci_bp_hardening,
>> +    },
>> +    {
>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
>> +        .enable = enable_psci_bp_hardening,
>> +    },
>> +    {
>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
>> +        .enable = enable_psci_bp_hardening,
>> +    },
> 
> We need to add a basic description in the desc field as it is printed by
> update_cpu_capabilities.

desc field is not mandatory, and in that case I think the print would be 
confusing. At the difference of the other errata, we have more check in 
install_bp_hardening_vec that may result to skip the hardening.

The errata here is covering all variant/revision of A75 models for 
safety reason. Arm has introduced a new field ID_AA64PFR0_EL1.CSV2 to 
tell whether a branch predictor trained in one context will affect 
speculative execution in another context. This field is checked in 
install_bp_hardening_vec so you avoid to harden the vector tables and 
small performance hit.

IHMO, it would be better to have a per-CPU message in 
install_bp_hardening_vec announcing whether the vector tables has been 
harden and the kind of hardening.

What do you think?

Cheers,

> 
> 
>> +#endif
>>       {},
>>   };
>>   
>> -- 
>> 2.11.0
>>
Stefano Stabellini Jan. 17, 2018, 5:11 p.m. UTC | #3
On Wed, 17 Jan 2018, Julien Grall wrote:
> Hi Stefano,
> 
> On 17/01/18 00:42, Stefano Stabellini wrote:
> > On Tue, 16 Jan 2018, Julien Grall wrote:
> > >   #define MIDR_RANGE(model, min, max)     \
> > > @@ -205,6 +232,28 @@ static const struct arm_cpu_capabilities arm_errata[]
> > > = {
> > >                      (1 << MIDR_VARIANT_SHIFT) | 2),
> > >       },
> > >   #endif
> > > +#ifdef CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR
> > > +    {
> > > +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> > > +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
> > > +        .enable = enable_psci_bp_hardening,
> > > +    },
> > > +    {
> > > +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> > > +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
> > > +        .enable = enable_psci_bp_hardening,
> > > +    },
> > > +    {
> > > +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> > > +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
> > > +        .enable = enable_psci_bp_hardening,
> > > +    },
> > > +    {
> > > +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
> > > +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
> > > +        .enable = enable_psci_bp_hardening,
> > > +    },
> > 
> > We need to add a basic description in the desc field as it is printed by
> > update_cpu_capabilities.
> 
> desc field is not mandatory, and in that case I think the print would be
> confusing. At the difference of the other errata, we have more check in
> install_bp_hardening_vec that may result to skip the hardening.
> 
> The errata here is covering all variant/revision of A75 models for safety
> reason. Arm has introduced a new field ID_AA64PFR0_EL1.CSV2 to tell whether a
> branch predictor trained in one context will affect speculative execution in
> another context. This field is checked in install_bp_hardening_vec so you
> avoid to harden the vector tables and small performance hit.
> 
> IHMO, it would be better to have a per-CPU message in install_bp_hardening_vec
> announcing whether the vector tables has been harden and the kind of
> hardening.
> 
> What do you think?

I understand what you are saying and I agree with you. Maybe we should
change update_cpu_capabilities to print "detected need for workaround:
blah" but you don't have to do it in this series.
Julien Grall Jan. 18, 2018, 11:19 a.m. UTC | #4
Hi,

On 17/01/18 17:11, Stefano Stabellini wrote:
> On Wed, 17 Jan 2018, Julien Grall wrote:
>> Hi Stefano,
>>
>> On 17/01/18 00:42, Stefano Stabellini wrote:
>>> On Tue, 16 Jan 2018, Julien Grall wrote:
>>>>    #define MIDR_RANGE(model, min, max)     \
>>>> @@ -205,6 +232,28 @@ static const struct arm_cpu_capabilities arm_errata[]
>>>> = {
>>>>                       (1 << MIDR_VARIANT_SHIFT) | 2),
>>>>        },
>>>>    #endif
>>>> +#ifdef CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR
>>>> +    {
>>>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>>>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
>>>> +        .enable = enable_psci_bp_hardening,
>>>> +    },
>>>> +    {
>>>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>>>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
>>>> +        .enable = enable_psci_bp_hardening,
>>>> +    },
>>>> +    {
>>>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>>>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
>>>> +        .enable = enable_psci_bp_hardening,
>>>> +    },
>>>> +    {
>>>> +        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
>>>> +        MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
>>>> +        .enable = enable_psci_bp_hardening,
>>>> +    },
>>>
>>> We need to add a basic description in the desc field as it is printed by
>>> update_cpu_capabilities.
>>
>> desc field is not mandatory, and in that case I think the print would be
>> confusing. At the difference of the other errata, we have more check in
>> install_bp_hardening_vec that may result to skip the hardening.
>>
>> The errata here is covering all variant/revision of A75 models for safety
>> reason. Arm has introduced a new field ID_AA64PFR0_EL1.CSV2 to tell whether a
>> branch predictor trained in one context will affect speculative execution in
>> another context. This field is checked in install_bp_hardening_vec so you
>> avoid to harden the vector tables and small performance hit.
>>
>> IHMO, it would be better to have a per-CPU message in install_bp_hardening_vec
>> announcing whether the vector tables has been harden and the kind of
>> hardening.
>>
>> What do you think?
> 
> I understand what you are saying and I agree with you. Maybe we should
> change update_cpu_capabilities to print "detected need for workaround:
> blah" but you don't have to do it in this series.

"need for workaround..." is not entirely true for the branch predictor 
hardening. It is more a "may need". I still prefer the per-CPU message
"CPU%u will %s on guest exit"

%u is the CPU number. %s will be the name of the call/instruction to 
execute.

The rationale behind is branch predictor hardening may be different on 
each CPU (think big.LITTLE) so code executed will be different. This 
differ from the other errata that will be applied for all CPUs.

Cheers,
diff mbox series

Patch

diff --git a/xen/arch/arm/arm64/bpi.S b/xen/arch/arm/arm64/bpi.S
index 6cc2f17529..4b7f1dc21f 100644
--- a/xen/arch/arm/arm64/bpi.S
+++ b/xen/arch/arm/arm64/bpi.S
@@ -56,6 +56,31 @@  ENTRY(__bp_harden_hyp_vecs_start)
     .endr
 ENTRY(__bp_harden_hyp_vecs_end)
 
+ENTRY(__psci_hyp_bp_inval_start)
+    sub     sp, sp, #(8 * 18)
+    stp     x16, x17, [sp, #(16 * 0)]
+    stp     x14, x15, [sp, #(16 * 1)]
+    stp     x12, x13, [sp, #(16 * 2)]
+    stp     x10, x11, [sp, #(16 * 3)]
+    stp     x8, x9, [sp, #(16 * 4)]
+    stp     x6, x7, [sp, #(16 * 5)]
+    stp     x4, x5, [sp, #(16 * 6)]
+    stp     x2, x3, [sp, #(16 * 7)]
+    stp     x0, x1, [sp, #(16 * 8)]
+    mov     x0, #0x84000000
+    smc     #0
+    ldp     x16, x17, [sp, #(16 * 0)]
+    ldp     x14, x15, [sp, #(16 * 1)]
+    ldp     x12, x13, [sp, #(16 * 2)]
+    ldp     x10, x11, [sp, #(16 * 3)]
+    ldp     x8, x9, [sp, #(16 * 4)]
+    ldp     x6, x7, [sp, #(16 * 5)]
+    ldp     x4, x5, [sp, #(16 * 6)]
+    ldp     x2, x3, [sp, #(16 * 7)]
+    ldp     x0, x1, [sp, #(16 * 8)]
+    add     sp, sp, #(8 * 18)
+ENTRY(__psci_hyp_bp_inval_end)
+
 /*
  * Local variables:
  * mode: ASM
diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c
index 76d98e771d..f1ea7f3c5b 100644
--- a/xen/arch/arm/cpuerrata.c
+++ b/xen/arch/arm/cpuerrata.c
@@ -4,8 +4,10 @@ 
 #include <xen/smp.h>
 #include <xen/spinlock.h>
 #include <xen/vmap.h>
+#include <xen/warning.h>
 #include <asm/cpufeature.h>
 #include <asm/cpuerrata.h>
+#include <asm/psci.h>
 
 /* Override macros from asm/page.h to make them work with mfn_t */
 #undef virt_to_mfn
@@ -141,6 +143,31 @@  install_bp_hardening_vec(const struct arm_cpu_capabilities *entry,
     return ret;
 }
 
+extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
+
+static int enable_psci_bp_hardening(void *data)
+{
+    bool ret = true;
+    static bool warned = false;
+
+    /*
+     * The mitigation is using PSCI version function to invalidate the
+     * branch predictor. This function is only available with PSCI 0.2
+     * and later.
+     */
+    if ( psci_ver >= PSCI_VERSION(0, 2) )
+        ret = install_bp_hardening_vec(data, __psci_hyp_bp_inval_start,
+                                       __psci_hyp_bp_inval_end);
+    else if ( !warned )
+    {
+        ASSERT(system_state < SYS_STATE_active);
+        warning_add("PSCI 0.2 or later is required for the branch predictor hardening.\n");
+        warned = true;
+    }
+
+    return !ret;
+}
+
 #endif /* CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR */
 
 #define MIDR_RANGE(model, min, max)     \
@@ -205,6 +232,28 @@  static const struct arm_cpu_capabilities arm_errata[] = {
                    (1 << MIDR_VARIANT_SHIFT) | 2),
     },
 #endif
+#ifdef CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR
+    {
+        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
+        MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
+        .enable = enable_psci_bp_hardening,
+    },
+    {
+        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
+        MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+        .enable = enable_psci_bp_hardening,
+    },
+    {
+        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
+        MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+        .enable = enable_psci_bp_hardening,
+    },
+    {
+        .capability = ARM_HARDEN_BRANCH_PREDICTOR,
+        MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
+        .enable = enable_psci_bp_hardening,
+    },
+#endif
     {},
 };