Hi,

We noticed 32/64bit compat issues with GETSIGINFO and SETSIGINFO. It
looks like s390 are already fixing this up in architecture specific
code, but here is a patch from Stephen Rothwell to add some generic
compat ptrace helpers.

Look OK? 

Anton

--

Subject: [PATCH] compat: add compat_ptrace_request
From: Stephen Rothwell <[EMAIL PROTECTED]>

This is needed so that we can cope with PTRACE_[GS]ETSIGINFO
from 32 bit processes.

Signed-off-by: Stephen Rothwell <[EMAIL PROTECTED]>
Acked-by: Anton Blanchard <[EMAIL PROTECTED]>
---

Index: build/arch/powerpc/kernel/ptrace32.c
===================================================================
--- build.orig/arch/powerpc/kernel/ptrace32.c   2006-01-09 17:44:32.000000000 
+1100
+++ build/arch/powerpc/kernel/ptrace32.c        2006-01-09 17:45:32.000000000 
+1100
@@ -18,6 +18,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -426,7 +427,7 @@
 #endif
 
        default:
-               ret = ptrace_request(child, request, addr, data);
+               ret = compat_ptrace_request(child, request, addr, data);
                break;
        }
 out_tsk:
Index: build/arch/powerpc/kernel/signal_32.c
===================================================================
--- build.orig/arch/powerpc/kernel/signal_32.c  2006-01-09 17:44:32.000000000 
+1100
+++ build/arch/powerpc/kernel/signal_32.c       2006-01-09 17:45:32.000000000 
+1100
@@ -621,6 +621,14 @@
        return ret;
 }
 
+int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
+{
+       if (copy_from_user(to, from, 3 * sizeof(int)) ||
+           copy_from_user (to->_sifields._pad, from->_sifields._pad,
+                   SI_PAD_SIZE32))
+               return -EFAULT;
+       return 0;
+}
 
 int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s)
 {
@@ -692,9 +700,9 @@
        int ret;
        mm_segment_t old_fs = get_fs();
 
-       if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
-           copy_from_user (info._sifields._pad, uinfo->_sifields._pad, 
SI_PAD_SIZE32))
-               return -EFAULT;
+       ret = copy_siginfo_from_user32(&info, uinfo);
+       if (ret)
+               return ret;
        set_fs (KERNEL_DS);
        /* The __user pointer cast is valid becasuse of the set_fs() */
        ret = sys_rt_sigqueueinfo((int)pid, (int)sig, (siginfo_t __user *) 
&info);
Index: build/include/linux/compat.h
===================================================================
--- build.orig/include/linux/compat.h   2006-01-09 17:44:26.000000000 +1100
+++ build/include/linux/compat.h        2006-01-09 17:45:32.000000000 +1100
@@ -161,5 +161,10 @@
 int get_compat_sigevent(struct sigevent *event,
                const struct compat_sigevent __user *u_event);
 
+struct task_struct;
+
+long compat_ptrace_request(struct task_struct *child, long request,
+               long addr, long data);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
Index: build/kernel/Makefile
===================================================================
--- build.orig/kernel/Makefile  2006-01-09 17:44:26.000000000 +1100
+++ build/kernel/Makefile       2006-01-09 17:45:32.000000000 +1100
@@ -19,7 +19,7 @@
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
-obj-$(CONFIG_COMPAT) += compat.o
+obj-$(CONFIG_COMPAT) += compat.o compat_ptrace.o
 obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
Index: build/kernel/compat_ptrace.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ build/kernel/compat_ptrace.c        2006-01-09 17:45:32.000000000 +1100
@@ -0,0 +1,91 @@
+/*
+ * (C) Copyright 2005 Stephen Rothwell, IBM Inc.
+ *
+ * Based on ptrace.c
+ *
+ * Common compatibility interfaces for "ptrace()" which we do not want
+ * to continually duplicate across every architecture.
+ */
+#include <linux/compat.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+
+typedef struct compat_siginfo compat_siginfo_t;
+
+static long compat_ptrace_getsiginfo(struct task_struct *child,
+               compat_siginfo_t __user *data)
+{
+       siginfo_t lastinfo;
+       int error = -ESRCH;
+
+       read_lock(&tasklist_lock);
+       if (likely(child->sighand != NULL)) {
+               error = -EINVAL;
+               spin_lock_irq(&child->sighand->siglock);
+               if (likely(child->last_siginfo != NULL)) {
+                       lastinfo = *child->last_siginfo;
+                       error = 0;
+               }
+               spin_unlock_irq(&child->sighand->siglock);
+       }
+       read_unlock(&tasklist_lock);
+       if (!error)
+               return copy_siginfo_to_user32(data, &lastinfo);
+       return error;
+}
+
+static long compat_ptrace_setsiginfo(struct task_struct *child,
+               compat_siginfo_t __user *data)
+{
+       siginfo_t newinfo;
+       int error = -ESRCH;
+
+       if (copy_siginfo_from_user32(&newinfo, data))
+               return -EFAULT;
+
+       read_lock(&tasklist_lock);
+       if (likely(child->sighand != NULL)) {
+               error = -EINVAL;
+               spin_lock_irq(&child->sighand->siglock);
+               if (likely(child->last_siginfo != NULL)) {
+                       *child->last_siginfo = newinfo;
+                       error = 0;
+               }
+               spin_unlock_irq(&child->sighand->siglock);
+       }
+       read_unlock(&tasklist_lock);
+       return error;
+}
+
+long compat_ptrace_request(struct task_struct *child, long request,
+                  long addr, long data)
+{
+       long ret = -EIO;
+
+       switch (request) {
+#ifdef PTRACE_OLDSETOPTIONS
+       case PTRACE_OLDSETOPTIONS:
+#endif
+       case PTRACE_SETOPTIONS:
+       case PTRACE_GETEVENTMSG:
+               ret = ptrace_request(child, request, addr, data);
+               break;
+       case PTRACE_GETSIGINFO:
+               ret = compat_ptrace_getsiginfo(child,
+                               (compat_siginfo_t __user *)data);
+               break;
+       case PTRACE_SETSIGINFO:
+               ret = compat_ptrace_setsiginfo(child,
+                               (compat_siginfo_t __user *)data);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
-
To unsubscribe from this list: send the line "unsubscribe linux-arch" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to