summaryrefslogtreecommitdiffstats
path: root/system/xen/xsa/xsa201-4.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/xsa/xsa201-4.patch')
-rw-r--r--system/xen/xsa/xsa201-4.patch130
1 files changed, 130 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa201-4.patch b/system/xen/xsa/xsa201-4.patch
new file mode 100644
index 0000000000..8060a5be13
--- /dev/null
+++ b/system/xen/xsa/xsa201-4.patch
@@ -0,0 +1,130 @@
+From: Wei Chen <Wei.Chen@arm.com>
+Subject: arm32: handle async aborts delivered while at HYP
+
+If guest generates an asynchronous abort and then traps into HYP
+(by HVC or IRQ) before the abort has been delivered, the hypervisor
+could not catch it, because the PSTATE.A bit is masked all the time
+in hypervisor. So this asynchronous abort may be slipped to next
+running guest with PSTATE.A bit unmasked.
+
+In order to avoid this, it is necessary to take the abort at HYP, by
+clearing the PSTATE.A bit. In this patch, we unmask the PSTATE.A bit
+to open a window to catch guest-generated asynchronous abort in all
+Guest -> HYP switch paths. If we caught such asynchronous abort in
+checking window, the HYP data abort exception will be triggered and
+the abort source guest will be crashed.
+
+This is CVE-2016-9818, part of XSA-201.
+
+Signed-off-by: Wei Chen <Wei.Chen@arm.com>
+Reviewed-by: Julien Grall <julien.grall@arm.com>
+
+--- a/xen/arch/arm/arm32/entry.S
++++ b/xen/arch/arm/arm32/entry.S
+@@ -42,6 +42,61 @@ save_guest_regs:
+ SAVE_BANKED(fiq)
+ SAVE_ONE_BANKED(R8_fiq); SAVE_ONE_BANKED(R9_fiq); SAVE_ONE_BANKED(R10_fiq)
+ SAVE_ONE_BANKED(R11_fiq); SAVE_ONE_BANKED(R12_fiq);
++ /*
++ * Start to check pending virtual abort in the gap of Guest -> HYP
++ * world switch.
++ *
++ * Save ELR_hyp to check whether the pending virtual abort exception
++ * takes place while we are doing this trap exception.
++ */
++ mrs r1, ELR_hyp
++
++ /*
++ * Force loads and stores to complete before unmasking asynchronous
++ * aborts and forcing the delivery of the exception.
++ */
++ dsb sy
++
++ /*
++ * Unmask asynchronous abort bit. If there is a pending asynchronous
++ * abort, the data_abort exception will happen after A bit is cleared.
++ */
++ cpsie a
++
++ /*
++ * This is our single instruction exception window. A pending
++ * asynchronous abort is guaranteed to occur at the earliest when we
++ * unmask it, and at the latest just after the ISB.
++ *
++ * If a pending abort occurs, the program will jump to data_abort
++ * exception handler, and the ELR_hyp will be set to
++ * abort_guest_exit_start or abort_guest_exit_end.
++ */
++ .global abort_guest_exit_start
++abort_guest_exit_start:
++
++ isb
++
++ .global abort_guest_exit_end
++abort_guest_exit_end:
++ /* Mask CPSR asynchronous abort bit, close the checking window. */
++ cpsid a
++
++ /*
++ * Compare ELR_hyp and the saved value to check whether we are
++ * returning from a valid exception caused by pending virtual
++ * abort.
++ */
++ mrs r2, ELR_hyp
++ cmp r1, r2
++
++ /*
++ * Not equal, the pending virtual abort exception took place, the
++ * initial exception does not have any significance to be handled.
++ * Exit ASAP.
++ */
++ bne return_from_trap
++
+ mov pc, lr
+
+ #define DEFINE_TRAP_ENTRY(trap) \
+--- a/xen/arch/arm/arm32/traps.c
++++ b/xen/arch/arm/arm32/traps.c
+@@ -63,7 +63,10 @@ asmlinkage void do_trap_prefetch_abort(struct cpu_user_regs *regs)
+
+ asmlinkage void do_trap_data_abort(struct cpu_user_regs *regs)
+ {
+- do_unexpected_trap("Data Abort", regs);
++ if ( VABORT_GEN_BY_GUEST(regs) )
++ do_trap_guest_error(regs);
++ else
++ do_unexpected_trap("Data Abort", regs);
+ }
+
+ /*
+--- a/xen/include/asm-arm/arm32/processor.h
++++ b/xen/include/asm-arm/arm32/processor.h
+@@ -55,6 +55,17 @@ struct cpu_user_regs
+
+ uint32_t pad1; /* Doubleword-align the user half of the frame */
+ };
++
++/* Functions for pending virtual abort checking window. */
++void abort_guest_exit_start(void);
++void abort_guest_exit_end(void);
++
++#define VABORT_GEN_BY_GUEST(r) \
++( \
++ ( (unsigned long)abort_guest_exit_start == (r)->pc ) || \
++ ( (unsigned long)abort_guest_exit_end == (r)->pc ) \
++)
++
+ #endif
+
+ /* Layout as used in assembly, with src/dest registers mixed in */
+--- a/xen/include/asm-arm/processor.h
++++ b/xen/include/asm-arm/processor.h
+@@ -690,6 +690,8 @@ void vcpu_regs_user_to_hyp(struct vcpu *vcpu,
+ int call_smc(register_t function_id, register_t arg0, register_t arg1,
+ register_t arg2);
+
++void do_trap_guest_error(struct cpu_user_regs *regs);
++
+ #endif /* __ASSEMBLY__ */
+ #endif /* __ASM_ARM_PROCESSOR_H */
+ /*