Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=431dc8040354db65e4f8d4d4e21ae4fab41f5bc3
Commit:     431dc8040354db65e4f8d4d4e21ae4fab41f5bc3
Parent:     366d6aef281a670b32a51d289fc07bf0e5e72d9a
Author:     Ralf Baechle <[EMAIL PROTECTED]>
AuthorDate: Tue Feb 13 00:05:11 2007 +0000
Committer:  Ralf Baechle <[EMAIL PROTECTED]>
CommitDate: Tue Feb 13 22:40:51 2007 +0000

    [MIPS] Fix sigset_t endianess swapping issues in 32-bit compat code.
    
    Signed-off-by: Ralf Baechle <[EMAIL PROTECTED]>
---
 arch/mips/kernel/linux32.c       |   47 ++++++++++++++++++++++++++++++++
 arch/mips/kernel/scall64-64.S    |    2 +-
 arch/mips/kernel/scall64-n32.S   |    2 +-
 arch/mips/kernel/signal32.c      |   11 +++++---
 arch/mips/kernel/signal_n32.c    |    7 +++--
 include/asm-mips/compat-signal.h |   55 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 115 insertions(+), 9 deletions(-)

diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index ca7ad78..fc4dd6c 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -39,6 +39,7 @@
 #include <net/sock.h>
 #include <net/scm.h>
 
+#include <asm/compat-signal.h>
 #include <asm/ipc.h>
 #include <asm/sim.h>
 #include <asm/uaccess.h>
@@ -736,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
        return do_fork(clone_flags, newsp, &regs, 0,
                       parent_tidptr, child_tidptr);
 }
+
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_pwait(2).
+ */
+asmlinkage long compat_sys_epoll_pwait(int epfd,
+       struct epoll_event __user *events, int maxevents, int timeout,
+       const compat_sigset_t __user *sigmask, size_t sigsetsize)
+{
+       int error;
+       sigset_t ksigmask, sigsaved;
+
+       /*
+        * If the caller wants a certain signal mask to be set during the wait,
+        * we apply it here.
+        */
+       if (sigmask) {
+               if (sigsetsize != sizeof(sigset_t))
+                       return -EINVAL;
+               if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask)))
+                       return -EFAULT;
+               if (__copy_conv_sigset_from_user(&ksigmask, sigmask))
+                       return -EFAULT;
+               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+       }
+
+       error = sys_epoll_wait(epfd, events, maxevents, timeout);
+
+       /*
+        * If we changed the signal mask, we need to restore the original one.
+        * In case we've got a signal while waiting, we do not restore the
+        * signal mask yet, and we allow do_signal() to deliver the signal on
+        * the way back to userspace, before the signal mask is restored.
+        */
+       if (sigmask) {
+               if (error == -EINTR) {
+                       memcpy(&current->saved_sigmask, &sigsaved,
+                               sizeof(sigsaved));
+                       set_thread_flag(TIF_RESTORE_SIGMASK);
+               } else
+                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+       }
+
+       return error;
+}
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index e569b84..10e9a18 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -470,4 +470,4 @@ sys_call_table:
        PTR     sys_get_robust_list
        PTR     sys_kexec_load                  /* 5270 */
        PTR     sys_getcpu
-       PTR     sys_epoll_pwait
+       PTR     compat_sys_epoll_pwait
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index ee8802b..2ceda46 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -396,4 +396,4 @@ EXPORT(sysn32_call_table)
        PTR     compat_sys_get_robust_list
        PTR     compat_sys_kexec_load
        PTR     sys_getcpu
-       PTR     sys_epoll_pwait
+       PTR     compat_sys_epoll_pwait
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index db00c33..c28cb21 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -8,6 +8,7 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #include <linux/cache.h>
+#include <linux/compat.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -24,6 +25,7 @@
 
 #include <asm/abi.h>
 #include <asm/asm.h>
+#include <asm/compat-signal.h>
 #include <linux/bitops.h>
 #include <asm/cacheflush.h>
 #include <asm/sim.h>
@@ -517,7 +519,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct 
pt_regs regs)
        frame = (struct sigframe32 __user *) regs.regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
-       if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
+       if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
                goto badframe;
 
        sigdelsetmask(&blocked, ~_BLOCKABLE);
@@ -554,7 +556,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct 
pt_regs regs)
        frame = (struct rt_sigframe32 __user *) regs.regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
-       if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
+       if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
                goto badframe;
 
        sigdelsetmask(&set, ~_BLOCKABLE);
@@ -609,7 +611,8 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs 
*regs,
        err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
 
        err |= setup_sigcontext32(regs, &frame->sf_sc);
-       err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
+       err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
+
        if (err)
                goto give_sigsegv;
 
@@ -668,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct 
pt_regs *regs,
        err |= __put_user(current->sas_ss_size,
                          &frame->rs_uc.uc_stack.ss_size);
        err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
-       err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
+       err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
 
        if (err)
                goto give_sigsegv;
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 1a5f248..7ca2a07 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -31,6 +31,7 @@
 
 #include <asm/asm.h>
 #include <asm/cacheflush.h>
+#include <asm/compat-signal.h>
 #include <asm/sim.h>
 #include <asm/uaccess.h>
 #include <asm/ucontext.h>
@@ -63,7 +64,7 @@ struct ucontextn32 {
        s32                 uc_link;
        stack32_t           uc_stack;
        struct sigcontext   uc_mcontext;
-       sigset_t            uc_sigmask;   /* mask last for extensibility */
+       compat_sigset_t     uc_sigmask;   /* mask last for extensibility */
 };
 
 #if ICACHE_REFILLS_WORKAROUND_WAR == 0
@@ -129,7 +130,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct 
pt_regs regs)
        frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
                goto badframe;
-       if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
+       if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
                goto badframe;
 
        sigdelsetmask(&set, ~_BLOCKABLE);
@@ -195,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
        err |= __put_user(current->sas_ss_size,
                          &frame->rs_uc.uc_stack.ss_size);
        err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
-       err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
+       err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
 
        if (err)
                goto give_sigsegv;
diff --git a/include/asm-mips/compat-signal.h b/include/asm-mips/compat-signal.h
new file mode 100644
index 0000000..6720770
--- /dev/null
+++ b/include/asm-mips/compat-signal.h
@@ -0,0 +1,55 @@
+#ifndef __ASM_COMPAT_SIGNAL_H
+#define __ASM_COMPAT_SIGNAL_H
+
+#include <linux/bug.h>
+#include <linux/compat.h>
+#include <linux/compiler.h>
+
+static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d,
+       const sigset_t *s)
+{
+       int err;
+
+       BUG_ON(sizeof(*d) != sizeof(*s));
+       BUG_ON(_NSIG_WORDS != 2);
+
+       err  = __put_user(s->sig[0],       &d->sig[0]);
+       err |= __put_user(s->sig[0] >> 32, &d->sig[1]);
+       err |= __put_user(s->sig[1],       &d->sig[2]);
+       err |= __put_user(s->sig[1] >> 32, &d->sig[3]);
+
+       return err;
+}
+
+static inline int __copy_conv_sigset_from_user(sigset_t *d,
+       const compat_sigset_t __user *s)
+{
+       int err;
+       union sigset_u {
+               sigset_t        s;
+               compat_sigset_t c;
+       } *u = (union sigset_u *) d;
+
+       BUG_ON(sizeof(*d) != sizeof(*s));
+       BUG_ON(_NSIG_WORDS != 2);
+
+       if (unlikely(!access_ok(VERIFY_READ, d, sizeof(*d))))
+               return -EFAULT;
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       err  = __get_user(u->c.sig[1], &s->sig[0]);
+       err |= __get_user(u->c.sig[0], &s->sig[1]);
+       err |= __get_user(u->c.sig[3], &s->sig[2]);
+       err |= __get_user(u->c.sig[2], &s->sig[3]);
+#endif
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+       err  = __get_user(u->c.sig[0], &s->sig[0]);
+       err |= __get_user(u->c.sig[1], &s->sig[1]);
+       err |= __get_user(u->c.sig[2], &s->sig[2]);
+       err |= __get_user(u->c.sig[3], &s->sig[3]);
+#endif
+
+       return err;
+}
+
+#endif /* __ASM_COMPAT_SIGNAL_H */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to