generic sys_sigaction() and compat_sys_sigaction()
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 26 Dec 2012 00:09:45 +0000 (19:09 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 3 Feb 2013 20:09:23 +0000 (15:09 -0500)
conditional on OLD_SIGACTION/COMPAT_OLD_SIGACTION

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/Kconfig
include/linux/compat.h
include/linux/signal.h
include/linux/syscalls.h
kernel/signal.c

index 3b4a416..e50d3af 100644 (file)
@@ -400,4 +400,15 @@ config OLD_SIGSUSPEND3
        help
          Even weirder antique ABI - three-argument sigsuspend(2)
 
+config OLD_SIGACTION
+       bool
+       help
+         Architecture has old sigaction(2) syscall.  Nope, not the same
+         as OLD_SIGSUSPEND | OLD_SIGSUSPEND3 - alpha has sigsuspend(2),
+         but fairly different variant of sigaction(2), thanks to OSF/1
+         compatibility...
+
+config COMPAT_OLD_SIGACTION
+       bool
+
 source "kernel/gcov/Kconfig"
index 0d53ab4..e20b8b4 100644 (file)
@@ -299,6 +299,15 @@ struct compat_robust_list_head {
        compat_uptr_t                   list_op_pending;
 };
 
+#ifdef CONFIG_COMPAT_OLD_SIGACTION
+struct compat_old_sigaction {
+       compat_uptr_t                   sa_handler;
+       compat_old_sigset_t             sa_mask;
+       compat_ulong_t                  sa_flags;
+       compat_uptr_t                   sa_restorer;
+};
+#endif
+
 struct compat_statfs;
 struct compat_statfs64;
 struct compat_old_linux_dirent;
@@ -383,6 +392,11 @@ int get_compat_sigevent(struct sigevent *event,
                const struct compat_sigevent __user *u_event);
 long compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig,
                                  struct compat_siginfo __user *uinfo);
+#ifdef CONFIG_COMPAT_OLD_SIGACTION
+asmlinkage long compat_sys_sigaction(int sig,
+                                   const struct compat_old_sigaction __user *act,
+                                   struct compat_old_sigaction __user *oact);
+#endif
 
 static inline int compat_timeval_compare(struct compat_timeval *lhs,
                                        struct compat_timeval *rhs)
index 0b6878e..e28e8d4 100644 (file)
@@ -269,6 +269,15 @@ struct k_sigaction {
        __sigrestore_t ka_restorer;
 #endif
 };
+#ifdef CONFIG_OLD_SIGACTION
+struct old_sigaction {
+       __sighandler_t sa_handler;
+       old_sigset_t sa_mask;
+       unsigned long sa_flags;
+       __sigrestore_t sa_restorer;
+};
+#endif
 
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
 extern void signal_delivered(int sig, siginfo_t *info, struct k_sigaction *ka, struct pt_regs *regs, int stepping);
index 1c4938b..02b0450 100644 (file)
@@ -385,6 +385,11 @@ asmlinkage long sys_sigsuspend(old_sigset_t mask);
 asmlinkage long sys_sigsuspend(int unused1, int unused2, old_sigset_t mask);
 #endif
 
+#ifdef CONFIG_OLD_SIGACTION
+asmlinkage long sys_sigaction(int, const struct old_sigaction __user *,
+                               struct old_sigaction __user *);
+#endif
+
 #ifndef CONFIG_ODD_RT_SIGACTION
 asmlinkage long sys_rt_sigaction(int,
                                 const struct sigaction __user *,
index f3665f3..79998f5 100644 (file)
@@ -3409,6 +3409,84 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig,
 #endif
 #endif /* !CONFIG_ODD_RT_SIGACTION */
 
+#ifdef CONFIG_OLD_SIGACTION
+SYSCALL_DEFINE3(sigaction, int, sig,
+               const struct old_sigaction __user *, act,
+               struct old_sigaction __user *, oact)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+
+       if (act) {
+               old_sigset_t mask;
+               if (!access_ok(VERIFY_READ, 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) ||
+                   __get_user(mask, &act->sa_mask))
+                       return -EFAULT;
+#ifdef __ARCH_HAS_KA_RESTORER
+               new_ka.ka_restorer = NULL;
+#endif
+               siginitset(&new_ka.sa.sa_mask, mask);
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               if (!access_ok(VERIFY_WRITE, 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) ||
+                   __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+                       return -EFAULT;
+       }
+
+       return ret;
+}
+#endif
+#ifdef CONFIG_COMPAT_OLD_SIGACTION
+COMPAT_SYSCALL_DEFINE3(sigaction, int, sig,
+               const struct compat_old_sigaction __user *, act,
+               struct compat_old_sigaction __user *, oact)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+       compat_old_sigset_t mask;
+       compat_uptr_t handler, restorer;
+
+       if (act) {
+               if (!access_ok(VERIFY_READ, 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) ||
+                   __get_user(mask, &act->sa_mask))
+                       return -EFAULT;
+
+#ifdef __ARCH_HAS_KA_RESTORER
+               new_ka.ka_restorer = NULL;
+#endif
+               new_ka.sa.sa_handler = compat_ptr(handler);
+               new_ka.sa.sa_restorer = compat_ptr(restorer);
+               siginitset(&new_ka.sa.sa_mask, mask);
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               if (!access_ok(VERIFY_WRITE, 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),
+                              &oact->sa_restorer) ||
+                   __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+                   __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+                       return -EFAULT;
+       }
+       return ret;
+}
+#endif
+
 #ifdef __ARCH_WANT_SYS_SGETMASK
 
 /*