From 35fd5eb6a16239d684d509f74380ddef0f59194b Mon Sep 17 00:00:00 2001 From: Ulf Carlsson Date: Sat, 13 May 2000 02:37:18 +0000 Subject: sigset_t fixes and a few new functions.. --- arch/mips64/kernel/signal32.c | 228 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 204 insertions(+), 24 deletions(-) (limited to 'arch/mips64/kernel/signal32.c') diff --git a/arch/mips64/kernel/signal32.c b/arch/mips64/kernel/signal32.c index e33a69d5e..7d4ce3050 100644 --- a/arch/mips64/kernel/signal32.c +++ b/arch/mips64/kernel/signal32.c @@ -61,7 +61,7 @@ struct sigaction32 { /* IRIX compatible stack_t */ typedef struct sigaltstack32 { void *ss_sp; - size_t ss_size; + __kernel_size_t32 ss_size; int ss_flags; } stack32_t; @@ -95,18 +95,72 @@ static inline int refill_fp_context(struct sigcontext *sc) return err; } +extern void __put_sigset_unknown_nsig(void); +extern void __get_sigset_unknown_nsig(void); + +static inline int +put_sigset(const sigset_t *kbuf, sigset32_t *ubuf) +{ + int err = 0; + + if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) + return -EFAULT; + + switch (_NSIG_WORDS) { + default: + __put_sigset_unknown_nsig(); + case 2: + err |= __put_user (kbuf->sig[1] >> 32, &ubuf->sig[3]); + err |= __put_user (kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); + case 1: + err |= __put_user (kbuf->sig[0] >> 32, &ubuf->sig[1]); + err |= __put_user (kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); + } + + return err; +} + +static inline int +get_sigset(sigset_t *kbuf, const sigset32_t *ubuf) +{ + int err = 0; + unsigned long sig[4]; + + if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) + return -EFAULT; + + switch (_NSIG_WORDS) { + default: + __get_sigset_unknown_nsig(); + case 2: + err |= __get_user (sig[3], &ubuf->sig[3]); + err |= __get_user (sig[2], &ubuf->sig[2]); + kbuf->sig[1] = sig[2] | (sig[3] << 32); + case 1: + err |= __get_user (sig[1], &ubuf->sig[1]); + err |= __get_user (sig[0], &ubuf->sig[0]); + kbuf->sig[0] = sig[0] | (sig[1] << 32); + } + + return err; +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage inline int sys32_sigsuspend(abi64_no_regargs, struct pt_regs regs) { - sigset_t *uset, saveset, newset; + sigset32_t *uset; + sigset_t newset, saveset; - save_static(®s); +#if DEBUG_MIPS64 printk("%s called.\n", __FUNCTION__); - uset = (sigset_t *) regs.regs[4]; - if (copy_from_user(&newset, uset, sizeof(sigset_t))) +#endif + + save_static(®s); + uset = (sigset32_t *) regs.regs[4]; + if (get_sigset(&newset, uset)) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); @@ -129,19 +183,22 @@ printk("%s called.\n", __FUNCTION__); asmlinkage int sys32_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs) { - sigset_t *unewset, saveset, newset; + sigset32_t *uset; + sigset_t newset, saveset; size_t sigsetsize; - save_static(®s); +#if DEBUG_MIPS64 printk("%s called.\n", __FUNCTION__); +#endif + save_static(®s); /* XXX Don't preclude handling different sized sigset_t's. */ sigsetsize = regs.regs[5]; - if (sigsetsize != sizeof(sigset_t)) + if (sigsetsize != sizeof(sigset32_t)) return -EINVAL; - unewset = (sigset_t *) regs.regs[4]; - if (copy_from_user(&newset, unewset, sizeof(newset))) + uset = (sigset32_t *) regs.regs[4]; + if (get_sigset(&newset, uset)) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); @@ -205,12 +262,37 @@ asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, asmlinkage int sys32_sigaltstack(abi64_no_regargs, struct pt_regs regs) { - const stack_t *uss = (const stack_t *) regs.regs[4]; - stack_t *uoss = (stack_t *) regs.regs[5]; + const stack32_t *uss = (const stack32_t *) regs.regs[4]; + stack32_t *uoss = (stack32_t *) regs.regs[5]; unsigned long usp = regs.regs[29]; -printk("%s called.\n", __FUNCTION__); + stack_t kss, koss; + 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(kss.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; + } - return do_sigaltstack(uss, uoss, usp); + set_fs (KERNEL_DS); + ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, usp); + set_fs (old_fs); + + if (!ret && uoss) { + if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) + return -EFAULT; + err |= __put_user(koss.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) + return -EFAULT; + } + return ret; } static asmlinkage int @@ -724,26 +806,124 @@ extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset); asmlinkage int sys32_sigprocmask(int how, old_sigset_t32 *set, - old_sigset_t32 *oset) + old_sigset_t32 *oset) { old_sigset_t s; int ret; mm_segment_t old_fs = get_fs(); - if (set && get_user (s, set)) return -EFAULT; + if (set && get_user (s, set)) + return -EFAULT; set_fs (KERNEL_DS); ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); set_fs (old_fs); - if (ret) return ret; - if (oset && put_user (s, oset)) return -EFAULT; - return 0; + if (!ret && oset && put_user (s, oset)) + return -EFAULT; + return ret; +} + +asmlinkage long sys_sigpending(old_sigset_t *set); + +asmlinkage int sys32_sigpending(old_sigset_t32 *set) +{ + old_sigset_t pending; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_sigpending(&pending); + set_fs (old_fs); + + if (put_user(pending, set)) + return -EFAULT; + + return ret; } -/* Dummies ... */ +asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, + struct sigaction32 *oact, + unsigned int sigsetsize) +{ + struct k_sigaction new_sa, old_sa; + int ret = -EINVAL; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + goto out; + + if (act) { + int err = 0; + + if (!access_ok(VERIFY_READ, act, sizeof(*act))) + return -EFAULT; + err |= __get_user (new_sa.sa.sa_handler, &act->sa_handler); + err |= __get_user (new_sa.sa.sa_flags, &act->sa_flags); + err |= __get_user (new_sa.sa.sa_restorer, &act->sa_restorer); + err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); + if (err) + return -EFAULT; + } + + ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); + + if (!ret && oact) { + int err = 0; + + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) + return -EFAULT; + + err |= __put_user (new_sa.sa.sa_handler, &oact->sa_handler); + err |= __put_user (new_sa.sa.sa_flags, &oact->sa_flags); + err |= __put_user (new_sa.sa.sa_restorer, &oact->sa_restorer); + err |= put_sigset(&new_sa.sa.sa_mask, &oact->sa_mask); + if (err) + return -EFAULT; + } +out: + return ret; +} + +asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, + size_t sigsetsize); + +asmlinkage int sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset, + unsigned int sigsetsize) +{ + sigset_t old_set, new_set; + int ret; + mm_segment_t old_fs = get_fs(); + + if (set && get_sigset(&new_set, set)) + return -EFAULT; + + set_fs (KERNEL_DS); + ret = sys_rt_sigprocmask(how, set ? &new_set : NULL, + oset ? &old_set : NULL, sigsetsize); + set_fs (old_fs); + + if (!ret && oset && put_sigset(&old_set, oset)) + return -EFAULT; + + return ret; +} + +asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); + +asmlinkage int sys32_rt_sigpending(sigset32_t *uset, unsigned int sigsetsize) +{ + int ret; + sigset_t set; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_rt_sigpending(&set, sigsetsize); + set_fs (old_fs); + + if (!ret && put_sigset(&set, uset)) + return -EFAULT; + + return ret; +} -asmlinkage void sys32_sigpending(void) { panic(__FUNCTION__ " called."); } -asmlinkage void sys32_rt_sigaction(void) { panic(__FUNCTION__ " called."); } -asmlinkage void sys32_rt_sigprocmask(void) { panic(__FUNCTION__ " called."); } -asmlinkage void sys32_rt_sigpending(void) { panic(__FUNCTION__ " called."); } asmlinkage void sys32_rt_sigtimedwait(void) { panic(__FUNCTION__ " called."); } asmlinkage void sys32_rt_sigqueueinfo(void) { panic(__FUNCTION__ " called."); } -- cgit v1.2.3