[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] xen: arm: Correctly handle exception injection from userspace on 64-bit.



commit a98669781769e821413dfef4ef99b93171375610
Author:     Ian Campbell <ian.campbell@xxxxxxxxxx>
AuthorDate: Tue Aug 12 15:36:15 2014 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Aug 12 15:36:15 2014 +0200

    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 CVE-2014-5147 / XSA-102.
    
    Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
    Acked-by: Julien Grall <julien.grall@xxxxxxxxxx>
---
 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 5adf125..7f34f1d 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>
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.