[PATCH 3/5] powerpc/tm: Block signal return setting invalid MSR state
Michael Ellerman
mpe at ellerman.id.au
Mon Nov 16 21:05:18 AEDT 2015
On Fri, 2015-11-13 at 15:57 +1100, Michael Neuling wrote:
> Currently we allow both the MSR T and S bits to be set by userspace on
> a signal return. Unfortunately this is a reserved configuration and
> will cause a TM Bad Thing exception if attempted (via rfid).
>
> This patch checks for this case in both the 32 and 64bit signals code.
> If these are both set, we clear them and trigger the bad stack frame
> handling.
>
> Found using a syscall fuzzer.
>
> Signed-off-by: Michael Neuling <mikey at neuling.org>
Is this fixes line right?
Fixes: 2b0a576d15e0 ("powerpc: Add new transactional memory state to the signal context")
Which went into v3.9.
In which case this:
> Cc: stable at vger.kernel.org
Should be:
Cc: stable at vger.kernel.org # v3.9+
> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
> index a908ada..2220f7a 100644
> --- a/arch/powerpc/include/asm/reg.h
> +++ b/arch/powerpc/include/asm/reg.h
> @@ -108,6 +108,7 @@
> #define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */
> #define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */
> #define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
> +#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */
Is reserved a good name? I think illegal/bad/wrong would be more helpful,
though I haven't checked the arch to see if it uses "reserved".
> #define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T)
> #define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S)
>
> diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
> index 0dbee46..5b519c7 100644
> --- a/arch/powerpc/kernel/signal_32.c
> +++ b/arch/powerpc/kernel/signal_32.c
> @@ -874,7 +874,16 @@ static long restore_tm_user_regs(struct pt_regs *regs,
> + ELF_NEVRREG))
> return 1;
> #endif /* CONFIG_SPE */
> -
I know you didn't start the rot here, but can you please use your newline key a
bit more :D
> + /* Get the top half of the MSR */
"top" scares me now that we have both kinds of endian, but you're just moving
that code anyway, and it is sane because it's a 32-bit value that we explicitly
put the top half of the 64-bit MSR in.
> + if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
> + return 1;
> + /* Pull in MSR TM from user context */
> + regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK);
Using a tmp variable would be safer.
> + /* Don't let the user set both TM bits */
> + if (MSR_TM_RESV(regs->msr)) {
> + regs->msr &= ~MSR_TS_MASK;
And avoid the clear here.
> + return 1;
> + }
At the (minor) expense of an assignment here to regs->msr.
> @@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
> current->thread.tm_texasr |= TEXASR_FS;
> /* This loads the checkpointed FP/VEC state, if used */
> tm_recheckpoint(¤t->thread, msr);
> - /* Get the top half of the MSR */
> - if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
> - return 1;
> - /* Pull in MSR TM from user context */
> - regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK);
>
> /* This loads the speculative FP/VEC state, if used */
> if (msr & MSR_FP) {
> diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
> index 20756df..b320689 100644
> --- a/arch/powerpc/kernel/signal_64.c
> +++ b/arch/powerpc/kernel/signal_64.c
> @@ -438,6 +438,12 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
>
> /* get MSR separately, transfer the LE bit if doing signal return */
> err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
> + /* Don't allow reserved mode. */
> + if (MSR_TM_RESV(msr)) {
> + msr &= ~MSR_TS_MASK;
Why are you clearing the bits before returning, it's a local isn't it?
> + return -EINVAL;
> + }
> +
> /* pull in MSR TM from user context */
> regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
>
cheers
More information about the Linuxppc-dev
mailing list