linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] Add generic compat_siginfo_t
@ 2006-01-08 19:37 Kyle McMartin
  2006-01-09 14:13 ` [parisc-linux] " Christoph Hellwig
  0 siblings, 1 reply; 7+ messages in thread
From: Kyle McMartin @ 2006-01-08 19:37 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, parisc-linux, carlos, willy

From: Carlos O'Donell <carlos@parisc-linux.org>

Almost all the linux arches have exactly the same definition
for many of the compat structures. In almost all situations the
compiler can generate code to copy element by element. This
element by element copy is generic enough that it can be 
used in asm-generic. It is generic enough that it can already
be used by many architectures.

This patch creates an is_compat_task macro to check if
the process personality is native and thus allows various
routines to call either a compat copy or a regular copy.
Since is_compat_task evaluates to zero in the non-compat
case the compiler removes the code.

The patch centralizes the signal compat structures into
include/linux/compat_siginfo.h, and creates kernel/compat_signal.c
to place all the generic copy routines for signal related compat.
Code that requires signal compat structures can include them if 
needed.

HAVE_* macros are provided for arches to override the current
macro definitions. This gives arch maintainers the flexibility
of special case processing.

By making compat code more generic we reduce the number 
of arch specific bugs and allow kernel maintainers to 
provide generic tested compat versions of various routines.
While still allowing arch maintainers the ability to override
them with custom fixes.

Signed-off-by: Carlos O'Donell <carlos@parisc-linux.org>
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>

---

Andrew,

Please incorporate this patch series in -mm.

This is the last major piece of divergence from the parisc-linux tree. All
parisc64 machines require this change to be usable from mainline, so this
is quite an important series if we ever want to be fully functional from
mainline. I believe there's now sufficient ability for architectures to
override functionality that all previous objections to these changes have
been addressed.

Arch maintainers will likely want to redefine is_compat_task() to
inspect a more correct personality.

 include/asm-generic/compat_signal.h |   25 +++
 include/linux/compat.h              |   39 ++---
 include/linux/compat_siginfo.h      |  182 +++++++++++++++++++++++
 include/linux/signal.h              |    3 
 ipc/compat_mq.c                     |    1 
 kernel/Makefile                     |    2 
 kernel/compat.c                     |   47 ++++++
 kernel/compat_signal.c              |  280 +++++++++++++++++++++++++++++++++++
 kernel/ptrace.c                     |    2 
 kernel/signal.c                     |   21 +++
 10 files changed, 570 insertions(+), 32 deletions(-)
 create mode 100644 include/asm-generic/compat_signal.h
 create mode 100644 include/linux/compat_siginfo.h
 create mode 100644 kernel/compat_signal.c

a0019dc539d22a19c39dcb18e636fbeadfcec759
diff --git a/include/asm-generic/compat_signal.h b/include/asm-generic/compat_signal.h
new file mode 100644
index 0000000..889d57f
--- /dev/null
+++ b/include/asm-generic/compat_signal.h
@@ -0,0 +1,25 @@
+#ifndef _ASM_GENERIC_COMPAT_SIGNAL_H
+#define _ASM_GENERIC_COMPAT_SIGNAL_H
+
+#ifndef __ASSEMBLY__
+#include <linux/compat.h>
+
+typedef compat_uptr_t compat_sighandler_t;
+
+typedef struct compat_sigaltstack {
+	compat_uptr_t ss_sp;
+	compat_int_t ss_flags;
+	compat_size_t ss_size;
+} compat_stack_t;
+
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+struct compat_sigaction {
+	compat_sighandler_t sa_handler;
+	compat_uint_t sa_flags;
+	compat_sigset_t sa_mask;		/* mask last for extensibility */
+};
+
+#endif /* !__ASSEMBLY__ */
+#endif /* !_ASM_GENERIC_COMPAT_SIGNAL_H */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index f9ca534..1638fff 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -6,10 +6,16 @@
  */
 #include <linux/config.h>
 
-#ifdef CONFIG_COMPAT
+#ifndef CONFIG_COMPAT
+
+/* Non-native task requiring compat... doesn't exist */
+#define is_compat_task(x) 0
+
+#else
 
 #include <linux/stat.h>
 #include <linux/param.h>	/* for HZ */
+#include <linux/personality.h>  /* Conditional process compat */
 #include <linux/sem.h>
 
 #include <asm/compat.h>
@@ -18,6 +24,11 @@
 #define compat_jiffies_to_clock_t(x)	\
 		(((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
 
+/* Non-native task requiring compat */
+#ifndef HAVE_ARCH_IS_COMPAT_TASK
+#define is_compat_task(x) (personality(x->personality) == PER_LINUX32)
+#endif
+
 typedef __compat_uid32_t	compat_uid_t;
 typedef __compat_gid32_t	compat_gid_t;
 
@@ -99,28 +110,6 @@ struct compat_dirent {
 	char		d_name[256];
 };
 
-typedef union compat_sigval {
-	compat_int_t	sival_int;
-	compat_uptr_t	sival_ptr;
-} compat_sigval_t;
-
-#define COMPAT_SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct compat_sigevent {
-	compat_sigval_t sigev_value;
-	compat_int_t sigev_signo;
-	compat_int_t sigev_notify;
-	union {
-		compat_int_t _pad[COMPAT_SIGEV_PAD_SIZE];
-		compat_int_t _tid;
-
-		struct {
-			compat_uptr_t _function;
-			compat_uptr_t _attribute;
-		} _sigev_thread;
-	} _sigev_un;
-} compat_sigevent_t;
-
 
 long compat_sys_semctl(int first, int second, int third, void __user *uptr);
 long compat_sys_msgsnd(int first, int second, int third, void __user *uptr);
@@ -156,10 +145,6 @@ long compat_get_bitmap(unsigned long *ma
 		       unsigned long bitmap_size);
 long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
 		       unsigned long bitmap_size);
-int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from);
-int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from);
-int get_compat_sigevent(struct sigevent *event,
-		const struct compat_sigevent __user *u_event);
 
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/compat_siginfo.h b/include/linux/compat_siginfo.h
new file mode 100644
index 0000000..38124cf
--- /dev/null
+++ b/include/linux/compat_siginfo.h
@@ -0,0 +1,182 @@
+#ifndef _ASM_GENERIC_COMPAT_SIGINFO_H
+#define _ASM_GENERIC_COMPAT_SIGINFO_H
+
+#include <linux/config.h>
+#include <linux/compat.h>
+
+#ifndef CONFIG_COMPAT
+
+/* No compatibility layer required, add empty definitions for the compiler */
+
+typedef struct compat_siginfo{
+} compat_siginfo_t;
+
+static inline int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, 
+						struct siginfo *from)
+{
+	return -1;
+}
+
+static inline int compat_copy_siginfo_from_user(struct siginfo *to,
+                                                compat_siginfo_t __user *from)
+{
+        return -1;
+}
+
+#else
+
+#include <linux/compiler.h>
+#include <asm/siginfo.h>
+
+/* compat view of sigval_t */
+typedef union compat_sigval {
+	compat_int_t sival_int;
+	compat_uptr_t sival_ptr;
+} compat_sigval_t;
+
+/*
+ * This is the size (including padding) of the part of the
+ * struct siginfo that is before the union.
+ */
+#ifndef __ARCH_SI_COMPAT_PREAMBLE_SIZE
+#define __ARCH_SI_COMPAT_PREAMBLE_SIZE	(3 * sizeof(compat_int_t))
+#endif
+
+#define SI_COMPAT_MAX_SIZE	128
+#ifndef SI_COMPAT_PAD_SIZE
+#define SI_COMPAT_PAD_SIZE \
+  ((SI_COMPAT_MAX_SIZE - __ARCH_SI_COMPAT_PREAMBLE_SIZE) / sizeof(compat_int_t))
+#endif
+
+/* 32-bit view of si.uid_t */
+#ifndef __ARCH_SI_COMPAT_UID_T
+#define __ARCH_SI_COMPAT_UID_T compat_uid_t
+#endif
+
+/* 32-bit view of si.band_t */
+#ifndef __ARCH_SI_COMPAT_BAND_T
+#define __ARCH_SI_COMPAT_BAND_T compat_int_t
+#endif
+
+#ifndef HAVE_ARCH_COMPAT_SIGINFO_T
+
+/* Compat view of siginfo_t */
+typedef struct compat_siginfo {
+	compat_int_t si_signo;
+	compat_int_t si_errno;
+	compat_int_t si_code;
+
+	union {
+		compat_int_t _pad[SI_COMPAT_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			compat_pid_t _pid;	/* sender's pid */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			compat_timer_t _tid;	/* timer id */
+			compat_int_t _overrun;		/* overrun count */
+			char _pad[sizeof(__ARCH_SI_COMPAT_UID_T) - sizeof(compat_int_t)];
+			compat_sigval_t _sigval;	/* same as below */
+			compat_int_t _sys_private;       /* not to be passed to user */
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			compat_pid_t _pid;		/* sender's pid */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+			compat_sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			compat_pid_t _pid;		/* which child */
+			__ARCH_SI_COMPAT_UID_T _uid;	/* sender's uid */
+			compat_int_t _status;		/* exit code */
+			compat_clock_t _utime;
+			compat_clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			compat_uptr_t _addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+			compat_int_t _trapno;	/* TRAP # which caused the signal */
+#endif
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			__ARCH_SI_COMPAT_BAND_T _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			compat_int_t _fd;
+		} _sigpoll;
+	} _sifields;
+} compat_siginfo_t;
+#endif /* !HAVE_ARCH_COMPAT_SIGINFO_T */
+
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+#define si_trapno	_sifields._sigfault._trapno
+#endif
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+
+#ifndef __ARCH_SIGEV_COMPAT_PREAMBLE_SIZE
+#define __ARCH_SIGEV_COMPAT_PREAMBLE_SIZE (sizeof(compat_int_t) * 2 + sizeof(compat_sigval_t))
+#endif
+
+#define COMPAT_SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
+#ifndef HAVE_ARCH_COMPAT_SIGEVENT_T
+
+/* 32-bit view of sigevent_t */
+typedef struct compat_sigevent {
+	compat_sigval_t sigev_value;
+	compat_int_t sigev_signo;
+	compat_int_t sigev_notify;
+	union {
+		compat_int_t _pad[COMPAT_SIGEV_PAD_SIZE];
+		compat_int_t _tid;
+
+		struct {
+			compat_uptr_t _function;
+			compat_uptr_t _attribute;  /* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} compat_sigevent_t;
+
+#endif /* HAVE_ARCH_COMPAT_SIGEVENT_T */
+
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO
+
+#include <linux/string.h>
+
+static inline void compat_copy_siginfo(struct compat_siginfo *to, struct compat_siginfo *from)
+{
+	if (from->si_code < 0)
+		memcpy(to, from, sizeof(*to));
+	else
+		/* _sigchld is currently the largest know union member */
+		memcpy(to, from, __ARCH_SI_COMPAT_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
+}
+
+#endif /* !HAVE_ARCH_COMPAT_COPY_SIGINFO */
+
+extern int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, struct siginfo *from);
+extern int compat_copy_siginfo_from_user(struct siginfo *to, compat_siginfo_t __user *from);
+
+extern int compat_copy_sigevent_from_user(struct sigevent *to, compat_sigevent_t __user *from);
+extern int compat_copy_sigevent_to_user(compat_sigevent_t __user *to, struct sigevent *from);
+
+#endif /* CONFIG_COMPAT */
+#endif /* _ASM_GENERIC_COMPAT_SIGINFO_H */
+
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 5dd5f02..2127cc1 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -233,6 +233,9 @@ extern int sigprocmask(int, sigset_t *, 
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
 
+int copy_siginfo_from_user(siginfo_t *to, siginfo_t __user *from);
+int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from);
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
index d8d1e9f..41572f3 100644
--- a/ipc/compat_mq.c
+++ b/ipc/compat_mq.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/compat.h>
+#include <linux/compat_siginfo.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/mqueue.h>
diff --git a/kernel/Makefile b/kernel/Makefile
index 4f5a145..cf7357d 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -19,7 +19,7 @@ obj-$(CONFIG_KALLSYMS) += kallsyms.o
 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_signal.o
 obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
diff --git a/kernel/compat.c b/kernel/compat.c
index 102296e..862f821 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -13,6 +13,7 @@
 
 #include <linux/linkage.h>
 #include <linux/compat.h>
+#include <linux/compat_siginfo.h>
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/signal.h>
@@ -439,7 +440,11 @@ asmlinkage long compat_sys_waitid(int wh
 
 	BUG_ON(info.si_code & __SI_MASK);
 	info.si_code |= __SI_CHLD;
-	return copy_siginfo_to_user32(uinfo, &info);
+	
+	if (compat_copy_siginfo_to_user(uinfo, &info) != 0)
+		return -EFAULT;
+
+	return 0;
 }
 
 static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
@@ -651,6 +656,44 @@ int get_compat_sigevent(struct sigevent 
 
 /* timer_create is architecture specific because it needs sigevent conversion */
 
+long compat_sys_timer_create(clockid_t which_clock,
+			     compat_sigevent_t __user *timer_event_spec,
+			     compat_timer_t __user * created_timer_id)
+{
+	sigevent_t kevent;
+	timer_t ktimer;
+	mm_segment_t old_fs = get_fs();
+	long ret;
+
+	/* sigevent_t needs handling for 32-bit to 64-bit compat */
+	if (timer_event_spec != NULL)
+		if (compat_copy_sigevent_from_user(&kevent, timer_event_spec) != 0)
+			return -EFAULT;
+	
+	/* Timer ID is assumed to be a non-struct simple value */
+	if (created_timer_id != NULL)
+		if (__get_user(ktimer, created_timer_id) != 0)
+		  	return -EFAULT;
+
+	set_fs(KERNEL_DS);
+	ret = sys_timer_create(which_clock, 
+	    			timer_event_spec ? (sigevent_t __user *)&kevent : NULL, 
+	    			created_timer_id ? (timer_t __user *)&ktimer : NULL);
+	set_fs(old_fs);
+	
+	/* Copy back the results to userspace */
+	if (timer_event_spec != NULL)
+	  	if (compat_copy_sigevent_to_user(timer_event_spec, &kevent) != 0)
+			return -EFAULT;
+
+	if (created_timer_id != NULL)
+	  	if (__put_user(ktimer, created_timer_id) != 0)
+		  	return -EFAULT;
+	
+	return ret;
+}
+
+
 long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask,
 		       unsigned long bitmap_size)
 {
@@ -807,7 +850,7 @@ compat_sys_rt_sigtimedwait (compat_sigse
 	if (sig) {
 		ret = sig;
 		if (uinfo) {
-			if (copy_siginfo_to_user32(uinfo, &info))
+			if (compat_copy_siginfo_to_user(uinfo, &info))
 				ret = -EFAULT;
 		}
 	}else {
diff --git a/kernel/compat_signal.c b/kernel/compat_signal.c
new file mode 100644
index 0000000..20b6f00
--- /dev/null
+++ b/kernel/compat_signal.c
@@ -0,0 +1,280 @@
+/*
+ *  Copyright (C) 2003 Carlos O'Donell
+ * 
+ *  2003-12-20  Carlos O'Donell
+ *              Copied linux/kernel/compat_signal.c (copy_siginfo_to_user)
+ *              and modified to use compat_siginfo_t for thunking down to
+ *              32-bit userspace from a 64-bit kernel.
+ *              
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ *
+ */
+
+#include <linux/compat_siginfo.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+#include <asm/siginfo.h>
+
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO_TO_USER
+int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, siginfo_t *from)
+{
+	int err;
+	compat_siginfo_t compat_from;	
+
+	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+		return -EFAULT;
+	
+	/*
+	 * If you change compat_siginfo_t structure *or* siginfo_t, 
+	 * 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.
+	 */
+
+	/* Convert structure, don't leak anything in the copy */
+	memset(&compat_from,'\0',sizeof(compat_siginfo_t));
+
+        /* Always copy si_signo, si_errno, and si_code */
+	compat_from.si_signo = (compat_int_t)(from->si_signo);
+	compat_from.si_errno = (compat_int_t)(from->si_errno);
+	/* si_code is only a (short) value, remove kernel bits. */
+	compat_from.si_code = (short)(from->si_code);
+        
+	err = __put_user(compat_from.si_signo, &to->si_signo);
+	err |= __put_user(compat_from.si_errno, &to->si_errno);
+	err |= __put_user(compat_from.si_code, &to->si_code);
+
+        /* siginfo_t came from userspace, so it is the right
+         * size, no need for conversion
+         */        
+	if (from->si_code < 0) {
+		return __copy_to_user(&to->_sifields._pad, 
+                                      &from->_sifields._pad, 
+                                      SI_COMPAT_PAD_SIZE)
+			? -EFAULT : 0;
+        }
+	
+	switch (from->si_code & __SI_MASK) {
+	case __SI_KILL:
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		break;
+	case __SI_TIMER:
+		compat_from.si_pid = (compat_timer_t)(from->si_tid);
+		compat_from.si_overrun = (compat_int_t)(from->si_overrun);
+		compat_from.si_ptr = (compat_uptr_t)((u64 __force)(from->si_ptr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_tid, &to->si_tid);
+		err |= __put_user(compat_from.si_overrun, &to->si_overrun);
+		err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+		break;
+	case __SI_POLL:
+		compat_from.si_band = (__ARCH_SI_COMPAT_BAND_T)(from->si_band);
+		compat_from.si_fd = (compat_int_t)(from->si_fd);
+		err |= __put_user(compat_from.si_band, &to->si_band);
+		err |= __put_user(compat_from.si_fd, &to->si_fd);
+		break;
+	case __SI_FAULT:
+		compat_from.si_addr = (compat_uptr_t)((u64 __force)(from->si_addr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_addr, &to->si_addr);
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+		compat_from.si_trapno = (compat_int_t)(from->si_addr);
+		err |= __put_user(compat_from.si_trapno, &to->si_trapno);
+#endif
+		break;
+	case __SI_CHLD:
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		compat_from.si_status = (compat_int_t)(from->si_status);
+		compat_from.si_utime = (compat_clock_t)(from->si_utime);
+		compat_from.si_stime = (compat_clock_t)(from->si_stime);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		err |= __put_user(compat_from.si_status, &to->si_status);
+		err |= __put_user(compat_from.si_utime, &to->si_utime);
+		err |= __put_user(compat_from.si_stime, &to->si_stime);
+		break;
+	case __SI_RT: /* This is not generated by the kernel as of now. */
+	case __SI_MESGQ: /* But this is */
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		compat_from.si_int = (compat_int_t)(from->si_int);
+		compat_from.si_ptr = (compat_uptr_t)((u64 __force)(from->si_ptr) & 0xffffffffUL);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		err |= __put_user(compat_from.si_int, &to->si_int);
+		err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+		break;
+	default: /* this is just in case for now ... */
+		compat_from.si_pid = (compat_pid_t)(from->si_pid);
+		compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+		err |= __put_user(compat_from.si_pid, &to->si_pid);
+		err |= __put_user(compat_from.si_uid, &to->si_uid);
+		break;
+	}
+	return err;
+}
+#endif
+
+#ifndef HAVE_ARCH_COPY_SIGINFO_FROM_USER
+int compat_copy_siginfo_from_user(siginfo_t *to, compat_siginfo_t __user *from)
+{
+	int err;
+        u64 scratch;
+
+	if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
+		return -EFAULT;
+	
+	/*
+	 * If you change compat_siginfo_t structure *or* siginfo_t, 
+	 * please be sure this code is fixed accordingly.
+	 */
+
+        /* Always copy si_signo, si_errno, and si_code */
+	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);
+        
+        /* siginfo_t came from userspace, so it is the right
+         * size, no need for conversion
+         */        
+	if (to->si_code < 0) {
+		return __copy_from_user(&to->_sifields._pad, 
+                                        &from->_sifields._pad, 
+                                        SI_COMPAT_PAD_SIZE)
+			? -EFAULT : 0;
+        }
+	
+	switch (to->si_code & __SI_MASK) {
+	case __SI_KILL:
+		err |= __get_user(to->si_pid, &from->si_pid);
+		err |= __get_user(to->si_uid, &from->si_uid);
+		break;
+	case __SI_TIMER:
+		err |= __get_user(to->si_tid, &from->si_tid);
+		err |= __get_user(to->si_overrun, &from->si_overrun);
+		err |= __get_user(scratch, &from->si_ptr);
+                to->si_ptr = (u64 __user*)scratch;                
+		break;
+	case __SI_POLL:
+		err |= __get_user(to->si_band, &from->si_band);
+		err |= __get_user(to->si_fd, &from->si_fd);
+		break;
+	case __SI_FAULT:
+		err |= __get_user(scratch, &from->si_addr);
+                to->si_addr = (u64 __user*)scratch;
+#ifdef __ARCH_SI_COMPAT_TRAPNO
+		err |= __get_user(to->si_trapno, &from->si_trapno);
+#endif
+		break;
+	case __SI_CHLD:
+		err |= __get_user(to->si_pid, &from->si_pid);
+		err |= __get_user(to->si_uid, &from->si_uid);
+		err |= __get_user(to->si_status, &from->si_status);
+		err |= __get_user(to->si_utime, &from->si_utime);
+		err |= __get_user(to->si_stime, &from->si_stime);
+		break;
+	case __SI_RT: /* This is not generated by the kernel as of now. */
+	case __SI_MESGQ: /* But this is */
+		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);
+		err |= __get_user(scratch, &from->si_ptr);
+                to->si_ptr = (u64 __user*)scratch;
+		break;
+	default: /* this is just in case for now ... */
+		err |= __get_user(to->si_pid, &from->si_pid);
+		err |= __get_user(to->si_uid, &from->si_uid);
+		break;
+	}
+	return err;
+}
+#endif
+
+#ifndef HAVE_ARCH_COPY_SIGEVENT_FROM_USER
+int compat_copy_sigevent_from_user(sigevent_t *to, compat_sigevent_t __user *from)
+{
+	int err;
+	u64 scratch;
+	
+	/* copy sigval_t sigev_value 
+	 	int_t sival_int		(same)
+	 	uptr_t sival_ptr	(32 vs 64)*/
+	err = __get_user(to->sigev_value.sival_int, 
+	    		 &from->sigev_value.sival_int);
+	err |= __get_user(scratch, &from->sigev_value.sival_ptr);
+	to->sigev_value.sival_ptr = (u64 __user *)scratch;
+	
+	/* copy int_t sigev_signo 	(same)*/
+	err |= __get_user(to->sigev_signo, &from->sigev_signo);
+	
+	/* copy int_t sigev_notify	(same)*/
+	err |= __get_user(to->sigev_notify, &from->sigev_notify);
+
+	/* never copy _sigev_un padding */
+
+	/* copy int_t _tid 		(same),
+	   good_sigevent() uses this value of */
+	err |= __get_user(to->sigev_notify_thread_id, &from->sigev_notify_thread_id);
+	
+	/* XXX: Do not copy these, they aren't used by
+	   anyone. We would need to distinguish the uses of the union.
+	   copy _sigev_thread
+	  	uptr_t _function	(32 vs 64)
+	  	uptr_t _attribute	(32 vs 64)*/
+	
+	return err;
+}
+#endif
+
+#ifndef HAVE_ARCH_COPY_SIGEVENT_TO_USER
+int compat_copy_sigevent_to_user(compat_sigevent_t __user *to, sigevent_t *from)
+{
+	int err;
+	u32 scratch;
+	
+	/* copy sigval_t sigev_value 
+	 	int_t sival_int		(same)
+	 	uptr_t sival_ptr	(32 vs 64)*/
+	err = __put_user(from->sigev_value.sival_int, 
+	    		 &to->sigev_value.sival_int);
+	scratch = (u32)((u64 __force)from->sigev_value.sival_ptr & 0xffffffffUL);
+	err |= __put_user((compat_uptr_t)scratch, &to->sigev_value.sival_ptr);
+	
+	/* copy int_t sigev_signo 	(same)*/
+	err |= __put_user(from->sigev_signo, &to->sigev_signo);
+	
+	/* copy int_t sigev_notify	(same)*/
+	err |= __put_user(from->sigev_notify, &to->sigev_notify);
+
+	/* never copy _sigev_un padding */
+
+	/* copy int_t _tid 		(same),
+	   good_sigevent() uses this value of */
+	err |= __put_user(from->sigev_notify_thread_id, &to->sigev_notify_thread_id);
+	
+	/* XXX: Do not copy these, they aren't used by
+	   anyone. We would need to distinguish the uses of the union.
+	   copy _sigev_thread
+	  	uptr_t _function	(32 vs 64)
+	  	uptr_t _attribute	(32 vs 64)*/
+	
+	return err;
+}
+#endif
+
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 656476e..298ca08 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -363,7 +363,7 @@ static int ptrace_setsiginfo(struct task
 	siginfo_t newinfo;
 	int error = -ESRCH;
 
-	if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
+	if (copy_siginfo_from_user(&newinfo, data) != 0)
 		return -EFAULT;
 
 	read_lock(&tasklist_lock);
diff --git a/kernel/signal.c b/kernel/signal.c
index d7611f1..8ef54c0 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -22,6 +22,7 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/ptrace.h>
+#include <linux/compat_siginfo.h>
 #include <linux/posix-timers.h>
 #include <linux/signal.h>
 #include <linux/audit.h>
@@ -2095,17 +2096,35 @@ sys_rt_sigpending(sigset_t __user *set, 
 	return do_sigpending(set, sigsetsize);
 }
 
+#ifndef HAVE_ARCH_COPY_SIGINFO_FROM_USER
+
+int copy_siginfo_from_user(siginfo_t *to, siginfo_t __user *from)
+{
+        if(is_compat_task(current))
+                return compat_copy_siginfo_from_user(to,(compat_siginfo_t __user *)from);
+  
+        return copy_from_user(&to, from, sizeof(siginfo_t));
+}
+
+#endif
+
 #ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER
 
 int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)
 {
 	int err;
+	
+	/* Use compat_siginfo_t with 32-bit signals */
+	if(is_compat_task(current)){
+		return compat_copy_siginfo_to_user((compat_siginfo_t __user *)to,from);
+	}
 
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
 	if (from->si_code < 0)
 		return __copy_to_user(to, from, sizeof(siginfo_t))
 			? -EFAULT : 0;
+	
 	/*
 	 * If you change siginfo_t structure, please be sure
 	 * this code is fixed accordingly.
@@ -2321,7 +2340,7 @@ sys_rt_sigqueueinfo(int pid, int sig, si
 {
 	siginfo_t info;
 
-	if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
+	if (copy_siginfo_from_user(&info, uinfo))
 		return -EFAULT;
 
 	/* Not even root can pretend to send signals from the kernel.
-- 
1.0.7


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [parisc-linux] [PATCH 1/5] Add generic compat_siginfo_t
  2006-01-08 19:37 [PATCH 1/5] Add generic compat_siginfo_t Kyle McMartin
@ 2006-01-09 14:13 ` Christoph Hellwig
  2006-01-10 15:01   ` Kyle McMartin
  0 siblings, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2006-01-09 14:13 UTC (permalink / raw)
  To: Kyle McMartin; +Cc: akpm, carlos, willy, linux-kernel, parisc-linux

-mm already has a much better implementation for compat_sys_timer_create
that doesn't require all the sigevent churn in this patch (which btw
doesn't seem to be mentioned in the changelog at all).  But even with
that remove there seems to be a lot of useless ifdef and indirection
in this patch.  Over the next days I'll send out my generic compat
singal bits which don't require all this, but otoh require every
architecture to supply helpers.  If you can make those generic without
all the ifdef an additional header bits all power to you!


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [parisc-linux] [PATCH 1/5] Add generic compat_siginfo_t
  2006-01-09 14:13 ` [parisc-linux] " Christoph Hellwig
@ 2006-01-10 15:01   ` Kyle McMartin
  2006-01-10 15:15     ` Christoph Hellwig
  0 siblings, 1 reply; 7+ messages in thread
From: Kyle McMartin @ 2006-01-10 15:01 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: akpm, carlos, willy, linux-kernel, parisc-linux

On Mon, Jan 09, 2006 at 03:13:55PM +0100, Christoph Hellwig wrote:
> -mm already has a much better implementation for compat_sys_timer_create
> that doesn't require all the sigevent churn in this patch (which btw
> doesn't seem to be mentioned in the changelog at all).  

Ok, I see it in -mm now, and it does seem to be nicer code, I'll
try it out on parisc64.

> But even with
> that remove there seems to be a lot of useless ifdef and indirection
> in this patch.  

I agree, I'm really just trying to shepard this home so we don't have
to maintain it out of tree. I'm not overly attached to the code, if
I can make parisc64 work with your compat signal bits, I'll be
just as happy.

The one thing from this patchset I'd like to keep is the is_compat_task()
as it does provide nice cleanups 

Cheers, Kyle

> Over the next days I'll send out my generic compat
> singal bits which don't require all this, but otoh require every
> architecture to supply helpers.  If you can make those generic without
> all the ifdef an additional header bits all power to you!

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [parisc-linux] [PATCH 1/5] Add generic compat_siginfo_t
  2006-01-10 15:01   ` Kyle McMartin
@ 2006-01-10 15:15     ` Christoph Hellwig
  2006-01-10 16:39       ` Matthew Wilcox
  0 siblings, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2006-01-10 15:15 UTC (permalink / raw)
  To: Kyle McMartin
  Cc: Christoph Hellwig, akpm, carlos, willy, linux-kernel, parisc-linux

On Tue, Jan 10, 2006 at 10:01:41AM -0500, Kyle McMartin wrote:
> I agree, I'm really just trying to shepard this home so we don't have
> to maintain it out of tree. I'm not overly attached to the code, if
> I can make parisc64 work with your compat signal bits, I'll be
> just as happy.
> 
> The one thing from this patchset I'd like to keep is the is_compat_task()
> as it does provide nice cleanups 

Yes, the is_compat_task helper is a nice thing to have.  I haven't
needed it for the signal bits I've done yet, but it's also useful
elsewhere.  But IIRC someone vehemently opposed it in the last round
of discussion.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [parisc-linux] [PATCH 1/5] Add generic compat_siginfo_t
  2006-01-10 15:15     ` Christoph Hellwig
@ 2006-01-10 16:39       ` Matthew Wilcox
  2006-01-11  3:46         ` Stephen Rothwell
  0 siblings, 1 reply; 7+ messages in thread
From: Matthew Wilcox @ 2006-01-10 16:39 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Kyle McMartin, akpm, carlos, linux-kernel, parisc-linux

On Tue, Jan 10, 2006 at 04:15:47PM +0100, Christoph Hellwig wrote:
> Yes, the is_compat_task helper is a nice thing to have.  I haven't
> needed it for the signal bits I've done yet, but it's also useful
> elsewhere.  But IIRC someone vehemently opposed it in the last round
> of discussion.

Andi's now dropped his opposition, so I think we're fine.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [parisc-linux] [PATCH 1/5] Add generic compat_siginfo_t
  2006-01-10 16:39       ` Matthew Wilcox
@ 2006-01-11  3:46         ` Stephen Rothwell
  2006-01-11 17:27           ` Kyle McMartin
  0 siblings, 1 reply; 7+ messages in thread
From: Stephen Rothwell @ 2006-01-11  3:46 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: hch, kyle, akpm, carlos, linux-kernel, parisc-linux

[-- Attachment #1: Type: text/plain, Size: 594 bytes --]

On Tue, 10 Jan 2006 09:39:43 -0700 Matthew Wilcox <matthew@wil.cx> wrote:
>
> On Tue, Jan 10, 2006 at 04:15:47PM +0100, Christoph Hellwig wrote:
> > Yes, the is_compat_task helper is a nice thing to have.  I haven't
> > needed it for the signal bits I've done yet, but it's also useful
> > elsewhere.  But IIRC someone vehemently opposed it in the last round
> > of discussion.
> 
> Andi's now dropped his opposition, so I think we're fine.

And I think DaveM got tired :-)

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [parisc-linux] [PATCH 1/5] Add generic compat_siginfo_t
  2006-01-11  3:46         ` Stephen Rothwell
@ 2006-01-11 17:27           ` Kyle McMartin
  0 siblings, 0 replies; 7+ messages in thread
From: Kyle McMartin @ 2006-01-11 17:27 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: Matthew Wilcox, hch, kyle, akpm, carlos, linux-kernel, parisc-linux

On Wed, Jan 11, 2006 at 02:46:00PM +1100, Stephen Rothwell wrote:
> > Andi's now dropped his opposition, so I think we're fine.
> 
> And I think DaveM got tired :-)
>

I think we can all agree that having one macro, which is more
easily controlled, and doesn't require large amounts of grep work
for an arch maintainer to find (ab)uses of. Is a far more desireable 
solution over every piece of code that needs to do it abusing various
test_thread_flag and such.

Cheers,
	Kyle

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2006-01-11 17:28 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-08 19:37 [PATCH 1/5] Add generic compat_siginfo_t Kyle McMartin
2006-01-09 14:13 ` [parisc-linux] " Christoph Hellwig
2006-01-10 15:01   ` Kyle McMartin
2006-01-10 15:15     ` Christoph Hellwig
2006-01-10 16:39       ` Matthew Wilcox
2006-01-11  3:46         ` Stephen Rothwell
2006-01-11 17:27           ` Kyle McMartin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).