Xen Security Advisory 102 (CVE-2014-5147) - Flaws in handling traps from 32-bit userspace on 64-bit ARM

Xen.org security team <[email protected]>
Newsgroups gmane.comp.emulators.xen.announce
Message-ID <E1XHBje-00086k-FW__17959.9550240257$1407849226$gmane$org@xenbits.xen.org>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

              Xen Security Advisory CVE-2014-5147 / XSA-102
                              version 3

       Flaws in handling traps from 32-bit userspace on 64-bit ARM

UPDATES IN VERSION 3
====================

Public release.

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

When handling a trap from guest mode on ARM, Xen asserts that the
current guest mode must match the domain address width.  This
assertion is false when a guest takes a trap from a 32-bit userspace
running on a 64-bit kernel in a 64-bit domain.

IMPACT
======

Any user in a guest which is running a 64-bit kernel who is able to
spawn a 32-bit process can crash the host.  I.e. an unprivileged guest
user can cause host-wide denial of service.

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

32-bit ARM systems and and X86 systems are not vulnerable.

64-bit ARM systems which support 32-bit userspace are vulnerable.

Not all 64-bit ARM CPUs support 32-bit userspace in the actual CPU
hardware.  Systems without that hardware support are not vulnerable.

Also, not all 64-bit ARM guest kernels have support for 32-bit
userspace.  Systems without that kernel support are vulnerable to a
malicious guest administrator, but not to an unprivileged guest user.

MITIGATION
==========

On systems where the guest kernel is controlled by the host rather than
guest administrator, running only 32-bit kernels.

On systems where the guest kernel is controlled by the host rather than
guest administrator, running 64-bit kernels with support for 32-bit
userspace disabled (e.g CONFIG_COMPAT=n under Linux) will prevent untrusted
guest users from exploting this issue. However untrusted guest
administrators can still trigger it unless further steps are taken to
prevent them from loading code into the kernel (e.g. by disabling loadable
modules etc) or from using other mechanisms which allow them to run code at
kernel privilege.

CREDITS
=======

This issue was reported as a bug by Riku Voipio, discovered via
Linaro's LAVA testing and was diagnosed as a security issue by Ian
Campbell.

RESOLUTION
==========

Applying the appropriate attached patches resolves these security
issues.

xsa102-unstable-*.patch        xen-unstable
xsa102-4.4-*.patch             Xen 4.4.x

$ sha256sum xsa102*.patch
a5beb5c552e5bffe3e115905c478d6699c35df1d8721f8d6681099c38a974091  xsa102-4.4-01.patch
9f04ecda4dd9e31360daa27d87588d6017d866a97b84566241097def0af86a63  xsa102-4.4-02.patch
a9860803ed5ed57bdc3ac94cdc924618b19e805b7f6a87bf9c1a9ea4b627281a  xsa102-4.4-03.patch
7d0b5e05e5915c6c2d83590ba9acab0acfd1eba986a65a20ba69cf2c3394e062  xsa102-unstable-01.patch
7d5cf339a3f8c98b3e06852f845a2305df3f8ce195d243ee22d6783bb6904d60  xsa102-unstable-02.patch
3ca7b0632af36cc72ba59ed1822bcaebf2363f150435348265d1ade25e21bf90  xsa102-unstable-03.patch
$
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iQEcBAEBAgAGBQJT6hBqAAoJEIP+FMlX6CvZDi0H/jFJPRxBIglzATvMDaho19fw
Ao1OHP99dZn3XkKf/qfw4v90KttCEp5+3uQo34hhXNTLkvbm5KCsZDjOdL812d3G
JjvEBWnU7480Av0QkvsYVoH+yjks0PIu6xEI+kQqKAAG4vbVxTi5ORg7HMkeOKAY
5Uyj5xjWi5JRn+V8pYcUr9wZZlvhEAuDbVATeg9dH6+FyH/4V9viNWWHBePi3Ocn
HWPt7U/Cv55wLIxfjmw27C5Te3b/xNjxy9hk+1XrGMafiO7FU1ntgHmqswqN+lBR
beORG0dRNl0fU6QY8dakssYzjwA0jgV9HKoonbUGlp+fPxRl2pNuoe7Mvn/y1nU=
=Iuvx
-----END PGP SIGNATURE-----

_______________________________________________
Xen-announce mailing list
[email protected]
http://lists.xen.org/xen-announce
xsa102-4.4-01.patch (application/octet-stream, 1.5 KB)
From 9f73c5d122b7fa0785e823cb203ec773caec7640 Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Fri, 18 Jul 2014 14:13:14 +0100
Subject: [PATCH 1/3] xen: arm: handle AArch32 userspace when dumping 64-bit
 guest state.

A 64-bit guest can still be in 32-bit mode when running userspace,
handle this case by dumping the correct 32-bit state.

Note that on ARM it is not possible to change mode without the help
of the next exception level, hence there is no way a 64-bit guest can
be running in 32-bit kernel modes.

This is part of XSA-102.

Signed-off-by: Ian Campbell <[email protected]>
Acked-by: Julien Grall <[email protected]>
---
 xen/arch/arm/traps.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index e2e2db3..7367399 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -697,7 +697,17 @@ static void _show_registers(struct cpu_user_regs *regs,
             show_registers_32(regs, ctxt, guest_mode, v);
 #ifdef CONFIG_ARM_64
         else if ( is_pv64_domain(v->domain) )
-            show_registers_64(regs, ctxt, guest_mode, v);
+        {
+            if ( psr_mode_is_32bit(regs->cpsr) )
+            {
+                BUG_ON(!usr_mode(regs));
+                show_registers_32(regs, ctxt, guest_mode, v);
+            }
+            else
+            {
+                show_registers_64(regs, ctxt, guest_mode, v);
+            }
+        }
 #endif
     }
     else
-- 
1.7.10.4
xsa102-4.4-02.patch (application/octet-stream, 7.7 KB)
From 64d68fc59f1341e36c595df21512c5b2a5ccde6f Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Tue, 22 Jul 2014 11:31:54 +0100
Subject: [PATCH 2/3] xen: arm: Correctly handle exception injection from
 userspace on 64-bit.

Firstly we must be prepared to propagate traps from 32-bit userspace even for
64-bit guests, so wrap the existing inject_undef??_exception into
inject_undef_exception and use that when injecting an undef exception. The
various other exception cases (aborts etc) already do this.

Secondly when injecting the trap we must pick the correct exception vector
depending on whether the source of the trap was 32-bit EL0, 64-bit EL0 or EL1.

This is part of XSA-102.

Signed-off-by: Ian Campbell <[email protected]>
Acked-by: Julien Grall <[email protected]>
---
 xen/arch/arm/traps.c            |   57 +++++++++++++++++++++++++++++++--------
 xen/include/asm-arm/processor.h |   18 +++++++------
 2 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 7367399..6536209 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -286,7 +286,7 @@ static void cpsr_switch_mode(struct cpu_user_regs *regs, int mode)
         regs->cpsr |= PSR_BIG_ENDIAN;
 }
 
-static vaddr_t exception_handler(vaddr_t offset)
+static vaddr_t exception_handler32(vaddr_t offset)
 {
     uint32_t sctlr = READ_SYSREG32(SCTLR_EL1);
 
@@ -318,7 +318,7 @@ static void inject_undef32_exception(struct cpu_user_regs *regs)
     regs->lr_und = regs->pc32 + return_offset;
 
     /* Branch to exception vector */
-    regs->pc32 = exception_handler(VECTOR32_UND);
+    regs->pc32 = exception_handler32(VECTOR32_UND);
 }
 
 /* Injects an Abort exception into the current vcpu, PC is the exact
@@ -344,7 +344,7 @@ static void inject_abt32_exception(struct cpu_user_regs *regs,
     regs->spsr_abt = spsr;
     regs->lr_abt = regs->pc32 + return_offset;
 
-    regs->pc32 = exception_handler(prefetch ? VECTOR32_PABT : VECTOR32_DABT);
+    regs->pc32 = exception_handler32(prefetch ? VECTOR32_PABT : VECTOR32_DABT);
 
     /* Inject a debug fault, best we can do right now */
     if ( READ_SYSREG(TCR_EL1) & TTBCR_EAE )
@@ -397,9 +397,28 @@ static void inject_pabt32_exception(struct cpu_user_regs *regs,
 }
 
 #ifdef CONFIG_ARM_64
+/*
+ * Take care to call this while regs contains the original faulting
+ * state and not the (partially constructed) exception state.
+ */
+static vaddr_t exception_handler64(struct cpu_user_regs *regs, vaddr_t offset)
+{
+    vaddr_t base = READ_SYSREG(VBAR_EL1);
+
+    if ( usr_mode(regs) )
+        base += VECTOR64_LOWER32_BASE;
+    else if ( psr_mode(regs->cpsr,PSR_MODE_EL0t) )
+        base += VECTOR64_LOWER64_BASE;
+    else /* Otherwise must be from kernel mode */
+        base += VECTOR64_CURRENT_SPx_BASE;
+
+    return base + offset;
+}
+
 /* Inject an undefined exception into a 64 bit guest */
 static void inject_undef64_exception(struct cpu_user_regs *regs, int instr_len)
 {
+    vaddr_t handler;
     union hsr esr = {
         .iss = 0,
         .len = instr_len,
@@ -408,12 +427,14 @@ static void inject_undef64_exception(struct cpu_user_regs *regs, int instr_len)
 
     BUG_ON( is_pv32_domain(current->domain) );
 
+    handler = exception_handler64(regs, VECTOR64_SYNC_OFFSET);
+
     regs->spsr_el1 = regs->cpsr;
     regs->elr_el1 = regs->pc;
 
     regs->cpsr = PSR_MODE_EL1h | PSR_ABT_MASK | PSR_FIQ_MASK | \
         PSR_IRQ_MASK | PSR_DBG_MASK;
-    regs->pc = READ_SYSREG(VBAR_EL1) + VECTOR64_CURRENT_SPx_SYNC;
+    regs->pc = handler;
 
     WRITE_SYSREG32(esr.bits, ESR_EL1);
 }
@@ -424,6 +445,7 @@ static void inject_abt64_exception(struct cpu_user_regs *regs,
                                    register_t addr,
                                    int instr_len)
 {
+    vaddr_t handler;
     union hsr esr = {
         .iss = 0,
         .len = instr_len,
@@ -445,12 +467,14 @@ static void inject_abt64_exception(struct cpu_user_regs *regs,
 
     BUG_ON( is_pv32_domain(current->domain) );
 
+    handler = exception_handler64(regs, VECTOR64_SYNC_OFFSET);
+
     regs->spsr_el1 = regs->cpsr;
     regs->elr_el1 = regs->pc;
 
     regs->cpsr = PSR_MODE_EL1h | PSR_ABT_MASK | PSR_FIQ_MASK | \
         PSR_IRQ_MASK | PSR_DBG_MASK;
-    regs->pc = READ_SYSREG(VBAR_EL1) + VECTOR64_CURRENT_SPx_SYNC;
+    regs->pc = handler;
 
     WRITE_SYSREG(addr, FAR_EL1);
     WRITE_SYSREG32(esr.bits, ESR_EL1);
@@ -472,6 +496,17 @@ static void inject_iabt64_exception(struct cpu_user_regs *regs,
 
 #endif
 
+static void inject_undef_exception(struct cpu_user_regs *regs,
+                                   int instr_len)
+{
+        if ( is_pv32_domain(current->domain) )
+            inject_undef32_exception(regs);
+#ifdef CONFIG_ARM_64
+        else
+            inject_undef64_exception(regs, instr_len);
+#endif
+}
+
 static void inject_iabt_exception(struct cpu_user_regs *regs,
                                   register_t addr,
                                   int instr_len)
@@ -1440,7 +1475,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
         gdprintk(XENLOG_ERR, "unhandled 32-bit CP15 access %#x\n",
                  hsr.bits & HSR_CP32_REGS_MASK);
 #endif
-        inject_undef32_exception(regs);
+        inject_undef_exception(regs, hsr.len);
         return;
     }
     advance_pc(regs, hsr);
@@ -1477,7 +1512,7 @@ static void do_cp15_64(struct cpu_user_regs *regs,
             gdprintk(XENLOG_ERR, "unhandled 64-bit CP15 access %#x\n",
                      hsr.bits & HSR_CP64_REGS_MASK);
 #endif
-            inject_undef32_exception(regs);
+            inject_undef_exception(regs, hsr.len);
             return;
         }
     }
@@ -1546,7 +1581,7 @@ bad_cp:
         gdprintk(XENLOG_ERR, "unhandled 32-bit cp14 access %#x\n",
                  hsr.bits & HSR_CP32_REGS_MASK);
 #endif
-        inject_undef32_exception(regs);
+        inject_undef_exception(regs, hsr.len);
         return;
     }
 
@@ -1561,7 +1596,7 @@ static void do_cp14_dbg(struct cpu_user_regs *regs, union hsr hsr)
         return;
     }
 
-    inject_undef32_exception(regs);
+    inject_undef_exception(regs, hsr.len);
 }
 
 static void do_cp(struct cpu_user_regs *regs, union hsr hsr)
@@ -1572,7 +1607,7 @@ static void do_cp(struct cpu_user_regs *regs, union hsr hsr)
         return;
     }
 
-    inject_undef32_exception(regs);
+    inject_undef_exception(regs, hsr.len);
 }
 
 #ifdef CONFIG_ARM_64
@@ -1647,7 +1682,7 @@ static void do_sysreg(struct cpu_user_regs *regs,
             gdprintk(XENLOG_ERR, "unhandled 64-bit sysreg access %#x\n",
                      hsr.bits & HSR_SYSREG_REGS_MASK);
 #endif
-            inject_undef64_exception(regs, sysreg.len);
+            inject_undef_exception(regs, sysreg.len);
         }
     }
 
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 9267c1b..1f158ce 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -432,14 +432,16 @@ union hsr {
 #define VECTOR32_PABT 12
 #define VECTOR32_DABT 16
 /* ... ARM64 */
-#define VECTOR64_CURRENT_SP0_SYNC  0x000
-#define VECTOR64_CURRENT_SP0_IRQ   0x080
-#define VECTOR64_CURRENT_SP0_FIQ   0x100
-#define VECTOR64_CURRENT_SP0_ERROR 0x180
-#define VECTOR64_CURRENT_SPx_SYNC  0x200
-#define VECTOR64_CURRENT_SPx_IRQ   0x280
-#define VECTOR64_CURRENT_SPx_FIQ   0x300
-#define VECTOR64_CURRENT_SPx_ERROR 0x380
+#define VECTOR64_CURRENT_SP0_BASE  0x000
+#define VECTOR64_CURRENT_SPx_BASE  0x200
+#define VECTOR64_LOWER64_BASE      0x400
+#define VECTOR64_LOWER32_BASE      0x600
+
+#define VECTOR64_SYNC_OFFSET       0x000
+#define VECTOR64_IRQ_OFFSET        0x080
+#define VECTOR64_FIQ_OFFSET        0x100
+#define VECTOR64_ERROR_OFFSET      0x180
+
 
 #if defined(CONFIG_ARM_32)
 # include <asm/arm32/processor.h>
-- 
1.7.10.4
xsa102-4.4-03.patch (application/octet-stream, 1.4 KB)
From 08a6895af8535b852ff4368c30a0c968a69ab1ad Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Thu, 24 Jul 2014 12:28:22 +0100
Subject: [PATCH 3/3] xen: arm: Handle traps from 32-bit userspace on 64-bit
 kernel as undef

We are not setup to handle these properly. This turns a host crash
into a trap to the guest kernel which will likely result in killing
the offending process.

This is part of XSA-102.

Signed-off-by: Ian Campbell <[email protected]>
Acked-by: Julien Grall <[email protected]>
---
 xen/arch/arm/traps.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 6536209..e763f12 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1812,6 +1812,17 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
 {
     union hsr hsr = { .bits = READ_SYSREG32(ESR_EL2) };
 
+    /*
+     * We currently do not handle 32-bit userspace on 64-bit kernels
+     * correctly (See XSA-102). Until that is resolved we treat any
+     * trap from 32-bit userspace on 64-bit kernel as undefined.
+     */
+    if ( is_pv64_domain(current->domain) && psr_mode_is_32bit(regs->cpsr) )
+    {
+        inject_undef_exception(regs, hsr.len);
+        return;
+    }
+
     switch (hsr.ec) {
     case HSR_EC_WFI_WFE:
         if ( !check_conditional_instr(regs, hsr) )
-- 
1.7.10.4
xsa102-unstable-01.patch (application/octet-stream, 1.5 KB)
From b0ee68ca981d9fe1f5e9fe7c1476921d8f8bdaf7 Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Fri, 18 Jul 2014 14:13:14 +0100
Subject: [PATCH 1/3] xen: arm: handle AArch32 userspace when dumping 64-bit
 guest state.

A 64-bit guest can still be in 32-bit mode when running userspace,
handle this case by dumping the correct 32-bit state.

Note that on ARM it is not possible to change mode without the help
of the next exception level, hence there is no way a 64-bit guest can
be running in 32-bit kernel modes.

This is part of XSA-102.

Signed-off-by: Ian Campbell <[email protected]>
Acked-by: Julien Grall <[email protected]>
---
 xen/arch/arm/traps.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 3dfabd0..e104509 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -697,7 +697,17 @@ static void _show_registers(struct cpu_user_regs *regs,
             show_registers_32(regs, ctxt, guest_mode, v);
 #ifdef CONFIG_ARM_64
         else if ( is_64bit_domain(v->domain) )
-            show_registers_64(regs, ctxt, guest_mode, v);
+        {
+            if ( psr_mode_is_32bit(regs->cpsr) )
+            {
+                BUG_ON(!usr_mode(regs));
+                show_registers_32(regs, ctxt, guest_mode, v);
+            }
+            else
+            {
+                show_registers_64(regs, ctxt, guest_mode, v);
+            }
+        }
 #endif
     }
     else
-- 
1.7.10.4
xsa102-unstable-02.patch (application/octet-stream, 7.9 KB)
From 2c2587ed74f6b116d2839d9d51ba88677d6414ef Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Tue, 22 Jul 2014 11:31:54 +0100
Subject: [PATCH 2/3] xen: arm: Correctly handle exception injection from
 userspace on 64-bit.

Firstly we must be prepared to propagate traps from 32-bit userspace even for
64-bit guests, so wrap the existing inject_undef??_exception into
inject_undef_exception and use that when injecting an undef exception. The
various other exception cases (aborts etc) already do this.

Secondly when injecting the trap we must pick the correct exception vector
depending on whether the source of the trap was 32-bit EL0, 64-bit EL0 or EL1.

This is part of XSA-102.

Signed-off-by: Ian Campbell <[email protected]>
Acked-by: Julien Grall <[email protected]>
---
 xen/arch/arm/traps.c            |   57 +++++++++++++++++++++++++++++++--------
 xen/include/asm-arm/processor.h |   18 +++++++------
 2 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index e104509..abaee62 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -286,7 +286,7 @@ static void cpsr_switch_mode(struct cpu_user_regs *regs, int mode)
         regs->cpsr |= PSR_BIG_ENDIAN;
 }
 
-static vaddr_t exception_handler(vaddr_t offset)
+static vaddr_t exception_handler32(vaddr_t offset)
 {
     uint32_t sctlr = READ_SYSREG32(SCTLR_EL1);
 
@@ -318,7 +318,7 @@ static void inject_undef32_exception(struct cpu_user_regs *regs)
     regs->lr_und = regs->pc32 + return_offset;
 
     /* Branch to exception vector */
-    regs->pc32 = exception_handler(VECTOR32_UND);
+    regs->pc32 = exception_handler32(VECTOR32_UND);
 }
 
 /* Injects an Abort exception into the current vcpu, PC is the exact
@@ -344,7 +344,7 @@ static void inject_abt32_exception(struct cpu_user_regs *regs,
     regs->spsr_abt = spsr;
     regs->lr_abt = regs->pc32 + return_offset;
 
-    regs->pc32 = exception_handler(prefetch ? VECTOR32_PABT : VECTOR32_DABT);
+    regs->pc32 = exception_handler32(prefetch ? VECTOR32_PABT : VECTOR32_DABT);
 
     /* Inject a debug fault, best we can do right now */
     if ( READ_SYSREG(TCR_EL1) & TTBCR_EAE )
@@ -397,9 +397,28 @@ static void inject_pabt32_exception(struct cpu_user_regs *regs,
 }
 
 #ifdef CONFIG_ARM_64
+/*
+ * Take care to call this while regs contains the original faulting
+ * state and not the (partially constructed) exception state.
+ */
+static vaddr_t exception_handler64(struct cpu_user_regs *regs, vaddr_t offset)
+{
+    vaddr_t base = READ_SYSREG(VBAR_EL1);
+
+    if ( usr_mode(regs) )
+        base += VECTOR64_LOWER32_BASE;
+    else if ( psr_mode(regs->cpsr,PSR_MODE_EL0t) )
+        base += VECTOR64_LOWER64_BASE;
+    else /* Otherwise must be from kernel mode */
+        base += VECTOR64_CURRENT_SPx_BASE;
+
+    return base + offset;
+}
+
 /* Inject an undefined exception into a 64 bit guest */
 static void inject_undef64_exception(struct cpu_user_regs *regs, int instr_len)
 {
+    vaddr_t handler;
     union hsr esr = {
         .iss = 0,
         .len = instr_len,
@@ -408,12 +427,14 @@ static void inject_undef64_exception(struct cpu_user_regs *regs, int instr_len)
 
     BUG_ON( is_32bit_domain(current->domain) );
 
+    handler = exception_handler64(regs, VECTOR64_SYNC_OFFSET);
+
     regs->spsr_el1 = regs->cpsr;
     regs->elr_el1 = regs->pc;
 
     regs->cpsr = PSR_MODE_EL1h | PSR_ABT_MASK | PSR_FIQ_MASK | \
         PSR_IRQ_MASK | PSR_DBG_MASK;
-    regs->pc = READ_SYSREG(VBAR_EL1) + VECTOR64_CURRENT_SPx_SYNC;
+    regs->pc = handler;
 
     WRITE_SYSREG32(esr.bits, ESR_EL1);
 }
@@ -424,6 +445,7 @@ static void inject_abt64_exception(struct cpu_user_regs *regs,
                                    register_t addr,
                                    int instr_len)
 {
+    vaddr_t handler;
     union hsr esr = {
         .iss = 0,
         .len = instr_len,
@@ -445,12 +467,14 @@ static void inject_abt64_exception(struct cpu_user_regs *regs,
 
     BUG_ON( is_32bit_domain(current->domain) );
 
+    handler = exception_handler64(regs, VECTOR64_SYNC_OFFSET);
+
     regs->spsr_el1 = regs->cpsr;
     regs->elr_el1 = regs->pc;
 
     regs->cpsr = PSR_MODE_EL1h | PSR_ABT_MASK | PSR_FIQ_MASK | \
         PSR_IRQ_MASK | PSR_DBG_MASK;
-    regs->pc = READ_SYSREG(VBAR_EL1) + VECTOR64_CURRENT_SPx_SYNC;
+    regs->pc = handler;
 
     WRITE_SYSREG(addr, FAR_EL1);
     WRITE_SYSREG32(esr.bits, ESR_EL1);
@@ -472,6 +496,17 @@ static void inject_iabt64_exception(struct cpu_user_regs *regs,
 
 #endif
 
+static void inject_undef_exception(struct cpu_user_regs *regs,
+                                   int instr_len)
+{
+        if ( is_32bit_domain(current->domain) )
+            inject_undef32_exception(regs);
+#ifdef CONFIG_ARM_64
+        else
+            inject_undef64_exception(regs, instr_len);
+#endif
+}
+
 static void inject_iabt_exception(struct cpu_user_regs *regs,
                                   register_t addr,
                                   int instr_len)
@@ -1441,7 +1476,7 @@ static void do_cp15_32(struct cpu_user_regs *regs,
         gdprintk(XENLOG_ERR, "unhandled 32-bit CP15 access %#x\n",
                  hsr.bits & HSR_CP32_REGS_MASK);
 #endif
-        inject_undef32_exception(regs);
+        inject_undef_exception(regs, hsr.len);
         return;
     }
     advance_pc(regs, hsr);
@@ -1478,7 +1513,7 @@ static void do_cp15_64(struct cpu_user_regs *regs,
             gdprintk(XENLOG_ERR, "unhandled 64-bit CP15 access %#x\n",
                      hsr.bits & HSR_CP64_REGS_MASK);
 #endif
-            inject_undef32_exception(regs);
+            inject_undef_exception(regs, hsr.len);
             return;
         }
     }
@@ -1547,7 +1582,7 @@ bad_cp:
         gdprintk(XENLOG_ERR, "unhandled 32-bit cp14 access %#x\n",
                  hsr.bits & HSR_CP32_REGS_MASK);
 #endif
-        inject_undef32_exception(regs);
+        inject_undef_exception(regs, hsr.len);
         return;
     }
 
@@ -1574,7 +1609,7 @@ static void do_cp14_dbg(struct cpu_user_regs *regs, union hsr hsr)
     gdprintk(XENLOG_ERR, "unhandled 64-bit CP14 access %#x\n",
              hsr.bits & HSR_CP64_REGS_MASK);
 #endif
-    inject_undef32_exception(regs);
+    inject_undef_exception(regs, hsr.len);
 }
 
 static void do_cp(struct cpu_user_regs *regs, union hsr hsr)
@@ -1593,7 +1628,7 @@ static void do_cp(struct cpu_user_regs *regs, union hsr hsr)
     ASSERT(!cp.tas); /* We don't trap SIMD instruction */
     gdprintk(XENLOG_ERR, "unhandled CP%d access\n", cp.coproc);
 #endif
-    inject_undef32_exception(regs);
+    inject_undef_exception(regs, hsr.len);
 }
 
 #ifdef CONFIG_ARM_64
@@ -1668,7 +1703,7 @@ static void do_sysreg(struct cpu_user_regs *regs,
             gdprintk(XENLOG_ERR, "unhandled 64-bit sysreg access %#x\n",
                      hsr.bits & HSR_SYSREG_REGS_MASK);
 #endif
-            inject_undef64_exception(regs, sysreg.len);
+            inject_undef_exception(regs, sysreg.len);
         }
     }
 
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 9d230f3..bf7c94c 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -460,14 +460,16 @@ union hsr {
 #define VECTOR32_PABT 12
 #define VECTOR32_DABT 16
 /* ... ARM64 */
-#define VECTOR64_CURRENT_SP0_SYNC  0x000
-#define VECTOR64_CURRENT_SP0_IRQ   0x080
-#define VECTOR64_CURRENT_SP0_FIQ   0x100
-#define VECTOR64_CURRENT_SP0_ERROR 0x180
-#define VECTOR64_CURRENT_SPx_SYNC  0x200
-#define VECTOR64_CURRENT_SPx_IRQ   0x280
-#define VECTOR64_CURRENT_SPx_FIQ   0x300
-#define VECTOR64_CURRENT_SPx_ERROR 0x380
+#define VECTOR64_CURRENT_SP0_BASE  0x000
+#define VECTOR64_CURRENT_SPx_BASE  0x200
+#define VECTOR64_LOWER64_BASE      0x400
+#define VECTOR64_LOWER32_BASE      0x600
+
+#define VECTOR64_SYNC_OFFSET       0x000
+#define VECTOR64_IRQ_OFFSET        0x080
+#define VECTOR64_FIQ_OFFSET        0x100
+#define VECTOR64_ERROR_OFFSET      0x180
+
 
 #if defined(CONFIG_ARM_32)
 # include <asm/arm32/processor.h>
-- 
1.7.10.4
xsa102-unstable-03.patch (application/octet-stream, 1.3 KB)
From db7a31166151df1348f958a10bd9b1534258af97 Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Thu, 24 Jul 2014 12:28:22 +0100
Subject: [PATCH 3/3] xen: arm: Handle traps from 32-bit userspace on 64-bit
 kernel as undef

We are not setup to handle these properly. This turns a host crash
into a trap to the guest kernel which will likely result in killing
the offending process.

This is part of XSA-102.

Signed-off-by: Ian Campbell <[email protected]>
Acked-by: Julien Grall <[email protected]>
---
 xen/arch/arm/traps.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index abaee62..c89421b 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1841,6 +1841,17 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
 
     enter_hypervisor_head(regs);
 
+    /*
+     * We currently do not handle 32-bit userspace on 64-bit kernels
+     * correctly (See XSA-102). Until that is resolved we treat any
+     * trap from 32-bit userspace on 64-bit kernel as undefined.
+     */
+    if ( is_64bit_domain(current->domain) && psr_mode_is_32bit(regs->cpsr) )
+    {
+        inject_undef_exception(regs, hsr.len);
+        return;
+    }
+
     switch (hsr.ec) {
     case HSR_EC_WFI_WFE:
         if ( !check_conditional_instr(regs, hsr) )
-- 
1.7.10.4
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.