Pull percpu-dtc into release branch
[pandora-kernel.git] / arch / parisc / kernel / signal32.c
index 0792e20..1c1a37f 100644 (file)
@@ -1,6 +1,8 @@
 /*    Signal support for 32-bit kernel builds
  *
  *    Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org>
+ *    Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org>
+ *
  *    Code was mostly borrowed from kernel/signal.c.
  *    See kernel/signal.c for additional Copyrights.
  *
@@ -31,7 +33,6 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 
-#include <asm/compat_signal.h>
 #include <asm/uaccess.h>
 
 #include "signal32.h"
@@ -398,3 +399,124 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __
 
        return err;
 }
+
+int
+copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
+{
+       compat_uptr_t addr;
+       int err;
+
+       if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
+               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 (to->si_code < 0)
+               err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+       else {
+               switch (to->si_code >> 16) {
+                     case __SI_CHLD >> 16:
+                       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);
+                     default:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       break;
+                     case __SI_FAULT >> 16:
+                       err |= __get_user(addr, &from->si_addr);
+                       to->si_addr = compat_ptr(addr);
+                       break;
+                     case __SI_POLL >> 16:
+                       err |= __get_user(to->si_band, &from->si_band);
+                       err |= __get_user(to->si_fd, &from->si_fd);
+                       break;
+                     case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
+                     case __SI_MESGQ >> 16:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       err |= __get_user(to->si_int, &from->si_int);
+                       break;
+               }
+       }
+       return err;
+}
+
+int
+copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
+{
+       compat_uptr_t addr;
+       compat_int_t val;
+       int err;
+
+       if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+               return -EFAULT;
+
+       /* If you change siginfo_t structure, please be sure
+          this code is fixed accordingly.
+          It should never copy any pad contained in the structure
+          to avoid security leaks, but must copy the generic
+          3 ints plus the relevant union member.
+          This routine must convert siginfo from 64bit to 32bit as well
+          at the same time.  */
+       err = __put_user(from->si_signo, &to->si_signo);
+       err |= __put_user(from->si_errno, &to->si_errno);
+       err |= __put_user((short)from->si_code, &to->si_code);
+       if (from->si_code < 0)
+               err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+       else {
+               switch (from->si_code >> 16) {
+               case __SI_CHLD >> 16:
+                       err |= __put_user(from->si_utime, &to->si_utime);
+                       err |= __put_user(from->si_stime, &to->si_stime);
+                       err |= __put_user(from->si_status, &to->si_status);
+               default:
+                       err |= __put_user(from->si_pid, &to->si_pid);
+                       err |= __put_user(from->si_uid, &to->si_uid);
+                       break;
+               case __SI_FAULT >> 16:
+                       addr = ptr_to_compat(from->si_addr);
+                       err |= __put_user(addr, &to->si_addr);
+                       break;
+               case __SI_POLL >> 16:
+                       err |= __put_user(from->si_band, &to->si_band);
+                       err |= __put_user(from->si_fd, &to->si_fd);
+                       break;
+               case __SI_TIMER >> 16:
+                       err |= __put_user(from->si_tid, &to->si_tid);
+                       err |= __put_user(from->si_overrun, &to->si_overrun);
+                       val = (compat_int_t)from->si_int;
+                       err |= __put_user(val, &to->si_int);
+                       break;
+               case __SI_RT >> 16:     /* Not generated by the kernel as of now.  */
+               case __SI_MESGQ >> 16:
+                       err |= __put_user(from->si_uid, &to->si_uid);
+                       err |= __put_user(from->si_pid, &to->si_pid);
+                       val = (compat_int_t)from->si_int;
+                       err |= __put_user(val, &to->si_int);
+                       break;
+               }
+       }
+       return err;
+}
+
+asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
+       struct compat_siginfo __user *uinfo)
+{
+       siginfo_t info;
+
+       if (copy_siginfo_from_user32(&info, uinfo))
+               return -EFAULT;
+
+       /* Not even root can pretend to send signals from the kernel.
+          Nor can they impersonate a kill(), which adds source info.  */
+       if (info.si_code >= 0)
+               return -EPERM;
+       info.si_signo = sig;
+
+       /* POSIX.1b doesn't mention process groups.  */
+       return kill_proc_info(sig, &info, pid);
+}
+