2005-07-28 02:44:44 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2003, Axis Communications AB.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/sched.h>
|
2017-02-09 01:51:37 +08:00
|
|
|
#include <linux/sched/task_stack.h>
|
2005-07-28 02:44:44 +08:00
|
|
|
#include <linux/mm.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2005-07-28 02:44:44 +08:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/signal.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/wait.h>
|
|
|
|
#include <linux/ptrace.h>
|
|
|
|
#include <linux/unistd.h>
|
|
|
|
#include <linux/stddef.h>
|
|
|
|
#include <linux/syscalls.h>
|
|
|
|
#include <linux/vmalloc.h>
|
|
|
|
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/processor.h>
|
|
|
|
#include <asm/ucontext.h>
|
2016-12-25 03:46:01 +08:00
|
|
|
#include <linux/uaccess.h>
|
2008-10-21 23:45:58 +08:00
|
|
|
#include <arch/hwregs/cpu_vect.h>
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
extern unsigned long cris_signal_return_page;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A syscall in CRIS is really a "break 13" instruction, which is 2
|
|
|
|
* bytes. The registers is manipulated so upon return the instruction
|
|
|
|
* will be executed again.
|
|
|
|
*
|
|
|
|
* This relies on that PC points to the instruction after the break call.
|
|
|
|
*/
|
|
|
|
#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->erp -= 2;
|
|
|
|
|
|
|
|
/* Signal frames. */
|
|
|
|
struct signal_frame {
|
|
|
|
struct sigcontext sc;
|
|
|
|
unsigned long extramask[_NSIG_WORDS - 1];
|
|
|
|
unsigned char retcode[8]; /* Trampoline code. */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rt_signal_frame {
|
|
|
|
struct siginfo *pinfo;
|
|
|
|
void *puc;
|
|
|
|
struct siginfo info;
|
|
|
|
struct ucontext uc;
|
|
|
|
unsigned char retcode[8]; /* Trampoline code. */
|
|
|
|
};
|
|
|
|
|
2008-01-25 23:10:02 +08:00
|
|
|
void do_signal(int restart, struct pt_regs *regs);
|
2005-07-28 02:44:44 +08:00
|
|
|
void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
|
|
|
|
struct pt_regs *regs);
|
|
|
|
|
|
|
|
static int
|
|
|
|
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
|
|
|
|
{
|
|
|
|
unsigned int err = 0;
|
|
|
|
unsigned long old_usp;
|
|
|
|
|
|
|
|
/* Always make any pending restarted system calls return -EINTR */
|
2015-02-13 07:01:14 +08:00
|
|
|
current->restart_block.fn = do_no_restart_syscall;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Restore the registers from &sc->regs. sc is already checked
|
|
|
|
* for VERIFY_READ since the signal_frame was previously
|
|
|
|
* checked in sys_sigreturn().
|
|
|
|
*/
|
|
|
|
if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
|
|
|
|
goto badframe;
|
|
|
|
|
|
|
|
/* Make that the user-mode flag is set. */
|
|
|
|
regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT));
|
|
|
|
|
CRISv32: prevent bogus restarts on sigreturn
Al Viro noted that CRIS is vulnerable to bogus restarts on sigreturn.
The fixes CRISv32 by using regs->exs as an additional indicator to
whether we should attempt to restart the syscall or not. EXS is only
used in the sigtrap handling, and in that path we already have r9 (the
other indicator, which indicates if we're in a syscall or not) cleared.
Test case, a port of Al's ARM version from 653d48b22166db2d8 ("arm: fix
really nasty sigreturn bug"):
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
void f(int n)
{
register int r10 asm ("r10") = n;
__asm__ __volatile__(
"ba 1f \n"
"nop \n"
"break 8 \n"
"1: ba . \n"
"nop \n"
:
: "r" (r10)
: "memory");
}
void handler1(int sig) { }
void handler2(int sig) { raise(1); }
void handler3(int sig) { exit(0); }
int main(int argc, char *argv[])
{
struct sigaction s = {.sa_handler = handler2};
struct itimerval t1 = { .it_value = {1} };
struct itimerval t2 = { .it_value = {2} };
signal(1, handler1);
sigemptyset(&s.sa_mask);
sigaddset(&s.sa_mask, 1);
sigaction(SIGALRM, &s, NULL);
signal(SIGVTALRM, handler3);
setitimer(ITIMER_REAL, &t1, NULL);
setitimer(ITIMER_VIRTUAL, &t2, NULL);
f(-513); /* -ERESTARTNOINTR */
return 0;
}
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Link: http://lkml.kernel.org/r/20121208074429.GC4939@ZenIV.linux.org.uk
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Jesper Nilsson <jespern@axis.com>
2015-02-09 00:53:22 +08:00
|
|
|
/* Don't perform syscall restarting */
|
|
|
|
regs->exs = -1;
|
|
|
|
|
2005-07-28 02:44:44 +08:00
|
|
|
/* Restore the old USP. */
|
|
|
|
err |= __get_user(old_usp, &sc->usp);
|
|
|
|
wrusp(old_usp);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
badframe:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-12-27 11:11:53 +08:00
|
|
|
asmlinkage int sys_sigreturn(void)
|
2005-07-28 02:44:44 +08:00
|
|
|
{
|
2012-12-27 11:11:53 +08:00
|
|
|
struct pt_regs *regs = current_pt_regs();
|
2005-07-28 02:44:44 +08:00
|
|
|
sigset_t set;
|
|
|
|
struct signal_frame __user *frame;
|
|
|
|
unsigned long oldspc = regs->spc;
|
|
|
|
unsigned long oldccs = regs->ccs;
|
|
|
|
|
|
|
|
frame = (struct signal_frame *) rdusp();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since the signal is stacked on a dword boundary, the frame
|
|
|
|
* should be dword aligned here as well. It it's not, then the
|
|
|
|
* user is trying some funny business.
|
|
|
|
*/
|
|
|
|
if (((long)frame) & 3)
|
|
|
|
goto badframe;
|
|
|
|
|
|
|
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
|
|
|
goto badframe;
|
|
|
|
|
|
|
|
if (__get_user(set.sig[0], &frame->sc.oldmask) ||
|
|
|
|
(_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1],
|
|
|
|
frame->extramask,
|
|
|
|
sizeof(frame->extramask))))
|
|
|
|
goto badframe;
|
|
|
|
|
2012-05-11 08:58:00 +08:00
|
|
|
set_current_blocked(&set);
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
if (restore_sigcontext(regs, &frame->sc))
|
|
|
|
goto badframe;
|
|
|
|
|
|
|
|
keep_debug_flags(oldccs, oldspc, regs);
|
|
|
|
|
|
|
|
return regs->r10;
|
|
|
|
|
|
|
|
badframe:
|
|
|
|
force_sig(SIGSEGV, current);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-27 11:11:53 +08:00
|
|
|
asmlinkage int sys_rt_sigreturn(void)
|
2005-07-28 02:44:44 +08:00
|
|
|
{
|
2012-12-27 11:11:53 +08:00
|
|
|
struct pt_regs *regs = current_pt_regs();
|
2005-07-28 02:44:44 +08:00
|
|
|
sigset_t set;
|
|
|
|
struct rt_signal_frame __user *frame;
|
|
|
|
unsigned long oldspc = regs->spc;
|
|
|
|
unsigned long oldccs = regs->ccs;
|
|
|
|
|
|
|
|
frame = (struct rt_signal_frame *) rdusp();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since the signal is stacked on a dword boundary, the frame
|
|
|
|
* should be dword aligned here as well. It it's not, then the
|
|
|
|
* user is trying some funny business.
|
|
|
|
*/
|
|
|
|
if (((long)frame) & 3)
|
|
|
|
goto badframe;
|
|
|
|
|
|
|
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
|
|
|
goto badframe;
|
|
|
|
|
|
|
|
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
|
|
|
goto badframe;
|
|
|
|
|
2012-05-11 08:58:00 +08:00
|
|
|
set_current_blocked(&set);
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
|
|
|
|
goto badframe;
|
|
|
|
|
2012-12-23 15:07:30 +08:00
|
|
|
if (restore_altstack(&frame->uc.uc_stack))
|
2008-01-25 23:10:02 +08:00
|
|
|
goto badframe;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
keep_debug_flags(oldccs, oldspc, regs);
|
|
|
|
|
|
|
|
return regs->r10;
|
|
|
|
|
|
|
|
badframe:
|
|
|
|
force_sig(SIGSEGV, current);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup a signal frame. */
|
|
|
|
static int
|
|
|
|
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
|
|
|
unsigned long mask)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
unsigned long usp;
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
usp = rdusp();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the registers. They are located first in sc, so it's
|
|
|
|
* possible to use sc directly.
|
|
|
|
*/
|
|
|
|
err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
|
|
|
|
|
|
|
|
err |= __put_user(mask, &sc->oldmask);
|
|
|
|
err |= __put_user(usp, &sc->usp);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out where to put the new signal frame - usually on the stack. */
|
|
|
|
static inline void __user *
|
2014-03-05 21:54:10 +08:00
|
|
|
get_sigframe(struct ksignal *ksig, size_t frame_size)
|
2005-07-28 02:44:44 +08:00
|
|
|
{
|
2014-03-05 21:54:10 +08:00
|
|
|
unsigned long sp = sigsp(rdusp(), ksig);
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/* Make sure the frame is dword-aligned. */
|
|
|
|
sp &= ~3;
|
|
|
|
|
|
|
|
return (void __user *)(sp - frame_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Grab and setup a signal frame.
|
|
|
|
*
|
|
|
|
* Basically a lot of state-info is stacked, and arranged for the
|
2008-01-25 23:10:02 +08:00
|
|
|
* user-mode program to return to the kernel using either a trampiline
|
2005-07-28 02:44:44 +08:00
|
|
|
* which performs the syscall sigreturn(), or a provided user-mode
|
|
|
|
* trampoline.
|
|
|
|
*/
|
2008-01-25 23:10:02 +08:00
|
|
|
static int
|
2013-10-07 18:56:24 +08:00
|
|
|
setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
|
2005-07-28 02:44:44 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
unsigned long return_ip;
|
|
|
|
struct signal_frame __user *frame;
|
|
|
|
|
|
|
|
err = 0;
|
2014-03-05 21:54:10 +08:00
|
|
|
frame = get_sigframe(ksig, sizeof(*frame));
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
|
|
|
|
|
|
|
|
if (err)
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
if (_NSIG_WORDS > 1) {
|
|
|
|
err |= __copy_to_user(frame->extramask, &set->sig[1],
|
|
|
|
sizeof(frame->extramask));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err)
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up to return from user-space. If provided, use a stub
|
|
|
|
* already located in user-space.
|
|
|
|
*/
|
2013-10-07 18:56:24 +08:00
|
|
|
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
|
|
|
return_ip = (unsigned long)ksig->ka.sa.sa_restorer;
|
2005-07-28 02:44:44 +08:00
|
|
|
} else {
|
|
|
|
/* Trampoline - the desired return ip is in the signal return page. */
|
|
|
|
return_ip = cris_signal_return_page;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is movu.w __NR_sigreturn, r9; break 13;
|
|
|
|
*
|
|
|
|
* WE DO NOT USE IT ANY MORE! It's only left here for historical
|
|
|
|
* reasons and because gdb uses it as a signature to notice
|
|
|
|
* signal handler stack frames.
|
|
|
|
*/
|
|
|
|
err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
|
|
|
|
err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2));
|
|
|
|
err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err)
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up registers for signal handler.
|
|
|
|
*
|
|
|
|
* Where the code enters now.
|
|
|
|
* Where the code enter later.
|
|
|
|
* First argument, signo.
|
|
|
|
*/
|
2013-10-07 18:56:24 +08:00
|
|
|
regs->erp = (unsigned long) ksig->ka.sa.sa_handler;
|
2005-07-28 02:44:44 +08:00
|
|
|
regs->srp = return_ip;
|
2013-10-07 18:56:24 +08:00
|
|
|
regs->r10 = ksig->sig;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/* Actually move the USP to reflect the stacked frame. */
|
|
|
|
wrusp((unsigned long)frame);
|
|
|
|
|
2008-01-25 23:10:02 +08:00
|
|
|
return 0;
|
2005-07-28 02:44:44 +08:00
|
|
|
}
|
|
|
|
|
2008-01-25 23:10:02 +08:00
|
|
|
static int
|
2013-10-07 18:56:24 +08:00
|
|
|
setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
|
2005-07-28 02:44:44 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
unsigned long return_ip;
|
|
|
|
struct rt_signal_frame __user *frame;
|
|
|
|
|
|
|
|
err = 0;
|
2014-03-05 21:54:10 +08:00
|
|
|
frame = get_sigframe(ksig, sizeof(*frame));
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
err |= __put_user(&frame->info, &frame->pinfo);
|
|
|
|
err |= __put_user(&frame->uc, &frame->puc);
|
2013-10-07 18:56:24 +08:00
|
|
|
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
if (err)
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/* Clear all the bits of the ucontext we don't use. */
|
|
|
|
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
|
|
|
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
|
|
|
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
2012-12-23 15:11:49 +08:00
|
|
|
err |= __save_altstack(&frame->uc.uc_stack, rdusp());
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
if (err)
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up to return from user-space. If provided, use a stub
|
|
|
|
* already located in user-space.
|
|
|
|
*/
|
2013-10-07 18:56:24 +08:00
|
|
|
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
|
|
|
|
return_ip = (unsigned long) ksig->ka.sa.sa_restorer;
|
2005-07-28 02:44:44 +08:00
|
|
|
} else {
|
|
|
|
/* Trampoline - the desired return ip is in the signal return page. */
|
|
|
|
return_ip = cris_signal_return_page + 6;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is movu.w __NR_rt_sigreturn, r9; break 13;
|
|
|
|
*
|
|
|
|
* WE DO NOT USE IT ANY MORE! It's only left here for historical
|
|
|
|
* reasons and because gdb uses it as a signature to notice
|
|
|
|
* signal handler stack frames.
|
|
|
|
*/
|
|
|
|
err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
|
|
|
|
|
|
|
|
err |= __put_user(__NR_rt_sigreturn,
|
|
|
|
(short __user*)(frame->retcode+2));
|
|
|
|
|
|
|
|
err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err)
|
2013-10-07 18:56:24 +08:00
|
|
|
return -EFAULT;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up registers for signal handler.
|
|
|
|
*
|
|
|
|
* Where the code enters now.
|
|
|
|
* Where the code enters later.
|
|
|
|
* First argument is signo.
|
|
|
|
* Second argument is (siginfo_t *).
|
|
|
|
* Third argument is unused.
|
|
|
|
*/
|
2013-10-07 18:56:24 +08:00
|
|
|
regs->erp = (unsigned long) ksig->ka.sa.sa_handler;
|
2005-07-28 02:44:44 +08:00
|
|
|
regs->srp = return_ip;
|
2013-10-07 18:56:24 +08:00
|
|
|
regs->r10 = ksig->sig;
|
2005-07-28 02:44:44 +08:00
|
|
|
regs->r11 = (unsigned long) &frame->info;
|
|
|
|
regs->r12 = 0;
|
|
|
|
|
|
|
|
/* Actually move the usp to reflect the stacked frame. */
|
|
|
|
wrusp((unsigned long)frame);
|
|
|
|
|
2008-01-25 23:10:02 +08:00
|
|
|
return 0;
|
2005-07-28 02:44:44 +08:00
|
|
|
}
|
|
|
|
|
2008-12-23 07:54:00 +08:00
|
|
|
/* Invoke a signal handler to, well, handle the signal. */
|
2012-05-22 11:42:15 +08:00
|
|
|
static inline void
|
2013-10-07 18:56:24 +08:00
|
|
|
handle_signal(int canrestart, struct ksignal *ksig, struct pt_regs *regs)
|
2005-07-28 02:44:44 +08:00
|
|
|
{
|
2012-05-02 21:59:21 +08:00
|
|
|
sigset_t *oldset = sigmask_to_save();
|
2008-01-25 23:10:02 +08:00
|
|
|
int ret;
|
|
|
|
|
2005-07-28 02:44:44 +08:00
|
|
|
/* Check if this got called from a system call. */
|
|
|
|
if (canrestart) {
|
|
|
|
/* If so, check system call restarting. */
|
|
|
|
switch (regs->r10) {
|
|
|
|
case -ERESTART_RESTARTBLOCK:
|
|
|
|
case -ERESTARTNOHAND:
|
|
|
|
/*
|
|
|
|
* This means that the syscall should
|
|
|
|
* only be restarted if there was no
|
|
|
|
* handler for the signal, and since
|
|
|
|
* this point isn't reached unless
|
|
|
|
* there is a handler, there's no need
|
|
|
|
* to restart.
|
|
|
|
*/
|
|
|
|
regs->r10 = -EINTR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case -ERESTARTSYS:
|
|
|
|
/*
|
|
|
|
* This means restart the syscall if
|
|
|
|
* there is no handler, or the handler
|
|
|
|
* was registered with SA_RESTART.
|
|
|
|
*/
|
2013-10-07 18:56:24 +08:00
|
|
|
if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
|
2005-07-28 02:44:44 +08:00
|
|
|
regs->r10 = -EINTR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
|
|
|
case -ERESTARTNOINTR:
|
|
|
|
/*
|
|
|
|
* This means that the syscall should
|
|
|
|
* be called again after the signal
|
|
|
|
* handler returns.
|
|
|
|
*/
|
|
|
|
RESTART_CRIS_SYS(regs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up the stack frame. */
|
2013-10-07 18:56:24 +08:00
|
|
|
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
|
|
|
|
ret = setup_rt_frame(ksig, oldset, regs);
|
2005-07-28 02:44:44 +08:00
|
|
|
else
|
2013-10-07 18:56:24 +08:00
|
|
|
ret = setup_frame(ksig, oldset, regs);
|
2005-07-28 02:44:44 +08:00
|
|
|
|
2013-10-07 18:56:24 +08:00
|
|
|
signal_setup_done(ret, ksig, 0);
|
2005-07-28 02:44:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that 'init' is a special process: it doesn't get signals it doesn't
|
|
|
|
* want to handle. Thus you cannot kill init even with a SIGKILL even by
|
|
|
|
* mistake.
|
|
|
|
*
|
|
|
|
* Also note that the regs structure given here as an argument, is the latest
|
|
|
|
* pushed pt_regs. It may or may not be the same as the first pushed registers
|
|
|
|
* when the initial usermode->kernelmode transition took place. Therefore
|
|
|
|
* we can use user_mode(regs) to see if we came directly from kernel or user
|
|
|
|
* mode below.
|
|
|
|
*/
|
2008-01-25 23:10:02 +08:00
|
|
|
void
|
|
|
|
do_signal(int canrestart, struct pt_regs *regs)
|
2005-07-28 02:44:44 +08:00
|
|
|
{
|
2013-10-07 18:56:24 +08:00
|
|
|
struct ksignal ksig;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
CRISv32: prevent bogus restarts on sigreturn
Al Viro noted that CRIS is vulnerable to bogus restarts on sigreturn.
The fixes CRISv32 by using regs->exs as an additional indicator to
whether we should attempt to restart the syscall or not. EXS is only
used in the sigtrap handling, and in that path we already have r9 (the
other indicator, which indicates if we're in a syscall or not) cleared.
Test case, a port of Al's ARM version from 653d48b22166db2d8 ("arm: fix
really nasty sigreturn bug"):
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
void f(int n)
{
register int r10 asm ("r10") = n;
__asm__ __volatile__(
"ba 1f \n"
"nop \n"
"break 8 \n"
"1: ba . \n"
"nop \n"
:
: "r" (r10)
: "memory");
}
void handler1(int sig) { }
void handler2(int sig) { raise(1); }
void handler3(int sig) { exit(0); }
int main(int argc, char *argv[])
{
struct sigaction s = {.sa_handler = handler2};
struct itimerval t1 = { .it_value = {1} };
struct itimerval t2 = { .it_value = {2} };
signal(1, handler1);
sigemptyset(&s.sa_mask);
sigaddset(&s.sa_mask, 1);
sigaction(SIGALRM, &s, NULL);
signal(SIGVTALRM, handler3);
setitimer(ITIMER_REAL, &t1, NULL);
setitimer(ITIMER_VIRTUAL, &t2, NULL);
f(-513); /* -ERESTARTNOINTR */
return 0;
}
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Link: http://lkml.kernel.org/r/20121208074429.GC4939@ZenIV.linux.org.uk
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Jesper Nilsson <jespern@axis.com>
2015-02-09 00:53:22 +08:00
|
|
|
canrestart = canrestart && ((int)regs->exs >= 0);
|
|
|
|
|
2005-07-28 02:44:44 +08:00
|
|
|
/*
|
|
|
|
* The common case should go fast, which is why this point is
|
|
|
|
* reached from kernel-mode. If that's the case, just return
|
|
|
|
* without doing anything.
|
|
|
|
*/
|
|
|
|
if (!user_mode(regs))
|
2008-01-25 23:10:02 +08:00
|
|
|
return;
|
2005-07-28 02:44:44 +08:00
|
|
|
|
2013-10-07 18:56:24 +08:00
|
|
|
if (get_signal(&ksig)) {
|
2008-01-25 23:10:02 +08:00
|
|
|
/* Whee! Actually deliver the signal. */
|
2013-10-07 18:56:24 +08:00
|
|
|
handle_signal(canrestart, &ksig, regs);
|
2008-01-25 23:10:02 +08:00
|
|
|
return;
|
2005-07-28 02:44:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Got here from a system call? */
|
|
|
|
if (canrestart) {
|
|
|
|
/* Restart the system call - no handlers present. */
|
|
|
|
if (regs->r10 == -ERESTARTNOHAND ||
|
|
|
|
regs->r10 == -ERESTARTSYS ||
|
|
|
|
regs->r10 == -ERESTARTNOINTR) {
|
|
|
|
RESTART_CRIS_SYS(regs);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (regs->r10 == -ERESTART_RESTARTBLOCK){
|
2010-08-03 21:55:48 +08:00
|
|
|
regs->r9 = __NR_restart_syscall;
|
2005-07-28 02:44:44 +08:00
|
|
|
regs->erp -= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-25 23:10:02 +08:00
|
|
|
/* if there's no signal to deliver, we just put the saved sigmask
|
|
|
|
* back */
|
2012-05-22 11:33:55 +08:00
|
|
|
restore_saved_sigmask();
|
2005-07-28 02:44:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
asmlinkage void
|
|
|
|
ugdb_trap_user(struct thread_info *ti, int sig)
|
|
|
|
{
|
|
|
|
if (((user_regs(ti)->exs & 0xff00) >> 8) != SINGLE_STEP_INTR_VECT) {
|
|
|
|
/* Zero single-step PC if the reason we stopped wasn't a single
|
|
|
|
step exception. This is to avoid relying on it when it isn't
|
|
|
|
reliable. */
|
|
|
|
user_regs(ti)->spc = 0;
|
|
|
|
}
|
|
|
|
/* FIXME: Filter out false h/w breakpoint hits (i.e. EDA
|
2011-03-31 09:57:33 +08:00
|
|
|
not within any configured h/w breakpoint range). Synchronize with
|
2005-07-28 02:44:44 +08:00
|
|
|
what already exists for kernel debugging. */
|
|
|
|
if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) {
|
|
|
|
/* Break 8: subtract 2 from ERP unless in a delay slot. */
|
|
|
|
if (!(user_regs(ti)->erp & 0x1))
|
|
|
|
user_regs(ti)->erp -= 2;
|
|
|
|
}
|
|
|
|
sys_kill(ti->task->pid, sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
|
|
|
|
struct pt_regs *regs)
|
|
|
|
{
|
|
|
|
if (oldccs & (1 << Q_CCS_BITNR)) {
|
|
|
|
/* Pending single step due to single-stepping the break 13
|
|
|
|
in the signal trampoline: keep the Q flag. */
|
|
|
|
regs->ccs |= (1 << Q_CCS_BITNR);
|
|
|
|
/* S flag should be set - complain if it's not. */
|
|
|
|
if (!(oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT)))) {
|
|
|
|
printk("Q flag but no S flag?");
|
|
|
|
}
|
|
|
|
regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
|
|
|
|
/* Assume the SPC is valid and interesting. */
|
|
|
|
regs->spc = oldspc;
|
|
|
|
|
|
|
|
} else if (oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT))) {
|
|
|
|
/* If a h/w bp was set in the signal handler we need
|
|
|
|
to keep the S flag. */
|
|
|
|
regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
|
|
|
|
/* Don't keep the old SPC though; if we got here due to
|
|
|
|
a single-step, the Q flag should have been set. */
|
|
|
|
} else if (regs->spc) {
|
|
|
|
/* If we were single-stepping *before* the signal was taken,
|
|
|
|
we don't want to restore that state now, because GDB will
|
|
|
|
have forgotten all about it. */
|
|
|
|
regs->spc = 0;
|
|
|
|
regs->ccs &= ~(1 << (S_CCS_BITNR + CCS_SHIFT));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up the trampolines on the signal return page. */
|
|
|
|
int __init
|
|
|
|
cris_init_signal(void)
|
|
|
|
{
|
2006-12-13 16:35:56 +08:00
|
|
|
u16* data = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
2005-07-28 02:44:44 +08:00
|
|
|
|
|
|
|
/* This is movu.w __NR_sigreturn, r9; break 13; */
|
|
|
|
data[0] = 0x9c5f;
|
|
|
|
data[1] = __NR_sigreturn;
|
|
|
|
data[2] = 0xe93d;
|
|
|
|
/* This is movu.w __NR_rt_sigreturn, r9; break 13; */
|
|
|
|
data[3] = 0x9c5f;
|
|
|
|
data[4] = __NR_rt_sigreturn;
|
|
|
|
data[5] = 0xe93d;
|
|
|
|
|
|
|
|
/* Map to userspace with appropriate permissions (no write access...) */
|
|
|
|
cris_signal_return_page = (unsigned long)
|
|
|
|
__ioremap_prot(virt_to_phys(data), PAGE_SIZE, PAGE_SIGNAL_TRAMPOLINE);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
__initcall(cris_init_signal);
|