[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |