X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fs390%2Fkernel%2Fcompat_signal.c;h=b728e027bf6f01a6795a13ab557f32924311a953;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=3886a27b8e4de4e4823eeed0cba85ba8844d244d;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 3886a27b8..b728e027b 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -40,6 +40,7 @@ typedef struct __u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; struct sigcontext32 sc; _sigregs32 sregs; + int signo; __u8 retcode[S390_SYSCALL_SIZE]; } sigframe32; @@ -47,17 +48,17 @@ typedef struct { __u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; __u8 retcode[S390_SYSCALL_SIZE]; - struct siginfo32 info; + compat_siginfo_t info; struct ucontext32 uc; } rt_sigframe32; asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); -int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) +int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -94,10 +95,65 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) &to->si_addr); break; case __SI_POLL >> 16: - case __SI_TIMER >> 16: err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_fd, &to->si_fd); break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_overrun, &to->si_overrun); + err |= __put_user(from->si_int, &to->si_int); + break; + default: + break; + } + } + return err; +} + +int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) +{ + int err; + u32 tmp; + + if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t))) + return -EFAULT; + + err = __get_user(to->si_signo, &from->si_signo); + err |= __get_user(to->si_errno, &from->si_errno); + err |= __get_user(to->si_code, &from->si_code); + + if (to->si_code < 0) + err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); + else { + switch (to->si_code >> 16) { + case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ + case __SI_MESGQ >> 16: + err |= __get_user(to->si_int, &from->si_int); + /* fallthrough */ + case __SI_KILL >> 16: + err |= __get_user(to->si_pid, &from->si_pid); + err |= __get_user(to->si_uid, &from->si_uid); + break; + case __SI_CHLD >> 16: + err |= __get_user(to->si_pid, &from->si_pid); + err |= __get_user(to->si_uid, &from->si_uid); + err |= __get_user(to->si_utime, &from->si_utime); + err |= __get_user(to->si_stime, &from->si_stime); + err |= __get_user(to->si_status, &from->si_status); + break; + case __SI_FAULT >> 16: + err |= __get_user(tmp, &from->si_addr); + to->si_addr = (void *)(u64) (tmp & PSW32_ADDR_INSN); + break; + case __SI_POLL >> 16: + err |= __get_user(to->si_band, &from->si_band); + err |= __get_user(to->si_fd, &from->si_fd); + break; + case __SI_TIMER >> 16: + err |= __get_user(to->si_tid, &from->si_tid); + err |= __get_user(to->si_overrun, &from->si_overrun); + err |= __get_user(to->si_int, &from->si_int); + break; default: break; } @@ -130,7 +186,8 @@ sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t } asmlinkage int -sys32_rt_sigsuspend(struct pt_regs * regs,compat_sigset_t *unewset, size_t sigsetsize) +sys32_rt_sigsuspend(struct pt_regs * regs, compat_sigset_t __user *unewset, + size_t sigsetsize) { sigset_t saveset, newset; compat_sigset_t set32; @@ -162,21 +219,24 @@ sys32_rt_sigsuspend(struct pt_regs * regs,compat_sigset_t *unewset, size_t sigse if (do_signal(regs, &saveset)) return -EINTR; } -} +} asmlinkage long -sys32_sigaction(int sig, const struct old_sigaction32 *act, - struct old_sigaction32 *oact) +sys32_sigaction(int sig, const struct old_sigaction32 __user *act, + struct old_sigaction32 __user *oact) { struct k_sigaction new_ka, old_ka; + unsigned long sa_handler, sa_restorer; int ret; if (act) { compat_old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler) || - __get_user((unsigned long)new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(sa_handler, &act->sa_handler) || + __get_user(sa_restorer, &act->sa_restorer)) return -EFAULT; + new_ka.sa.sa_handler = (__sighandler_t) sa_handler; + new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer; __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); @@ -185,9 +245,11 @@ sys32_sigaction(int sig, const struct old_sigaction32 *act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { + sa_handler = (unsigned long) old_ka.sa.sa_handler; + sa_restorer = (unsigned long) old_ka.sa.sa_restorer; if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user((unsigned long)old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(sa_handler, &oact->sa_handler) || + __put_user(sa_restorer, &oact->sa_restorer)) return -EFAULT; __put_user(old_ka.sa.sa_flags, &oact->sa_flags); __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); @@ -199,11 +261,12 @@ sys32_sigaction(int sig, const struct old_sigaction32 *act, int do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact); -asmlinkage long -sys32_rt_sigaction(int sig, const struct sigaction32 *act, - struct sigaction32 *oact, size_t sigsetsize) +asmlinkage long +sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, + struct sigaction32 __user *oact, size_t sigsetsize) { struct k_sigaction new_ka, old_ka; + unsigned long sa_handler; int ret; compat_sigset_t set32; @@ -212,7 +275,7 @@ sys32_rt_sigaction(int sig, const struct sigaction32 *act, return -EINVAL; if (act) { - ret = get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler); + ret = get_user(sa_handler, &act->sa_handler); ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); switch (_NSIG_WORDS) { @@ -229,6 +292,7 @@ sys32_rt_sigaction(int sig, const struct sigaction32 *act, if (ret) return -EFAULT; + new_ka.sa.sa_handler = (__sighandler_t) sa_handler; } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); @@ -258,30 +322,36 @@ sys32_rt_sigaction(int sig, const struct sigaction32 *act, } asmlinkage long -sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs) +sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss, + struct pt_regs *regs) { stack_t kss, koss; + unsigned long ss_sp; int ret, err = 0; mm_segment_t old_fs = get_fs(); if (uss) { if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) return -EFAULT; - err |= __get_user((unsigned long) kss.ss_sp, &uss->ss_sp); + err |= __get_user(ss_sp, &uss->ss_sp); err |= __get_user(kss.ss_size, &uss->ss_size); err |= __get_user(kss.ss_flags, &uss->ss_flags); if (err) return -EFAULT; + kss.ss_sp = (void *) ss_sp; } set_fs (KERNEL_DS); - ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, regs->gprs[15]); + ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL), + (stack_t __user *) (uoss ? &koss : NULL), + regs->gprs[15]); set_fs (old_fs); if (!ret && uoss) { if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) return -EFAULT; - err |= __put_user((unsigned long) koss.ss_sp, &uoss->ss_sp); + ss_sp = (unsigned long) koss.ss_sp; + err |= __put_user(ss_sp, &uoss->ss_sp); err |= __put_user(koss.ss_size, &uoss->ss_size); err |= __put_user(koss.ss_flags, &uoss->ss_flags); if (err) @@ -290,7 +360,7 @@ sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs) return ret; } -static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) +static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs) { _s390_regs_common32 regs32; int err, i; @@ -311,7 +381,7 @@ static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) sizeof(_s390_fp_regs32)); } -static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) +static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) { _s390_regs_common32 regs32; int err, i; @@ -343,7 +413,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs) asmlinkage long sys32_sigreturn(struct pt_regs *regs) { - sigframe32 *frame = (sigframe32 *)regs->gprs[15]; + sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; sigset_t set; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) @@ -365,11 +435,11 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs) badframe: force_sig(SIGSEGV, current); return 0; -} +} asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) { - rt_sigframe32 *frame = (rt_sigframe32 *)regs->gprs[15]; + rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; sigset_t set; stack_t st; __u32 ss_sp; @@ -399,8 +469,8 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - set_fs (KERNEL_DS); - do_sigaltstack(&st, NULL, regs->gprs[15]); + set_fs (KERNEL_DS); + do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]); set_fs (old_fs); return regs->gprs[2]; @@ -418,7 +488,7 @@ badframe: /* * Determine which stack to use.. */ -static inline void * +static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long sp; @@ -439,7 +509,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) sp = (unsigned long) ka->sa.sa_restorer; } - return (void *)((sp - frame_size) & -8ul); + return (void __user *)((sp - frame_size) & -8ul); } static inline int map_signal(int sig) @@ -455,7 +525,7 @@ static inline int map_signal(int sig) static void setup_frame32(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { - sigframe32 *frame = get_sigframe(ka, regs, sizeof(sigframe32)); + sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32)); if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32))) goto give_sigsegv; @@ -474,12 +544,12 @@ static void setup_frame32(int sig, struct k_sigaction *ka, } else { regs->gprs[14] = (__u64) frame->retcode; if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, - (u16 *)(frame->retcode))) + (u16 __user *)(frame->retcode))) goto give_sigsegv; } /* Set up backchain. */ - if (__put_user(regs->gprs[15], (unsigned int *) frame)) + if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) goto give_sigsegv; /* Set up registers for signal handler */ @@ -493,19 +563,21 @@ static void setup_frame32(int sig, struct k_sigaction *ka, To avoid breaking binary compatibility, they are passed as args. */ regs->gprs[4] = current->thread.trap_no; regs->gprs[5] = current->thread.prot_addr; + + /* Place signal number on stack to allow backtrace from handler. */ + if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) + goto give_sigsegv; return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { int err = 0; - rt_sigframe32 *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32)); + rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32)); if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32))) goto give_sigsegv; @@ -531,11 +603,11 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, } else { regs->gprs[14] = (__u64) frame->retcode; err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, - (u16 *)(frame->retcode)); + (u16 __user *)(frame->retcode)); } /* Set up backchain. */ - if (__put_user(regs->gprs[15], (unsigned int *) frame)) + if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) goto give_sigsegv; /* Set up registers for signal handler */ @@ -548,9 +620,7 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* @@ -558,20 +628,15 @@ give_sigsegv: */ void -handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs) +handle_signal32(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame32(sig, ka, info, oldset, regs); else setup_frame32(sig, ka, oldset, regs); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);