[POWERPC] Merge creation of signal frame
The code for creating signal frames was still duplicated and split in strange ways between 32 and 64 bits, including the SA_ONSTACK handling being in do_signal on 32 bits but inside handle_rt_signal on 64 bits etc... This moves the 64 bits get_sigframe() to the generic signal.c, cleans it a bit, moves the access_ok() call done by all callers to it as well, and adapts/cleanups the 3 different signal handling cases to use that common function. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
parent
5f9f375a62
commit
a3f61dc0a5
4 changed files with 59 additions and 62 deletions
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/signal.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#include "signal.h"
|
||||
|
@ -28,6 +29,32 @@ static inline int is_32bit_task(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate space for the signal frame
|
||||
*/
|
||||
void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
size_t frame_size)
|
||||
{
|
||||
unsigned long oldsp, newsp;
|
||||
|
||||
/* Default to using normal stack */
|
||||
oldsp = regs->gpr[1];
|
||||
|
||||
/* Check for alt stack */
|
||||
if ((ka->sa.sa_flags & SA_ONSTACK) &&
|
||||
current->sas_ss_size && !on_sig_stack(oldsp))
|
||||
oldsp = (current->sas_ss_sp + current->sas_ss_size);
|
||||
|
||||
/* Get aligned frame */
|
||||
newsp = (oldsp - frame_size) & ~0xFUL;
|
||||
|
||||
/* Check access */
|
||||
if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
|
||||
return NULL;
|
||||
|
||||
return (void __user *)newsp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Restore the user process's signal mask
|
||||
|
@ -130,20 +157,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
|
|||
#endif
|
||||
|
||||
if (is32) {
|
||||
unsigned int newsp;
|
||||
|
||||
if ((ka.sa.sa_flags & SA_ONSTACK) &&
|
||||
current->sas_ss_size && !on_sig_stack(regs->gpr[1]))
|
||||
newsp = current->sas_ss_sp + current->sas_ss_size;
|
||||
else
|
||||
newsp = regs->gpr[1];
|
||||
|
||||
if (ka.sa.sa_flags & SA_SIGINFO)
|
||||
ret = handle_rt_signal32(signr, &ka, &info, oldset,
|
||||
regs, newsp);
|
||||
regs);
|
||||
else
|
||||
ret = handle_signal32(signr, &ka, &info, oldset,
|
||||
regs, newsp);
|
||||
regs);
|
||||
#ifdef CONFIG_PPC64
|
||||
} else {
|
||||
ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
|
||||
|
|
|
@ -12,15 +12,17 @@
|
|||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
size_t frame_size);
|
||||
extern void restore_sigmask(sigset_t *set);
|
||||
|
||||
extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset,
|
||||
struct pt_regs *regs, unsigned long newsp);
|
||||
struct pt_regs *regs);
|
||||
|
||||
extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset,
|
||||
struct pt_regs *regs, unsigned long newsp);
|
||||
struct pt_regs *regs);
|
||||
|
||||
extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *set,
|
||||
|
|
|
@ -282,14 +282,17 @@ long sys_sigaction(int sig, struct old_sigaction __user *act,
|
|||
/*
|
||||
* When we have signals to deliver, we set up on the
|
||||
* user stack, going down from the original stack pointer:
|
||||
* a sigregs struct
|
||||
* an ABI gap of 56 words
|
||||
* an mcontext struct
|
||||
* a sigcontext struct
|
||||
* a gap of __SIGNAL_FRAMESIZE bytes
|
||||
*
|
||||
* Each of these things must be a multiple of 16 bytes in size.
|
||||
* Each of these things must be a multiple of 16 bytes in size. The following
|
||||
* structure represent all of this except the __SIGNAL_FRAMESIZE gap
|
||||
*
|
||||
*/
|
||||
struct sigregs {
|
||||
struct sigframe {
|
||||
struct sigcontext sctx; /* the sigcontext */
|
||||
struct mcontext mctx; /* all the register values */
|
||||
/*
|
||||
* Programs using the rs6000/xcoff abi can save up to 19 gp
|
||||
|
@ -698,21 +701,16 @@ int compat_sys_sigaltstack(u32 __new, u32 __old, int r5,
|
|||
*/
|
||||
int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset,
|
||||
struct pt_regs *regs, unsigned long newsp)
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct rt_sigframe __user *rt_sf;
|
||||
struct mcontext __user *frame;
|
||||
unsigned long origsp = newsp;
|
||||
unsigned long newsp = 0;
|
||||
|
||||
/* Set up Signal Frame */
|
||||
/* Put a Real Time Context onto stack */
|
||||
newsp -= sizeof(*rt_sf);
|
||||
rt_sf = (struct rt_sigframe __user *)newsp;
|
||||
|
||||
/* create a stack frame for the caller of the handler */
|
||||
newsp -= __SIGNAL_FRAMESIZE + 16;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))
|
||||
rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
|
||||
if (unlikely(rt_sf == NULL))
|
||||
goto badframe;
|
||||
|
||||
/* Put the siginfo & fill in most of the ucontext */
|
||||
|
@ -742,8 +740,12 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
|
|||
|
||||
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
|
||||
|
||||
/* create a stack frame for the caller of the handler */
|
||||
newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
|
||||
if (put_user(regs->gpr[1], (u32 __user *)newsp))
|
||||
goto badframe;
|
||||
|
||||
/* Fill registers for signal handler */
|
||||
regs->gpr[1] = newsp;
|
||||
regs->gpr[3] = sig;
|
||||
regs->gpr[4] = (unsigned long) &rt_sf->info;
|
||||
|
@ -988,26 +990,17 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
|
|||
* OK, we're invoking a handler
|
||||
*/
|
||||
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
|
||||
unsigned long newsp)
|
||||
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
|
||||
{
|
||||
struct sigcontext __user *sc;
|
||||
struct sigregs __user *frame;
|
||||
unsigned long origsp = newsp;
|
||||
struct sigframe __user *frame;
|
||||
unsigned long newsp = 0;
|
||||
|
||||
/* Set up Signal Frame */
|
||||
newsp -= sizeof(struct sigregs);
|
||||
frame = (struct sigregs __user *) newsp;
|
||||
|
||||
/* Put a sigcontext on the stack */
|
||||
newsp -= sizeof(*sc);
|
||||
sc = (struct sigcontext __user *) newsp;
|
||||
|
||||
/* create a stack frame for the caller of the handler */
|
||||
newsp -= __SIGNAL_FRAMESIZE;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
if (unlikely(frame == NULL))
|
||||
goto badframe;
|
||||
sc = (struct sigcontext __user *) &frame->sctx;
|
||||
|
||||
#if _NSIG != 64
|
||||
#error "Please adjust handle_signal()"
|
||||
|
@ -1019,7 +1012,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
|||
#else
|
||||
|| __put_user(oldset->sig[1], &sc->_unused[3])
|
||||
#endif
|
||||
|| __put_user(to_user_ptr(frame), &sc->regs)
|
||||
|| __put_user(to_user_ptr(&frame->mctx), &sc->regs)
|
||||
|| __put_user(sig, &sc->signal))
|
||||
goto badframe;
|
||||
|
||||
|
@ -1035,8 +1028,11 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
|||
|
||||
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
|
||||
|
||||
/* create a stack frame for the caller of the handler */
|
||||
newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
|
||||
if (put_user(regs->gpr[1], (u32 __user *)newsp))
|
||||
goto badframe;
|
||||
|
||||
regs->gpr[1] = newsp;
|
||||
regs->gpr[3] = sig;
|
||||
regs->gpr[4] = (unsigned long) sc;
|
||||
|
|
|
@ -195,25 +195,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space for the signal frame
|
||||
*/
|
||||
static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
size_t frame_size)
|
||||
{
|
||||
unsigned long newsp;
|
||||
|
||||
/* Default to using normal stack */
|
||||
newsp = regs->gpr[1];
|
||||
|
||||
if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) {
|
||||
if (! on_sig_stack(regs->gpr[1]))
|
||||
newsp = (current->sas_ss_sp + current->sas_ss_size);
|
||||
}
|
||||
|
||||
return (void __user *)((newsp - frame_size) & -16ul);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the trampoline code on the stack
|
||||
*/
|
||||
|
@ -348,8 +329,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
|
|||
long err = 0;
|
||||
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
if (unlikely(frame == NULL))
|
||||
goto badframe;
|
||||
|
||||
err |= __put_user(&frame->info, &frame->pinfo);
|
||||
|
@ -386,7 +366,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
|
|||
funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler;
|
||||
|
||||
/* Allocate a dummy caller frame for the signal handler. */
|
||||
newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
|
||||
newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
|
||||
err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
|
||||
|
||||
/* Set up "regs" so we "return" to the signal handler. */
|
||||
|
|
Loading…
Reference in a new issue