[xen stable-4.6] xen/arm32: Add skeleton to harden branch predictor aliasing attacks

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[xen stable-4.6] xen/arm32: Add skeleton to harden branch predictor aliasing attacks

patchbot
commit 8005ed3ef14c6c8b31a9e1a5ae2576a4b4c66528
Author:     Julien Grall <[hidden email]>
AuthorDate: Fri Feb 2 14:19:22 2018 +0000
Commit:     Stefano Stabellini <[hidden email]>
CommitDate: Mon Feb 19 14:16:36 2018 -0800

    xen/arm32: Add skeleton to harden branch predictor aliasing attacks
   
    Aliasing attacked against CPU branch predictors can allow an attacker to
    redirect speculative control flow on some CPUs and potentially divulge
    information from one context to another.
   
    This patch adds initiatial skeleton code behind a new Kconfig option
    to enable implementation-specific mitigations against these attacks
    for CPUs that are affected.
   
    Most of mitigations will have to be applied when entering to the
    hypervisor from the guest context.
   
    Because the attack is against branch predictor, it is not possible to
    safely use branch instruction before the mitigation is applied.
    Therefore this has to be done in the vector entry before jump to the
    helper handling a given exception.
   
    However, on arm32, each vector contain a single instruction. This means
    that the hardened vector tables may rely on the state of registers that
    does not hold when in the hypervisor (e.g SP is 8 bytes aligned).
    Therefore hypervisor code running with guest vectors table should be
    minimized and always have IRQs and SErrors masked to reduce the risk to
    use them.
   
    This patch provides an infrastructure to switch vector tables before
    entering to the guest and when leaving it.
   
    Note that alternative could have been used, but older Xen (4.8 or
    earlier) doesn't have support. So avoid using alternative to ease
    backporting.
   
    This is part of XSA-254.
   
    Signed-off-by: Julien Grall <[hidden email]>
    Reviewed-by: Stefano Stabellini <[hidden email]>
    (cherry picked from commit 9bd4463b5c7cc026a07b9bbd41a6a7122a95647e)
---
 config/arm32.mk            |  3 +++
 xen/arch/arm/arm32/entry.S | 41 ++++++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/cpuerrata.c   | 30 ++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/config/arm32.mk b/config/arm32.mk
index cd97e42881..2c2f5637fd 100644
--- a/config/arm32.mk
+++ b/config/arm32.mk
@@ -16,6 +16,9 @@ HAS_SCIF := y
 HAS_NS16550 := y
 HAS_MEM_ACCESS := y
 
+CONFIG_HARDEN_BRANCH_PREDICTOR := y
+CONFIG_ARM32_HARDEN_BRANCH_PREDICTOR := y
+
 # Use only if calling $(LD) directly.
 LDFLAGS_DIRECT += -EL
 
diff --git a/xen/arch/arm/arm32/entry.S b/xen/arch/arm/arm32/entry.S
index c5fec60e44..97cfa4cd27 100644
--- a/xen/arch/arm/arm32/entry.S
+++ b/xen/arch/arm/arm32/entry.S
@@ -34,6 +34,20 @@
         blne save_guest_regs
 
 save_guest_regs:
+#ifdef CONFIG_ARM32_HARDEN_BRANCH_PREDICTOR
+        /*
+         * Restore vectors table to the default as it may have been
+         * changed when returning to the guest (see
+         * return_to_hypervisor). We need to do that early (e.g before
+         * any interrupts are unmasked) because hardened vectors requires
+         * SP to be 8 bytes aligned. This does not hold when running in
+         * the hypervisor.
+         */
+        ldr r1, =hyp_traps_vector
+        mcr p15, 4, r1, c12, c0, 0
+        isb
+#endif
+
         ldr r11, =0xffffffff  /* Clobber SP which is only valid for hypervisor frames. */
         str r11, [sp, #UREGS_sp]
         SAVE_ONE_BANKED(SP_usr)
@@ -167,12 +181,37 @@ return_to_guest:
         RESTORE_ONE_BANKED(R11_fiq); RESTORE_ONE_BANKED(R12_fiq);
         /* Fall thru */
 return_to_hypervisor:
-        cpsid i
+        cpsid ai
         ldr lr, [sp, #UREGS_lr]
         ldr r11, [sp, #UREGS_pc]
         msr ELR_hyp, r11
         ldr r11, [sp, #UREGS_cpsr]
         msr SPSR_hyp, r11
+#ifdef CONFIG_ARM32_HARDEN_BRANCH_PREDICTOR
+        /*
+         * Hardening branch predictor may require to setup a different
+         * vector tables before returning to the guests. Those vectors
+         * may rely on the state of registers that does not hold when
+         * running in the hypervisor (e.g SP is 8 bytes aligned). So setup
+         * HVBAR very late.
+         *
+         * Default vectors table will be restored on exit (see
+         * save_guest_regs).
+         */
+        mov r9, #0                      /* vector tables = NULL */
+        /*
+         * Load vector tables pointer from the per-cpu bp_harden_vecs
+         * when returning to the guest only.
+         */
+        and r11, #PSR_MODE_MASK
+        cmp r11, #PSR_MODE_HYP
+        ldrne r11, =per_cpu__bp_harden_vecs
+        mrcne p15, 4, r10, c13, c0, 2   /* r10 = per-cpu offset (HTPIDR) */
+        addne r11, r11, r10             /* r11 = offset of the vector tables */
+        ldrne r9, [r11]                 /* r9  = vector tables */
+        cmp r9, #0                      /* Only update HVBAR when the vector */
+        mcrne p15, 4, r9, c12, c0, 0    /* tables is not NULL. */
+#endif
         pop {r0-r12}
         add sp, #(UREGS_SP_usr - UREGS_sp); /* SP, LR, SPSR, PC */
         clrex
diff --git a/xen/arch/arm/cpuerrata.c b/xen/arch/arm/cpuerrata.c
index 68e99934e3..97d36a2643 100644
--- a/xen/arch/arm/cpuerrata.c
+++ b/xen/arch/arm/cpuerrata.c
@@ -166,6 +166,36 @@ static int enable_psci_bp_hardening(void *data)
 
 #endif /* CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR */
 
+/* Hardening Branch predictor code for Arm32 */
+#ifdef CONFIG_ARM32_HARDEN_BRANCH_PREDICTOR
+
+/*
+ * Per-CPU vector tables to use when returning to the guests. They will
+ * only be used on platform requiring to harden the branch predictor.
+ */
+DEFINE_PER_CPU_READ_MOSTLY(const char *, bp_harden_vecs);
+
+extern char hyp_traps_vector_bp_inv[];
+
+static void __maybe_unused
+install_bp_hardening_vecs(const struct arm_cpu_capabilities *entry,
+                          const char *hyp_vecs, const char *desc)
+{
+    /*
+     * Enable callbacks are called on every CPU based on the
+     * capabilities. So double-check whether the CPU matches the
+     * entry.
+     */
+    if ( !entry->matches(entry) )
+        return;
+
+    printk(XENLOG_INFO "CPU%u will %s on guest exit\n",
+           smp_processor_id(), desc);
+    this_cpu(bp_harden_vecs) = hyp_vecs;
+}
+
+#endif
+
 #define MIDR_RANGE(model, min, max)     \
     .matches = is_affected_midr_range,  \
     .midr_model = model,                \
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.6

_______________________________________________
Xen-changelog mailing list
[hidden email]
https://lists.xenproject.org/xen-changelog