Skip to content

Commit

Permalink
[POWERPC] Merge creation of signal frame
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Jun 14, 2007
1 parent 5f9f375 commit a3f61dc
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 62 deletions.
39 changes: 29 additions & 10 deletions arch/powerpc/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <linux/ptrace.h>
#include <linux/signal.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>

#include "signal.h"
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions arch/powerpc/kernel/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
52 changes: 24 additions & 28 deletions arch/powerpc/kernel/signal_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()"
Expand All @@ -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;

Expand All @@ -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;
Expand Down
24 changes: 2 additions & 22 deletions arch/powerpc/kernel/signal_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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. */
Expand Down

0 comments on commit a3f61dc

Please sign in to comment.