Commit d45c791c authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds

[PATCH] ppc64: fix signal mask restoration when delivery fails

This is the third of 3 patches from David Woodhouse which fix various
problems with signal handling on ppc64.

At present, if a signal is being delivered, and the process has specified
delivery of that signal on an alternate stack but the alternate stack that
has been specified is invalid (i.e.  the kernel gets a fault writing to the
alternate stack), then we (correctly) give the process a SIGSEGV but we put
the wrong signal mask in the saved state on the stack - i.e.  we put the
mask that would have been established for the original signal handler
there.

This patch fixes it by making setup_rt_frame, handle_rt_signal32 and
handle_signal32 return a status code to indicate whether they successfully
established a stack frame.  If they fail, the caller doesn't block the
signals specified for the signal handler.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 44e0a901
......@@ -388,7 +388,7 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
return 0;
}
static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
/* Handler is *really* a pointer to the function descriptor for
......@@ -456,7 +456,7 @@ static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
return;
return 1;
badframe:
#if DEBUG_SIG
......@@ -464,25 +464,30 @@ static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
regs, frame, newsp);
#endif
force_sigsegv(signr, current);
return 0;
}
/*
* OK, we're invoking a handler
*/
static void handle_signal(unsigned long sig, struct k_sigaction *ka,
static int handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
int ret;
/* Set up Signal Frame */
setup_rt_frame(sig, ka, info, oldset, regs);
ret = setup_rt_frame(sig, ka, info, oldset, regs);
if (!(ka->sa.sa_flags & SA_NODEFER)) {
if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
return ret;
}
static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
......@@ -542,8 +547,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
/* Whee! Actually deliver the signal. */
if (TRAP(regs) == 0x0C00)
syscall_restart(regs, &ka);
handle_signal(signr, &ka, &info, oldset, regs);
return 1;
return handle_signal(signr, &ka, &info, oldset, regs);
}
if (TRAP(regs) == 0x0C00) { /* System Call! */
......
......@@ -650,7 +650,7 @@ int sys32_sigaltstack(u32 __new, u32 __old, int r5,
* Set up a signal frame for a "real-time" signal handler
* (one which gets siginfo).
*/
static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
struct pt_regs * regs, unsigned long newsp)
{
......@@ -704,7 +704,7 @@ static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
return;
return 1;
badframe:
#if DEBUG_SIG
......@@ -712,6 +712,7 @@ static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
regs, frame, newsp);
#endif
force_sigsegv(sig, current);
return 0;
}
static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig)
......@@ -822,7 +823,7 @@ long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
/*
* OK, we're invoking a handler
*/
static void handle_signal32(unsigned long sig, struct k_sigaction *ka,
static int handle_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
struct pt_regs * regs, unsigned long newsp)
{
......@@ -870,7 +871,7 @@ static void handle_signal32(unsigned long sig, struct k_sigaction *ka,
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
return;
return 1;
badframe:
#if DEBUG_SIG
......@@ -878,6 +879,7 @@ static void handle_signal32(unsigned long sig, struct k_sigaction *ka,
regs, frame, *newspp);
#endif
force_sigsegv(sig, current);
return 0;
}
/*
......@@ -987,11 +989,11 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
/* Whee! Actually deliver the signal. */
if (ka.sa.sa_flags & SA_SIGINFO)
handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp);
ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp);
else
handle_signal32(signr, &ka, &info, oldset, regs, newsp);
ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp);
if (!(ka.sa.sa_flags & SA_NODEFER)) {
if (ret && !(ka.sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked,
&ka.sa.sa_mask);
......@@ -1000,5 +1002,5 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
spin_unlock_irq(&current->sighand->siglock);
}
return 1;
return ret;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment