Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2b9d2a5 authored by Michael Neuling's avatar Michael Neuling Committed by Michael Ellerman
Browse files

powerpc/tm: Block signal return setting invalid MSR state



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 64 bit signals
code.  If both T and S are set, we mark the context as invalid.

Found using a syscall fuzzer.

Fixes: 2b0a576d ("powerpc: Add new transactional memory state to the signal context")
Cc: stable@vger.kernel.org # v3.9+
Signed-off-by: default avatarMichael Neuling <mikey@neuling.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 1ec21837
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -108,6 +108,7 @@
#define MSR_TS_T	__MASK(MSR_TS_T_LG)	/*  Transaction Transactional */
#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_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_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */
#define MSR_TM_TRANSACTIONAL(x)	(((x) & MSR_TS_MASK) == MSR_TS_T)
#define MSR_TM_TRANSACTIONAL(x)	(((x) & MSR_TS_MASK) == MSR_TS_T)
#define MSR_TM_SUSPENDED(x)	(((x) & MSR_TS_MASK) == MSR_TS_S)
#define MSR_TM_SUSPENDED(x)	(((x) & MSR_TS_MASK) == MSR_TS_S)


+9 −5
Original line number Original line Diff line number Diff line
@@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs,
		return 1;
		return 1;
#endif /* CONFIG_SPE */
#endif /* CONFIG_SPE */


	/* Get the top half of the MSR from the user context */
	if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
		return 1;
	msr_hi <<= 32;
	/* If TM bits are set to the reserved value, it's an invalid context */
	if (MSR_TM_RESV(msr_hi))
		return 1;
	/* Pull in the MSR TM bits from the user context */
	regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK);
	/* Now, recheckpoint.  This loads up all of the checkpointed (older)
	/* Now, recheckpoint.  This loads up all of the checkpointed (older)
	 * registers, including FP and V[S]Rs.  After recheckpointing, the
	 * registers, including FP and V[S]Rs.  After recheckpointing, the
	 * transactional versions should be loaded.
	 * transactional versions should be loaded.
@@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
	current->thread.tm_texasr |= TEXASR_FS;
	current->thread.tm_texasr |= TEXASR_FS;
	/* This loads the checkpointed FP/VEC state, if used */
	/* This loads the checkpointed FP/VEC state, if used */
	tm_recheckpoint(&current->thread, msr);
	tm_recheckpoint(&current->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 */
	/* This loads the speculative FP/VEC state, if used */
	if (msr & MSR_FP) {
	if (msr & MSR_FP) {
+4 −0
Original line number Original line Diff line number Diff line
@@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,


	/* get MSR separately, transfer the LE bit if doing signal return */
	/* get MSR separately, transfer the LE bit if doing signal return */
	err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
	err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
	/* Don't allow reserved mode. */
	if (MSR_TM_RESV(msr))
		return -EINVAL;

	/* pull in MSR TM from user context */
	/* pull in MSR TM from user context */
	regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
	regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);