diff options
Diffstat (limited to 'arch/s390/kernel/signal.c')
-rw-r--r-- | arch/s390/kernel/signal.c | 83 |
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 || |