aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2013-06-09 07:23:16 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-06-20 03:05:18 -0400
commitfee55450710dff32a13ae30b4129ec7b5a4b44d0 (patch)
tree9aea8b3e1d80e274f1407abedabb925a82aaa604 /arch/powerpc/kernel
parent1d25f11fdbcc5390d68efd98c28900bfd29b264c (diff)
powerpc/tm: Fix 32 bit non-rt signals
Currently sys_sigreturn() is TM unaware. Therefore, if we take a 32 bit signal without SIGINFO (non RT) inside a transaction, on signal return we don't restore the signal frame correctly. This checks if the signal frame being restoring is an active transaction, and if so, it copies the additional state to ptregs so it can be restored. Signed-off-by: Michael Neuling <mikey@neuling.org> cc: stable@vger.kernel.org (v3.9+) Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/signal_32.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 5bc819f50af6..fa81462f6987 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -1494,16 +1494,22 @@ badframe:
1494long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, 1494long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
1495 struct pt_regs *regs) 1495 struct pt_regs *regs)
1496{ 1496{
1497 struct sigframe __user *sf;
1497 struct sigcontext __user *sc; 1498 struct sigcontext __user *sc;
1498 struct sigcontext sigctx; 1499 struct sigcontext sigctx;
1499 struct mcontext __user *sr; 1500 struct mcontext __user *sr;
1500 void __user *addr; 1501 void __user *addr;
1501 sigset_t set; 1502 sigset_t set;
1503#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
1504 struct mcontext __user *mcp, *tm_mcp;
1505 unsigned long msr_hi;
1506#endif
1502 1507
1503 /* Always make any pending restarted system calls return -EINTR */ 1508 /* Always make any pending restarted system calls return -EINTR */
1504 current_thread_info()->restart_block.fn = do_no_restart_syscall; 1509 current_thread_info()->restart_block.fn = do_no_restart_syscall;
1505 1510
1506 sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); 1511 sf = (struct sigframe __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
1512 sc = &sf->sctx;
1507 addr = sc; 1513 addr = sc;
1508 if (copy_from_user(&sigctx, sc, sizeof(sigctx))) 1514 if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
1509 goto badframe; 1515 goto badframe;
@@ -1520,11 +1526,25 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
1520#endif 1526#endif
1521 set_current_blocked(&set); 1527 set_current_blocked(&set);
1522 1528
1523 sr = (struct mcontext __user *)from_user_ptr(sigctx.regs); 1529#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
1524 addr = sr; 1530 mcp = (struct mcontext __user *)&sf->mctx;
1525 if (!access_ok(VERIFY_READ, sr, sizeof(*sr)) 1531 tm_mcp = (struct mcontext __user *)&sf->mctx_transact;
1526 || restore_user_regs(regs, sr, 1)) 1532 if (__get_user(msr_hi, &tm_mcp->mc_gregs[PT_MSR]))
1527 goto badframe; 1533 goto badframe;
1534 if (MSR_TM_ACTIVE(msr_hi<<32)) {
1535 if (!cpu_has_feature(CPU_FTR_TM))
1536 goto badframe;
1537 if (restore_tm_user_regs(regs, mcp, tm_mcp))
1538 goto badframe;
1539 } else
1540#endif
1541 {
1542 sr = (struct mcontext __user *)from_user_ptr(sigctx.regs);
1543 addr = sr;
1544 if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
1545 || restore_user_regs(regs, sr, 1))
1546 goto badframe;
1547 }
1528 1548
1529 set_thread_flag(TIF_RESTOREALL); 1549 set_thread_flag(TIF_RESTOREALL);
1530 return 0; 1550 return 0;