X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fs390%2Fkernel%2Fcompat_signal.c;h=e8c8b2fe7af5789b436b47d5990984b71c5cdc6c;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;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..e8c8b2fe7 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; @@ -53,7 +54,7 @@ typedef struct 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(siginfo_t32 __user *to, siginfo_t *from) { int err; @@ -105,6 +106,53 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) return err; } +int copy_siginfo_from_user32(siginfo_t *to, siginfo_t32 __user *from) +{ + int err; + u32 tmp; + + if (!access_ok (VERIFY_READ, from, sizeof(siginfo_t32))) + 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 (from->si_code < 0) + err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); + else { + switch (from->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: + case __SI_TIMER >> 16: + err |= __get_user(to->si_band, &from->si_band); + err |= __get_user(to->si_fd, &from->si_fd); + break; + default: + break; + } + } + return err; +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -130,7 +178,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,11 +211,11 @@ 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; int ret; @@ -199,9 +248,9 @@ 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; int ret; @@ -258,7 +307,8 @@ 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; int ret, err = 0; @@ -275,7 +325,9 @@ sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs) } 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) { @@ -290,7 +342,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 +363,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 +395,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 +417,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 +451,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 +470,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 +491,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 +507,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 +526,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,6 +545,10 @@ 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: @@ -505,7 +561,7 @@ 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 +587,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 */