Hi all, This patch pulls together the compat_sigevent structs. It also consolidates the copying of these structures into the kernel.
The only part of the second union in sigevent that the kernel looks at currently is the _tid, so that is the only bit we copy. This patch depends on my previous two patches "add and use COMPAT_SIGEV_PAD_SIZE" and "Consolidate the last compat sigvals". Signed-off-by: Stephen Rothwell <[EMAIL PROTECTED]> diffstat looks like this: arch/ia64/ia32/ia32priv.h | 13 ------------- arch/ia64/ia32/sys_ia32.c | 9 ++------- arch/ppc64/kernel/sys_ppc32.c | 9 +-------- arch/s390/kernel/compat_linux.c | 13 ++----------- arch/s390/kernel/compat_linux.h | 17 ----------------- arch/sparc64/kernel/sys_sparc32.c | 9 ++------- arch/x86_64/ia32/sys_ia32.c | 16 ++-------------- include/asm-sparc64/siginfo.h | 22 ---------------------- include/linux/compat.h | 3 +++ ipc/compat_mq.c | 14 -------------- kernel/compat.c | 21 +++++++++++++++++++++ 11 files changed, 33 insertions(+), 113 deletions(-) Built and run on PPC64. If there are no objections, I will send this on to Andrew/Linus. -- Cheers, Stephen Rothwell [EMAIL PROTECTED] http://www.canb.auug.org.au/~sfr/ diff -ruNp linus-sigval/arch/ia64/ia32/ia32priv.h linus-sigevent/arch/ia64/ia32/ia32priv.h --- linus-sigval/arch/ia64/ia32/ia32priv.h 2005-03-07 17:52:28.000000000 +1100 +++ linus-sigevent/arch/ia64/ia32/ia32priv.h 2005-03-08 13:25:56.000000000 +1100 @@ -277,19 +277,6 @@ typedef struct compat_siginfo { } _sifields; } compat_siginfo_t; -typedef struct sigevent32 { - compat_sigval_t sigev_value; - int sigev_signo; - int sigev_notify; - union { - int _pad[COMPAT_SIGEV_PAD_SIZE]; - struct { - u32 _function; - u32 _attribute; /* really pthread_attr_t */ - } _sigev_thread; - } _sigev_un; -} sigevent_t32; - struct old_linux32_dirent { u32 d_ino; u32 d_offset; diff -ruNp linus-sigval/arch/ia64/ia32/sys_ia32.c linus-sigevent/arch/ia64/ia32/sys_ia32.c --- linus-sigval/arch/ia64/ia32/sys_ia32.c 2005-03-07 13:06:23.000000000 +1100 +++ linus-sigevent/arch/ia64/ia32/sys_ia32.c 2005-03-08 15:21:40.000000000 +1100 @@ -2592,7 +2592,7 @@ sys32_get_thread_area (struct ia32_user_ } asmlinkage long -sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id) +sys32_timer_create(u32 clock, struct compat_sigevent __user *se32, timer_t __user *timer_id) { struct sigevent se; mm_segment_t oldfs; @@ -2602,12 +2602,7 @@ sys32_timer_create(u32 clock, struct sig if (se32 == NULL) return sys_timer_create(clock, NULL, timer_id); - memset(&se, 0, sizeof(struct sigevent)); - if (get_user(se.sigev_value.sival_int, &se32->sigev_value.sival_int) || - __get_user(se.sigev_signo, &se32->sigev_signo) || - __get_user(se.sigev_notify, &se32->sigev_notify) || - __copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad, - sizeof(se._sigev_un._pad))) + if (get_compat_sigevent(&se, se32)) return -EFAULT; if (!access_ok(VERIFY_WRITE,timer_id,sizeof(timer_t))) diff -ruNp linus-sigval/arch/ppc64/kernel/sys_ppc32.c linus-sigevent/arch/ppc64/kernel/sys_ppc32.c --- linus-sigval/arch/ppc64/kernel/sys_ppc32.c 2005-01-29 06:05:47.000000000 +1100 +++ linus-sigevent/arch/ppc64/kernel/sys_ppc32.c 2005-03-08 15:23:17.000000000 +1100 @@ -1290,14 +1290,7 @@ long ppc32_timer_create(clockid_t clock, if (ev32 == NULL) return sys_timer_create(clock, NULL, timer_id); - memset(&event, 0, sizeof(event)); - if (!access_ok(VERIFY_READ, ev32, sizeof(struct compat_sigevent)) - || __get_user(event.sigev_value.sival_int, - &ev32->sigev_value.sival_int) - || __get_user(event.sigev_signo, &ev32->sigev_signo) - || __get_user(event.sigev_notify, &ev32->sigev_notify) - || __get_user(event.sigev_notify_thread_id, - &ev32->sigev_notify_thread_id)) + if (get_compat_sigevent(&event, ev32)) return -EFAULT; if (!access_ok(VERIFY_WRITE, timer_id, sizeof(timer_t))) diff -ruNp linus-sigval/arch/s390/kernel/compat_linux.c linus-sigevent/arch/s390/kernel/compat_linux.c --- linus-sigval/arch/s390/kernel/compat_linux.c 2005-02-11 13:05:29.000000000 +1100 +++ linus-sigevent/arch/s390/kernel/compat_linux.c 2005-03-08 15:24:35.000000000 +1100 @@ -1019,7 +1019,7 @@ extern asmlinkage long sys_timer_create(clockid_t, struct sigevent *, timer_t *); asmlinkage long -sys32_timer_create(clockid_t which_clock, struct sigevent32 *se32, +sys32_timer_create(clockid_t which_clock, struct compat_sigevent *se32, timer_t *timer_id) { struct sigevent se; @@ -1030,16 +1030,7 @@ sys32_timer_create(clockid_t which_clock if (se32 == NULL) return sys_timer_create(which_clock, NULL, timer_id); - /* XXX: converting se32 to se is filthy because of the - * two union members. For now it is ok, because the pointers - * are not touched in kernel. - */ - memset(&se, 0, sizeof(se)); - if (get_user(se.sigev_value.sival_int, &se32->sigev_value.sival_int) || - get_user(se.sigev_signo, &se32->sigev_signo) || - get_user(se.sigev_notify, &se32->sigev_notify) || - copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad, - sizeof(se._sigev_un._pad))) + if (get_compat_sigevent(&se, se32)) return -EFAULT; old_fs = get_fs(); diff -ruNp linus-sigval/arch/s390/kernel/compat_linux.h linus-sigevent/arch/s390/kernel/compat_linux.h --- linus-sigval/arch/s390/kernel/compat_linux.h 2005-03-07 17:49:16.000000000 +1100 +++ linus-sigevent/arch/s390/kernel/compat_linux.h 2005-03-08 14:16:28.000000000 +1100 @@ -194,21 +194,4 @@ struct ucontext32 { compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; -struct sigevent32 { - union { - int sival_int; - u32 sival_ptr; - } sigev_value; - int sigev_signo; - int sigev_notify; - union { - int _pad[COMPAT_SIGEV_PAD_SIZE]; - int _tid; - struct { - u32 *_function; - u32 *_attribute; - } _sigev_thread; - } _sigev_un; -}; - #endif /* _ASM_S390X_S390_H */ diff -ruNp linus-sigval/arch/sparc64/kernel/sys_sparc32.c linus-sigevent/arch/sparc64/kernel/sys_sparc32.c --- linus-sigval/arch/sparc64/kernel/sys_sparc32.c 2005-03-07 13:06:23.000000000 +1100 +++ linus-sigevent/arch/sparc64/kernel/sys_sparc32.c 2005-03-08 15:25:36.000000000 +1100 @@ -1087,7 +1087,7 @@ sys_timer_create(clockid_t which_clock, timer_t __user *created_timer_id); long -sys32_timer_create(u32 clock, struct sigevent32 __user *se32, +sys32_timer_create(u32 clock, struct compat_sigevent __user *se32, timer_t __user *timer_id) { struct sigevent se; @@ -1098,12 +1098,7 @@ sys32_timer_create(u32 clock, struct sig if (se32 == NULL) return sys_timer_create(clock, NULL, timer_id); - memset(&se, 0, sizeof(struct sigevent)); - if (get_user(se.sigev_value.sival_int, &se32->sigev_value.sival_int) || - __get_user(se.sigev_signo, &se32->sigev_signo) || - __get_user(se.sigev_notify, &se32->sigev_notify) || - __copy_from_user(&se._sigev_un._pad, &se32->_sigev_un._pad, - sizeof(se._sigev_un._pad))) + if (get_compat_sigevent(&se, se32)) return -EFAULT; if (!access_ok(VERIFY_WRITE,timer_id,sizeof(timer_t))) diff -ruNp linus-sigval/arch/x86_64/ia32/sys_ia32.c linus-sigevent/arch/x86_64/ia32/sys_ia32.c --- linus-sigval/arch/x86_64/ia32/sys_ia32.c 2005-03-07 13:06:23.000000000 +1100 +++ linus-sigevent/arch/x86_64/ia32/sys_ia32.c 2005-03-08 15:27:14.000000000 +1100 @@ -993,31 +993,19 @@ asmlinkage long sys32_open(const char __ return fd; } -struct sigevent32 { - u32 sigev_value; - u32 sigev_signo; - u32 sigev_notify; - u32 payload[(64 / 4) - 3]; -}; - extern asmlinkage long sys_timer_create(clockid_t which_clock, struct sigevent __user *timer_event_spec, timer_t __user * created_timer_id); long -sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id) +sys32_timer_create(u32 clock, struct compat_sigevent __user *se32, timer_t __user *timer_id) { struct sigevent __user *p = NULL; if (se32) { struct sigevent se; p = compat_alloc_user_space(sizeof(struct sigevent)); - memset(&se, 0, sizeof(struct sigevent)); - if (get_user(se.sigev_value.sival_int, &se32->sigev_value) || - __get_user(se.sigev_signo, &se32->sigev_signo) || - __get_user(se.sigev_notify, &se32->sigev_notify) || - __copy_from_user(&se._sigev_un._pad, &se32->payload, - sizeof(se32->payload)) || + if (get_compat_sigevent(&se, se32) || copy_to_user(p, &se, sizeof(se))) return -EFAULT; } diff -ruNp linus-sigval/include/asm-sparc64/siginfo.h linus-sigevent/include/asm-sparc64/siginfo.h --- linus-sigval/include/asm-sparc64/siginfo.h 2005-03-07 17:49:55.000000000 +1100 +++ linus-sigevent/include/asm-sparc64/siginfo.h 2005-03-08 14:19:52.000000000 +1100 @@ -32,26 +32,4 @@ struct compat_siginfo; #define EMT_TAGOVF (__SI_FAULT|1) /* tag overflow */ #define NSIGEMT 1 -#ifdef __KERNEL__ - -#ifdef CONFIG_COMPAT - -typedef struct sigevent32 { - compat_sigval_t sigev_value; - int sigev_signo; - int sigev_notify; - union { - int _pad[COMPAT_SIGEV_PAD_SIZE]; - - struct { - u32 _function; - u32 _attribute; /* really pthread_attr_t */ - } _sigev_thread; - } _sigev_un; -} sigevent_t32; - -#endif /* CONFIG_COMPAT */ - -#endif /* __KERNEL__ */ - #endif diff -ruNp linus-sigval/include/linux/compat.h linus-sigevent/include/linux/compat.h --- linus-sigval/include/linux/compat.h 2005-03-07 14:07:26.000000000 +1100 +++ linus-sigevent/include/linux/compat.h 2005-03-08 14:38:57.000000000 +1100 @@ -155,5 +155,8 @@ long compat_put_bitmap(compat_ulong_t __ 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 -ruNp linus-sigval/ipc/compat_mq.c linus-sigevent/ipc/compat_mq.c --- linus-sigval/ipc/compat_mq.c 2004-07-17 08:44:05.000000000 +1000 +++ linus-sigevent/ipc/compat_mq.c 2005-03-08 14:33:15.000000000 +1100 @@ -102,20 +102,6 @@ asmlinkage ssize_t compat_sys_mq_timedre u_msg_prio, u_ts); } -static int get_compat_sigevent(struct sigevent *event, - const struct compat_sigevent __user *u_event) -{ - if (verify_area(VERIFY_READ, u_event, sizeof(*u_event))) - return -EFAULT; - - return __get_user(event->sigev_value.sival_int, - &u_event->sigev_value.sival_int) - | __get_user(event->sigev_signo, &u_event->sigev_signo) - | __get_user(event->sigev_notify, &u_event->sigev_notify) - | __get_user(event->sigev_notify_thread_id, - &u_event->sigev_notify_thread_id); -} - asmlinkage long compat_sys_mq_notify(mqd_t mqdes, const struct compat_sigevent __user *u_notification) { diff -ruNp linus-sigval/kernel/compat.c linus-sigevent/kernel/compat.c --- linus-sigval/kernel/compat.c 2005-03-07 13:06:24.000000000 +1100 +++ linus-sigevent/kernel/compat.c 2005-03-08 16:16:51.000000000 +1100 @@ -630,6 +630,27 @@ long compat_sys_clock_nanosleep(clockid_ return err; } +/* + * We currently only need the following fields from the sigevent + * structure: sigev_value, sigev_signo, sig_notify and (sometimes + * sigev_notify_thread_id). The others are handled in user mode. + * We also assume that copying sigev_value.sival_int is sufficient + * to keep all the bits of sigev_value.sival_ptr intact. + */ +int get_compat_sigevent(struct sigevent *event, + const struct compat_sigevent __user *u_event) +{ + memset(&event, 0, sizeof(*event)); + return (!access_ok(VERIFY_READ, u_event, sizeof(*u_event)) || + __get_user(event->sigev_value.sival_int, + &u_event->sigev_value.sival_int) || + __get_user(event->sigev_signo, &u_event->sigev_signo) || + __get_user(event->sigev_notify, &u_event->sigev_notify) || + __get_user(event->sigev_notify_thread_id, + &u_event->sigev_notify_thread_id)) + ? -EFAULT : 0; +} + /* timer_create is architecture specific because it needs sigevent conversion */ long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask,
