Xen Security Advisory 91 - Hardware timer context is not properly context switched on ARM

Xen.org security team <[email protected]>
Newsgroups gmane.comp.emulators.xen.announce
Message-ID <E1WfTQw-0003kR-8R__19975.6149355837$1398860703$gmane$org@xenbits.xen.org>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

                     Xen Security Advisory XSA-91
                               version 2

    Hardware timer context is not properly context switched on ARM

UPDATES IN VERSION 2
====================

Public release.

ISSUE DESCRIPTION
=================

When running on an ARM platform Xen was not context switching the
CNTKCTL_EL1 register, which is used by the guest kernel to control
access by userspace processes to the hardware timers. This meant that
any guest can reconfigure these settings for the entire system.

IMPACT
======

A malicious guest kernel can reconfigure CNTKCTL_EL1 to block
userspace access to the timer hardware for all domains, including
control domains. Depending on the other guest kernels in use this may
cause an unexpected exception in those guests which may lead to a
kernel crash and therefore a denial of service.

64-bit ARM Linux is known to be susceptible to crashing in this way.

A malicious guest kernel can also enable userspace access to the timer
control registers, which may not be expected by kernels running in
other domains. This can allow user processes to reprogram timer
interrupts and therefore lead to unexpected behaviour, potentially up
to and including crashing the guest. Userspace processes will also be
able to read the current timestamp value for the domain perhaps
leaking information to those processes.

VULNERABLE SYSTEMS
==================

Both 32- and 64-bit ARM systems are vulnerable from Xen 4.4 onwards.

x86 systems are not vulnerable.

MITIGATION
==========

None.

CREDITS
=======

Chen Baozi discovered this issue as a bug which was then diagnosed by
Julien Grall.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

xsa91-unstable.patch                  xen-unstable
xsa91-4.4.patch                       Xen 4.4.x

$ sha256sum xsa91*.patch
8a3dc1f001274550acfe929a0a443b09f8164001f6eea76821bd87292b8732e0  xsa91-4.4.patch
327ccd88f2d9bc21daf51f3e5c81cbae2e779a6f997715d9d0d95285c509ecbd  xsa91-unstable.patch
$
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iQEcBAEBAgAGBQJTYMejAAoJEIP+FMlX6CvZ3oMH/j+7Ln89gf0rvyvwUAwK7EUj
AD2fR/OSXQJVs4g0fZDSft4wgsIpbnbvcCl06tK98XAZH8Cyr0burQV4rXgQbM9e
rWYRpfy4mWt7RNvwdgeBYecuEYvFIULmMC1hI+eJRtJTrB8UnpCvXLPbFktp2zXP
Z+pPjck/dAjS8HKJZckL5ciy9ctTr1R50NmpqvW9FfeZAVhahmbmMiz3A5izQEQ0
BppXWdRad2J5vcR2u8k3uxweUfWM1Yg/eQAmMVvWPS45ceH+UHgqaGngBzWlM9oV
SwqCDl0/8DjcQziFnKx5cdYcXfFbTzqV7SP5OzcV2BRoSvGZOVDowaXsqvt1jME=
=LkmE
-----END PGP SIGNATURE-----

_______________________________________________
Xen-announce mailing list
[email protected]
http://lists.xen.org/xen-announce
xsa91-4.4.patch (application/octet-stream, 2.7 KB)
xen/arm: Correctly save/restore CNTKCTL_EL1

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.

Reported-by: Chen Baozi <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Signed-off-by: Ian Jackson <[email protected]>
Acked-by: Ian Campbell <[email protected]>

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 3a6cc50..db4b60d 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -72,6 +72,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_pv32_domain(p->domain) && cpu_has_thumbee )
@@ -224,6 +225,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);
 }
 
diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index 6bbe980..fca1387 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -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);
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 50b9b54..4dc1d5a 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -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;
xsa91-unstable.patch (application/octet-stream, 2.7 KB)
xen/arm: Correctly save/restore CNTKCTL_EL1

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.

Reported-by: Chen Baozi <[email protected]>
Signed-off-by: Julien Grall <[email protected]>
Signed-off-by: Ian Jackson <[email protected]>
Acked-by: Ian Campbell <[email protected]>

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 3a6cc50..db4b60d 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -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);
 }
 
diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index 6bbe980..fca1387 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -223,7 +223,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);
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 50b9b54..4dc1d5a 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -289,6 +289,9 @@ struct arch_vcpu
         spinlock_t lock;
     } vgic;
 
+    /* Timer registers  */
+    uint32_t cntkctl;
+
     struct vtimer phys_timer;
     struct vtimer virt_timer;
 }  __cacheline_aligned;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.