xen/arm: Correctly save/restore CNTKCTL_EL1
authorJulien Grall <julien.grall@linaro.org>
Thu, 1 May 2014 10:54:40 +0000 (11:54 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Thu, 1 May 2014 10:54:58 +0000 (11:54 +0100)
CNTKCTL_EL1 is used by the guest to control access to the timer from
userspace.  It therefore needs to be save/restored by Xen as part of
the VCPU state.

By default Linux on ARM64 exposes the timer to userspace.  Furthermore on
ARM64, Linux provides helpers in a VDSO (gettimeofday/__do_get_tspec)
that use the timer counter.  Conversely, during CPU bring up, Xen will
set CNTKCTL_EL1 to 0 (i.e disallow timer access to the userspace).  As
a result, currently, if dom0 has 1 VCPU which is migrated to another
PCPU, init might crash.

Alternatively, a guest (malicious or not) might decide to disable
access to the timer from userspace.  If the register is not
save/restored, when a DOM0 VCPU runs again, a similar crash would
result.

Also, drop CNTKCTL_EL1 initialization in init_timer_interrupt.  Xen
should let the guest deal with this register.

This is XSA-91 / CVE-2014-3125.

Reported-by: Chen Baozi <baozich@gmail.com>
Signed-off-by: Julien Grall <julien.grall@linaro.org>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
xen/arch/arm/domain.c
xen/arch/arm/time.c
xen/include/asm-arm/domain.h

index ccccb77af378048d24de94b3d92817af51d0ddb2..3faf7a69fd9396f35cf7d54384d15af2e70881b8 100644 (file)
@@ -73,6 +73,7 @@ static void ctxt_switch_from(struct vcpu *p)
     p->arch.tpidr_el1 = READ_SYSREG(TPIDR_EL1);
 
     /* Arch timer */
+    p->arch.cntkctl = READ_SYSREG32(CNTKCTL_EL1);
     virt_timer_save(p);
 
     if ( is_32bit_domain(p->domain) && cpu_has_thumbee )
@@ -209,6 +210,7 @@ static void ctxt_switch_to(struct vcpu *n)
 
     /* This is could trigger an hardware interrupt from the virtual
      * timer. The interrupt needs to be injected into the guest. */
+    WRITE_SYSREG32(n->arch.cntkctl, CNTKCTL_EL1);
     virt_timer_restore(n);
 }
 
index 8dd4bea17ac8376019c156fbb45415d21e708e12..9f0adeb460df8d4d06d996663ec6c0594a840416 100644 (file)
@@ -234,7 +234,6 @@ void __cpuinit init_timer_interrupt(void)
 {
     /* Sensible defaults */
     WRITE_SYSREG64(0, CNTVOFF_EL2);     /* No VM-specific offset */
-    WRITE_SYSREG32(0, CNTKCTL_EL1);     /* No user-mode access */
 #if USE_HYP_TIMER
     /* Do not let the VMs program the physical timer, only read the physical counter */
     WRITE_SYSREG32(CNTHCTL_PA, CNTHCTL_EL2);
index ec66a4e9e913d0a798473ad6cdcc2ef8d2f72540..aabeb51ae415967627be13b1f100fe424a293bbb 100644 (file)
@@ -283,6 +283,9 @@ struct arch_vcpu
         spinlock_t lock;
     } vgic;
 
+    /* Timer registers  */
+    uint32_t cntkctl;
+
     struct vtimer phys_timer;
     struct vtimer virt_timer;
 }  __cacheline_aligned;