fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / powerpc / kernel / signal_32.c
index 320353f..267fc33 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/elf.h>
+#include <linux/tracehook.h>
 #ifdef CONFIG_PPC64
 #include <linux/syscalls.h>
 #include <linux/compat.h>
@@ -36,7 +37,7 @@
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
-#include <linux/suspend.h>
+#include <linux/freezer.h>
 #endif
 
 #include <asm/uaccess.h>
@@ -631,6 +632,58 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s)
 
 #define copy_siginfo_to_user   copy_siginfo_to_user32
 
+/* mostly stolen from arch/s390/kernel/compat_signal.c */
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+       int err;
+       u32 tmp;
+
+       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_RT >> 16: /* This is not generated by the kernel as of now.  */
+               case __SI_MESGQ >> 16:
+                       err |= __get_user(to->si_int, &from->si_int);
+                       /* fallthrough */
+               case __SI_KILL >> 16:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       break;
+               case __SI_CHLD >> 16:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       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);
+                       break;
+               case __SI_FAULT >> 16:
+                       err |= __get_user(tmp, &from->si_addr);
+                       to->si_addr = (void __user *)(u64) tmp;
+                       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_TIMER >> 16:
+                       err |= __get_user(to->si_tid, &from->si_tid);
+                       err |= __get_user(to->si_overrun, &from->si_overrun);
+                       err |= __get_user(to->si_int, &from->si_int);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return err;
+}
+
 /*
  * Note: it is necessary to treat pid and sig as unsigned ints, with the
  * corresponding cast to a signed int to insure that the proper conversion
@@ -835,11 +888,21 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
                return -EINVAL;
 
        if (old_ctx != NULL) {
+               struct mcontext __user *mctx;
+
+               /*
+                * old_ctx might not be 16-byte aligned, in which
+                * case old_ctx->uc_mcontext won't be either.
+                * Because we have the old_ctx->uc_pad2 field
+                * before old_ctx->uc_mcontext, we need to round down
+                * from &old_ctx->uc_mcontext to a 16-byte boundary.
+                */
+               mctx = (struct mcontext __user *)
+                       ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL);
                if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
-                   || save_user_regs(regs, &old_ctx->uc_mcontext, 0)
+                   || save_user_regs(regs, mctx, 0)
                    || put_sigset_t(&old_ctx->uc_sigmask, &current->blocked)
-                   || __put_user(to_user_ptr(&old_ctx->uc_mcontext),
-                           &old_ctx->uc_regs))
+                   || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs))
                        return -EFAULT;
        }
        if (new_ctx == NULL)
@@ -1216,6 +1279,8 @@ no_signal:
                   its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
                if (test_thread_flag(TIF_RESTORE_SIGMASK))
                        clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+               tracehook_report_handle_signal(signr, &ka, oldset, regs);
        }
 
        return ret;