Skip to content

Commit d2b9d2a

Browse files
mikeympe
authored andcommitted
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: 2b0a576 ("powerpc: Add new transactional memory state to the signal context") Cc: stable@vger.kernel.org # v3.9+ Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
1 parent 1ec2183 commit d2b9d2a

File tree

3 files changed

+14
-5
lines changed

3 files changed

+14
-5
lines changed

Diff for: arch/powerpc/include/asm/reg.h

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
#define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */
109109
#define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */
110110
#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
111+
#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */
111112
#define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T)
112113
#define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S)
113114

Diff for: arch/powerpc/kernel/signal_32.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs,
875875
return 1;
876876
#endif /* CONFIG_SPE */
877877

878+
/* Get the top half of the MSR from the user context */
879+
if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
880+
return 1;
881+
msr_hi <<= 32;
882+
/* If TM bits are set to the reserved value, it's an invalid context */
883+
if (MSR_TM_RESV(msr_hi))
884+
return 1;
885+
/* Pull in the MSR TM bits from the user context */
886+
regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK);
878887
/* Now, recheckpoint. This loads up all of the checkpointed (older)
879888
* registers, including FP and V[S]Rs. After recheckpointing, the
880889
* transactional versions should be loaded.
@@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
884893
current->thread.tm_texasr |= TEXASR_FS;
885894
/* This loads the checkpointed FP/VEC state, if used */
886895
tm_recheckpoint(&current->thread, msr);
887-
/* Get the top half of the MSR */
888-
if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
889-
return 1;
890-
/* Pull in MSR TM from user context */
891-
regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK);
892896

893897
/* This loads the speculative FP/VEC state, if used */
894898
if (msr & MSR_FP) {

Diff for: arch/powerpc/kernel/signal_64.c

+4
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
438438

439439
/* get MSR separately, transfer the LE bit if doing signal return */
440440
err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
441+
/* Don't allow reserved mode. */
442+
if (MSR_TM_RESV(msr))
443+
return -EINVAL;
444+
441445
/* pull in MSR TM from user context */
442446
regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
443447

0 commit comments

Comments
 (0)