Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux-2.6-microblaze.git] / kernel / signal.c
index 9a32bc2..e1d7ad8 100644 (file)
@@ -2735,6 +2735,84 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
 }
 EXPORT_SYMBOL(sigprocmask);
 
+/*
+ * The api helps set app-provided sigmasks.
+ *
+ * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
+ * epoll_pwait where a new sigmask is passed from userland for the syscalls.
+ */
+int set_user_sigmask(const sigset_t __user *usigmask, sigset_t *set,
+                    sigset_t *oldset, size_t sigsetsize)
+{
+       if (!usigmask)
+               return 0;
+
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+       if (copy_from_user(set, usigmask, sizeof(sigset_t)))
+               return -EFAULT;
+
+       *oldset = current->blocked;
+       set_current_blocked(set);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_user_sigmask);
+
+#ifdef CONFIG_COMPAT
+int set_compat_user_sigmask(const compat_sigset_t __user *usigmask,
+                           sigset_t *set, sigset_t *oldset,
+                           size_t sigsetsize)
+{
+       if (!usigmask)
+               return 0;
+
+       if (sigsetsize != sizeof(compat_sigset_t))
+               return -EINVAL;
+       if (get_compat_sigset(set, usigmask))
+               return -EFAULT;
+
+       *oldset = current->blocked;
+       set_current_blocked(set);
+
+       return 0;
+}
+EXPORT_SYMBOL(set_compat_user_sigmask);
+#endif
+
+/*
+ * restore_user_sigmask:
+ * usigmask: sigmask passed in from userland.
+ * sigsaved: saved sigmask when the syscall started and changed the sigmask to
+ *           usigmask.
+ *
+ * This is useful for syscalls such as ppoll, pselect, io_pgetevents and
+ * epoll_pwait where a new sigmask is passed in from userland for the syscalls.
+ */
+void restore_user_sigmask(const void __user *usigmask, sigset_t *sigsaved)
+{
+
+       if (!usigmask)
+               return;
+       /*
+        * When signals are pending, do not restore them here.
+        * Restoring sigmask here can lead to delivering signals that the above
+        * syscalls are intended to block because of the sigmask passed in.
+        */
+       if (signal_pending(current)) {
+               current->saved_sigmask = *sigsaved;
+               set_restore_sigmask();
+               return;
+       }
+
+       /*
+        * This is needed because the fast syscall return path does not restore
+        * saved_sigmask when signals are not pending.
+        */
+       set_current_blocked(sigsaved);
+}
+EXPORT_SYMBOL(restore_user_sigmask);
+
 /**
  *  sys_rt_sigprocmask - change the list of currently blocked signals
  *  @how: whether to add, remove, or set signals
@@ -3254,7 +3332,71 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
        return ret;
 }
 
+#ifdef CONFIG_COMPAT_32BIT_TIME
+SYSCALL_DEFINE4(rt_sigtimedwait_time32, const sigset_t __user *, uthese,
+               siginfo_t __user *, uinfo,
+               const struct old_timespec32 __user *, uts,
+               size_t, sigsetsize)
+{
+       sigset_t these;
+       struct timespec64 ts;
+       kernel_siginfo_t info;
+       int ret;
+
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (copy_from_user(&these, uthese, sizeof(these)))
+               return -EFAULT;
+
+       if (uts) {
+               if (get_old_timespec32(&ts, uts))
+                       return -EFAULT;
+       }
+
+       ret = do_sigtimedwait(&these, &info, uts ? &ts : NULL);
+
+       if (ret > 0 && uinfo) {
+               if (copy_siginfo_to_user(uinfo, &info))
+                       ret = -EFAULT;
+       }
+
+       return ret;
+}
+#endif
+
 #ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time64, compat_sigset_t __user *, uthese,
+               struct compat_siginfo __user *, uinfo,
+               struct __kernel_timespec __user *, uts, compat_size_t, sigsetsize)
+{
+       sigset_t s;
+       struct timespec64 t;
+       kernel_siginfo_t info;
+       long ret;
+
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (get_compat_sigset(&s, uthese))
+               return -EFAULT;
+
+       if (uts) {
+               if (get_timespec64(&t, uts))
+                       return -EFAULT;
+       }
+
+       ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
+
+       if (ret > 0 && uinfo) {
+               if (copy_siginfo_to_user32(uinfo, &info))
+                       ret = -EFAULT;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT_32BIT_TIME
 COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
                struct compat_siginfo __user *, uinfo,
                struct old_timespec32 __user *, uts, compat_size_t, sigsetsize)
@@ -3285,6 +3427,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
        return ret;
 }
 #endif
+#endif
 
 /**
  *  sys_kill - send a signal to a process
@@ -3854,7 +3997,7 @@ SYSCALL_DEFINE3(sigaction, int, sig,
 
        if (act) {
                old_sigset_t mask;
-               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+               if (!access_ok(act, sizeof(*act)) ||
                    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
                    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
@@ -3869,7 +4012,7 @@ SYSCALL_DEFINE3(sigaction, int, sig,
        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
        if (!ret && oact) {
-               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+               if (!access_ok(oact, sizeof(*oact)) ||
                    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
                    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
@@ -3891,7 +4034,7 @@ COMPAT_SYSCALL_DEFINE3(sigaction, int, sig,
        compat_uptr_t handler, restorer;
 
        if (act) {
-               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+               if (!access_ok(act, sizeof(*act)) ||
                    __get_user(handler, &act->sa_handler) ||
                    __get_user(restorer, &act->sa_restorer) ||
                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
@@ -3909,7 +4052,7 @@ COMPAT_SYSCALL_DEFINE3(sigaction, int, sig,
        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
        if (!ret && oact) {
-               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+               if (!access_ok(oact, sizeof(*oact)) ||
                    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
                               &oact->sa_handler) ||
                    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),