summaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/signal.c')
-rw-r--r--arch/s390/kernel/signal.c83
1 files changed, 59 insertions, 24 deletions
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 7809a4a2b..de05ec764 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -2,7 +2,7 @@
* arch/s390/kernel/signal.c
*
* S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*
* Based on Intel version
@@ -37,7 +37,7 @@
#define SIGFRAME_COMMON \
__u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \
struct sigcontext sc; \
-sigregs sregs; \
+_sigregs sregs; \
__u8 retcode[S390_SYSCALL_SIZE];
typedef struct
@@ -54,6 +54,41 @@ typedef struct
asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -71,7 +106,7 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma
regs->gprs[2] = -EINTR;
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
@@ -99,7 +134,7 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
regs->gprs[2] = -EINTR;
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
@@ -139,16 +174,15 @@ sys_sigaction(int sig, const struct old_sigaction *act,
}
asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *) &uss;
return do_sigaltstack(uss, uoss, regs->gprs[15]);
}
-static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int save_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
@@ -163,7 +197,7 @@ static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
}
-static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
@@ -185,13 +219,13 @@ static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
static int
restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
- sigregs *sregs,sigset_t *set)
+ _sigregs *sregs,sigset_t *set)
{
unsigned int err;
err=restore_sigregs(regs,sregs);
if(!err)
- err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE);
+ err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
return(err);
}
@@ -227,15 +261,12 @@ badframe:
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
- stack_t st;
if (sigreturn_common(regs,sizeof(rt_sigframe)))
goto badframe;
- if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
- goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs->gprs[15]);
+ do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
return regs->gprs[2];
badframe:
@@ -290,7 +321,7 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
err=__put_user(&frame->sregs,&frame->sc.sregs);
if(!err)
- err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE);
+ err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
if(!err)
{
regs->gprs[2]=(current->exec_domain
@@ -316,14 +347,17 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
static void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs)
{
+ sigframe *frame;
- if(!setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
- (S390_SYSCALL_OPCODE|__NR_sigreturn)))
+ if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
+ (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
goto give_sigsegv;
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->eip, frame->pretcode);
#endif
+ /* Martin wants this for pthreads */
+ regs->gprs[3] = (addr_t)&frame->sc;
return;
give_sigsegv:
@@ -343,7 +377,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
(S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
goto give_sigsegv;
- err = __copy_to_user(&frame->info, info, sizeof(*info));
+ err = copy_siginfo_to_user(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -352,8 +386,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(sas_ss_flags(orig_sp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- regs->gprs[3] = (u32)&frame->info;
- regs->gprs[4] = (u32)&frame->uc;
+ err |= __put_user(&frame->sc,&frame->uc.sc);
+ regs->gprs[3] = (addr_t)&frame->info;
+ regs->gprs[4] = (addr_t)&frame->uc;
if (err)
goto give_sigsegv;
@@ -452,10 +487,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!signr)
break;
- if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
/* Let the debugger run. */
current->exit_code = signr;
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
notify_parent(current, SIGCHLD);
schedule();
@@ -511,7 +546,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
/* FALLTHRU */
case SIGSTOP:
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
@@ -540,7 +575,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
}
/* Did we come from a system call? */
- if ( regs->trap == 0x20 /* System Call! */ ) {
+ if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
/* Restart the system call - no handlers present */
if (regs->gprs[2] == -ERESTARTNOHAND ||
regs->gprs[2] == -ERESTARTSYS ||