[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen stable-4.5] xen: arm: correctly handle vtimer traps from userspace
commit 2b0d3714cb4c2d422775ea63b300de0edfe26f06 Author: Ian Campbell <ian.campbell@xxxxxxxxxx> AuthorDate: Mon Mar 30 12:12:23 2015 +0100 Commit: Ian Campbell <ian.campbell@xxxxxxxxxx> CommitDate: Fri Sep 25 13:37:00 2015 +0100 xen: arm: correctly handle vtimer traps from userspace Previously 32-bit userspace on 32-bit kernel and 64-bit userspace on 64-bit kernel could access these registers irrespective of whether the kernel had configured them to be allowed to. To fix this: - Userspace access to CNTP_CTL_EL0 and CNTP_TVAL_EL0 should be gated on CNTKCTL_EL1.EL0PTEN. - Userspace access to CNTPCT_EL0 should be gated on CNTKCTL_EL1.EL0PCTEN. When we do not handle an access we now silently inject an undef even in debug mode since the debugging messages are not helpful (we have handled the access, by explicitly choosing not to). The usermode accessibility check is rather repetitive, so a helper macro is introduced. Since HSR_EC_CP15_64 cannot be taken from a guest in AArch64 mode except due to a hardware bug switch the associated check to a BUG_ON (which will be switched to something more appropriate in a subsequent patch) Fix a coding style issue in HSR_CPREG64(CNTPCT) while touching similar code. Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> Reviewed-by: Julien Grall <julien.grall@xxxxxxxxxx> (cherry picked from commit d306211e2131eb2d160522f21f21fceaa9dd054c) Conflicts: xen/arch/arm/traps.c --- xen/arch/arm/traps.c | 28 ++++++++----------------- xen/arch/arm/vtimer.c | 43 +++++++++++++++++++++++++------------- xen/include/asm-arm/processor.h | 6 +++++ 3 files changed, 43 insertions(+), 34 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 4063a80..944e241 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -1579,11 +1579,7 @@ static void do_cp15_32(struct cpu_user_regs *regs, case HSR_CPREG32(CNTP_CTL): case HSR_CPREG32(CNTP_TVAL): if ( !vtimer_emulate(regs, hsr) ) - { - dprintk(XENLOG_ERR, - "failed emulation of 32-bit vtimer CP register access\n"); - domain_crash_synchronous(); - } + goto undef_cp15_32; break; case HSR_CPREG32(ACTLR): if ( cp32.read ) @@ -1626,6 +1622,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 + undef_cp15_32: inject_undef_exception(regs, hsr.len); return; } @@ -1645,11 +1642,7 @@ static void do_cp15_64(struct cpu_user_regs *regs, { case HSR_CPREG64(CNTPCT): if ( !vtimer_emulate(regs, hsr) ) - { - dprintk(XENLOG_ERR, - "failed emulation of 64-bit vtimer CP register access\n"); - domain_crash_synchronous(); - } + goto undef_cp15_64; break; default: { @@ -1663,6 +1656,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 + undef_cp15_64: inject_undef_exception(regs, hsr.len); return; } @@ -1830,11 +1824,7 @@ static void do_sysreg(struct cpu_user_regs *regs, case HSR_SYSREG_CNTP_CTL_EL0: case HSR_SYSREG_CNTP_TVAL_EL0: if ( !vtimer_emulate(regs, hsr) ) - { - dprintk(XENLOG_ERR, - "failed emulation of 64-bit vtimer sysreg access\n"); - domain_crash_synchronous(); - } + goto undef_sysreg; break; case HSR_SYSREG_ICC_SGI1R_EL1: if ( !vgic_emulate(regs, hsr) ) @@ -1853,8 +1843,8 @@ static void do_sysreg(struct cpu_user_regs *regs, default: bad_sysreg: { - struct hsr_sysreg sysreg = hsr.sysreg; #ifndef NDEBUG + struct hsr_sysreg sysreg = hsr.sysreg; gdprintk(XENLOG_ERR, "%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n", @@ -1867,7 +1857,8 @@ 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_undef_exception(regs, sysreg.len); + undef_sysreg: + inject_undef_exception(regs, hsr.sysreg.len); return; } } @@ -2040,8 +2031,7 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs) do_cp15_32(regs, hsr); break; case HSR_EC_CP15_64: - if ( !is_32bit_domain(current->domain) ) - goto bad_trap; + BUG_ON(!psr_mode_is_32bit(regs->cpsr)); do_cp15_64(regs, hsr); break; case HSR_EC_CP14_32: diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c index 2e95ceb..592cfab 100644 --- a/xen/arch/arm/vtimer.c +++ b/xen/arch/arm/vtimer.c @@ -30,6 +30,14 @@ extern s_time_t ticks_to_ns(uint64_t ticks); extern uint64_t ns_to_ticks(s_time_t ns); +/* + * Check if regs is allowed access, user_gate is tail end of a + * CNTKCTL_EL1_ bit name which gates user access + */ +#define ACCESS_ALLOWED(regs, user_gate) \ + ( !psr_mode_is_user(regs) || \ + (READ_SYSREG(CNTKCTL_EL1) & CNTKCTL_EL1_##user_gate) ) + static void phys_timer_expired(void *data) { struct vtimer *t = data; @@ -122,9 +130,13 @@ int virt_timer_restore(struct vcpu *v) return 0; } -static void vtimer_cntp_ctl(struct cpu_user_regs *regs, uint32_t *r, int read) +static int vtimer_cntp_ctl(struct cpu_user_regs *regs, uint32_t *r, int read) { struct vcpu *v = current; + + if ( !ACCESS_ALLOWED(regs, EL0PTEN) ) + return 0; + if ( read ) { *r = v->arch.phys_timer.ctl; @@ -144,13 +156,17 @@ static void vtimer_cntp_ctl(struct cpu_user_regs *regs, uint32_t *r, int read) else stop_timer(&v->arch.phys_timer.timer); } + return 1; } -static void vtimer_cntp_tval(struct cpu_user_regs *regs, uint32_t *r, int read) +static int vtimer_cntp_tval(struct cpu_user_regs *regs, uint32_t *r, int read) { struct vcpu *v = current; s_time_t now; + if ( !ACCESS_ALLOWED(regs, EL0PTEN) ) + return 0; + now = NOW() - v->domain->arch.phys_timer_base.offset; if ( read ) @@ -168,6 +184,7 @@ static void vtimer_cntp_tval(struct cpu_user_regs *regs, uint32_t *r, int read) v->domain->arch.phys_timer_base.offset); } } + return 1; } static int vtimer_cntpct(struct cpu_user_regs *regs, uint64_t *r, int read) @@ -178,6 +195,8 @@ static int vtimer_cntpct(struct cpu_user_regs *regs, uint64_t *r, int read) if ( read ) { + if ( !ACCESS_ALLOWED(regs, EL0PCTEN) ) + return 0; now = NOW() - v->domain->arch.phys_timer_base.offset; ticks = ns_to_ticks(now); *r = ticks; @@ -199,12 +218,10 @@ static int vtimer_emulate_cp32(struct cpu_user_regs *regs, union hsr hsr) switch ( hsr.bits & HSR_CP32_REGS_MASK ) { case HSR_CPREG32(CNTP_CTL): - vtimer_cntp_ctl(regs, r, cp32.read); - return 1; + return vtimer_cntp_ctl(regs, r, cp32.read); case HSR_CPREG32(CNTP_TVAL): - vtimer_cntp_tval(regs, r, cp32.read); - return 1; + return vtimer_cntp_tval(regs, r, cp32.read); default: return 0; @@ -221,7 +238,7 @@ static int vtimer_emulate_cp64(struct cpu_user_regs *regs, union hsr hsr) switch ( hsr.bits & HSR_CP64_REGS_MASK ) { case HSR_CPREG64(CNTPCT): - if (!vtimer_cntpct(regs, &x, cp64.read)) + if ( !vtimer_cntpct(regs, &x, cp64.read) ) return 0; if ( cp64.read ) @@ -246,12 +263,14 @@ static int vtimer_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr) switch ( hsr.bits & HSR_SYSREG_REGS_MASK ) { case HSR_SYSREG_CNTP_CTL_EL0: - vtimer_cntp_ctl(regs, &r, sysreg.read); + if ( !vtimer_cntp_ctl(regs, &r, sysreg.read) ) + return 0; if ( sysreg.read ) *x = r; return 1; case HSR_SYSREG_CNTP_TVAL_EL0: - vtimer_cntp_tval(regs, &r, sysreg.read); + if ( !vtimer_cntp_tval(regs, &r, sysreg.read) ) + return 0; if ( sysreg.read ) *x = r; return 1; @@ -271,17 +290,11 @@ int vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr) switch (hsr.ec) { case HSR_EC_CP15_32: - if ( !is_32bit_domain(current->domain) ) - return 0; return vtimer_emulate_cp32(regs, hsr); case HSR_EC_CP15_64: - if ( !is_32bit_domain(current->domain) ) - return 0; return vtimer_emulate_cp64(regs, hsr); #ifdef CONFIG_ARM_64 case HSR_EC_SYSREG: - if ( is_32bit_domain(current->domain) ) - return 0; return vtimer_emulate_sysreg(regs, hsr); #endif default: diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index fcd26fb..b7e88a6 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -558,6 +558,12 @@ union hsr { #define CNTHCTL_PA (1u<<0) /* Kernel/user access to physical counter */ #define CNTHCTL_TA (1u<<1) /* Kernel/user access to CNTP timer */ +/* Time counter kernel control register */ +#define CNTKCTL_EL1_EL0PCTEN (1u<<0) /* Expose phys counters to EL0 */ +#define CNTKCTL_EL1_EL0VCTEN (1u<<1) /* Expose virt counters to EL0 */ +#define CNTKCTL_EL1_EL0VTEN (1u<<8) /* Expose virt timer registers to EL0 */ +#define CNTKCTL_EL1_EL0PTEN (1u<<9) /* Expose phys timer registers to EL0 */ + /* Timer control registers */ #define CNTx_CTL_ENABLE (1u<<0) /* Enable timer */ #define CNTx_CTL_MASK (1u<<1) /* Mask IRQ */ -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.5 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |