#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/elf.h>
+#include <linux/ptrace.h>
#ifdef CONFIG_PPC64
#include <linux/syscalls.h>
#include <linux/compat.h>
-#include <linux/ptrace.h>
#else
#include <linux/wait.h>
-#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/tty.h>
/*
* 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
*/
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;
+ void __user *addr;
+ 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));
+ addr = rt_sf;
+ if (unlikely(rt_sf == NULL))
goto badframe;
/* Put the siginfo & fill in most of the ucontext */
/* Save user registers on the stack */
frame = &rt_sf->uc.uc_mcontext;
+ addr = frame;
if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
if (save_user_regs(regs, frame, 0))
goto badframe;
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);
+ addr = (void __user *)regs->gpr[1];
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;
printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
+ if (show_unhandled_signals && printk_ratelimit())
+ printk(KERN_INFO "%s[%d]: bad frame in handle_rt_signal32: "
+ "%p nip %08lx lr %08lx\n",
+ current->comm, current->pid,
+ addr, regs->nip, regs->link);
+
force_sigsegv(sig, current);
return 0;
}
return 0;
bad:
+ if (show_unhandled_signals && printk_ratelimit())
+ printk(KERN_INFO "%s[%d]: bad frame in sys_rt_sigreturn: "
+ "%p nip %08lx lr %08lx\n",
+ current->comm, current->pid,
+ rt_sf, regs->nip, regs->link);
+
force_sig(SIGSEGV, current);
return 0;
}
* We kill the task with a SIGSEGV in this situation.
*/
if (do_setcontext(ctx, regs, 1)) {
+ if (show_unhandled_signals && printk_ratelimit())
+ printk(KERN_INFO "%s[%d]: bad frame in "
+ "sys_debug_setcontext: %p nip %08lx "
+ "lr %08lx\n",
+ current->comm, current->pid,
+ ctx, regs->nip, regs->link);
+
force_sig(SIGSEGV, current);
goto out;
}
* 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()"
#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;
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;
printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
+ if (show_unhandled_signals && printk_ratelimit())
+ printk(KERN_INFO "%s[%d]: bad frame in handle_signal32: "
+ "%p nip %08lx lr %08lx\n",
+ current->comm, current->pid,
+ frame, regs->nip, regs->link);
+
force_sigsegv(sig, current);
return 0;
}
struct sigcontext __user *sc;
struct sigcontext sigctx;
struct mcontext __user *sr;
+ void __user *addr;
sigset_t set;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ addr = sc;
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
restore_sigmask(&set);
sr = (struct mcontext __user *)from_user_ptr(sigctx.regs);
+ addr = sr;
if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
|| restore_user_regs(regs, sr, 1))
goto badframe;
return 0;
badframe:
+ if (show_unhandled_signals && printk_ratelimit())
+ printk(KERN_INFO "%s[%d]: bad frame in sys_sigreturn: "
+ "%p nip %08lx lr %08lx\n",
+ current->comm, current->pid,
+ addr, regs->nip, regs->link);
+
force_sig(SIGSEGV, current);
return 0;
}