diff options
-rw-r--r-- | arch/Kconfig | 3 | ||||
-rw-r--r-- | include/linux/compat.h | 8 | ||||
-rw-r--r-- | kernel/compat.c | 13 | ||||
-rw-r--r-- | kernel/signal.c | 41 |
4 files changed, 63 insertions, 2 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 6e4c32a5a358..374a68adbf1f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -359,6 +359,9 @@ config MODULES_USE_ELF_REL | |||
359 | config GENERIC_SIGALTSTACK | 359 | config GENERIC_SIGALTSTACK |
360 | bool | 360 | bool |
361 | 361 | ||
362 | config GENERIC_COMPAT_RT_SIGPROCMASK | ||
363 | bool | ||
364 | |||
362 | # | 365 | # |
363 | # ABI hall of shame | 366 | # ABI hall of shame |
364 | # | 367 | # |
diff --git a/include/linux/compat.h b/include/linux/compat.h index dec7e2d18875..9d3c2a98d537 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
@@ -401,7 +401,8 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, | |||
401 | asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); | 401 | asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); |
402 | 402 | ||
403 | extern int compat_printk(const char *fmt, ...); | 403 | extern int compat_printk(const char *fmt, ...); |
404 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | 404 | extern void sigset_from_compat(sigset_t *set, const compat_sigset_t *compat); |
405 | extern void sigset_to_compat(compat_sigset_t *compat, const sigset_t *set); | ||
405 | 406 | ||
406 | asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, | 407 | asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, |
407 | compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, | 408 | compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, |
@@ -592,6 +593,11 @@ asmlinkage long compat_sys_rt_sigtimedwait(compat_sigset_t __user *uthese, | |||
592 | struct compat_timespec __user *uts, compat_size_t sigsetsize); | 593 | struct compat_timespec __user *uts, compat_size_t sigsetsize); |
593 | asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, | 594 | asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, |
594 | compat_size_t sigsetsize); | 595 | compat_size_t sigsetsize); |
596 | #ifdef CONFIG_GENERIC_COMPAT_RT_SIGPROCMASK | ||
597 | asmlinkage long compat_sys_rt_sigprocmask(int how, compat_sigset_t __user *set, | ||
598 | compat_sigset_t __user *oset, | ||
599 | compat_size_t sigsetsize); | ||
600 | #endif | ||
595 | asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info); | 601 | asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info); |
596 | asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | 602 | asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, |
597 | unsigned long arg); | 603 | unsigned long arg); |
diff --git a/kernel/compat.c b/kernel/compat.c index 0c07d435254f..e2a9c4785988 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -971,7 +971,7 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, | |||
971 | } | 971 | } |
972 | 972 | ||
973 | void | 973 | void |
974 | sigset_from_compat (sigset_t *set, compat_sigset_t *compat) | 974 | sigset_from_compat(sigset_t *set, const compat_sigset_t *compat) |
975 | { | 975 | { |
976 | switch (_NSIG_WORDS) { | 976 | switch (_NSIG_WORDS) { |
977 | case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 ); | 977 | case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 ); |
@@ -982,6 +982,17 @@ sigset_from_compat (sigset_t *set, compat_sigset_t *compat) | |||
982 | } | 982 | } |
983 | EXPORT_SYMBOL_GPL(sigset_from_compat); | 983 | EXPORT_SYMBOL_GPL(sigset_from_compat); |
984 | 984 | ||
985 | void | ||
986 | sigset_to_compat(compat_sigset_t *compat, const sigset_t *set) | ||
987 | { | ||
988 | switch (_NSIG_WORDS) { | ||
989 | case 4: compat->sig[7] = (set->sig[3] >> 32); compat->sig[6] = set->sig[3]; | ||
990 | case 3: compat->sig[5] = (set->sig[2] >> 32); compat->sig[4] = set->sig[2]; | ||
991 | case 2: compat->sig[3] = (set->sig[1] >> 32); compat->sig[2] = set->sig[1]; | ||
992 | case 1: compat->sig[1] = (set->sig[0] >> 32); compat->sig[0] = set->sig[0]; | ||
993 | } | ||
994 | } | ||
995 | |||
985 | asmlinkage long | 996 | asmlinkage long |
986 | compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, | 997 | compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, |
987 | struct compat_siginfo __user *uinfo, | 998 | struct compat_siginfo __user *uinfo, |
diff --git a/kernel/signal.c b/kernel/signal.c index 4a0934e03d5c..bce1222b7315 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -2613,6 +2613,47 @@ SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset, | |||
2613 | return 0; | 2613 | return 0; |
2614 | } | 2614 | } |
2615 | 2615 | ||
2616 | #ifdef CONFIG_COMPAT | ||
2617 | #ifdef CONFIG_GENERIC_COMPAT_RT_SIGPROCMASK | ||
2618 | COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset, | ||
2619 | compat_sigset_t __user *, oset, compat_size_t, sigsetsize) | ||
2620 | { | ||
2621 | #ifdef __BIG_ENDIAN | ||
2622 | sigset_t old_set = current->blocked; | ||
2623 | |||
2624 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
2625 | if (sigsetsize != sizeof(sigset_t)) | ||
2626 | return -EINVAL; | ||
2627 | |||
2628 | if (nset) { | ||
2629 | compat_sigset_t new32; | ||
2630 | sigset_t new_set; | ||
2631 | int error; | ||
2632 | if (copy_from_user(&new32, nset, sizeof(compat_sigset_t))) | ||
2633 | return -EFAULT; | ||
2634 | |||
2635 | sigset_from_compat(&new_set, &new32); | ||
2636 | sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
2637 | |||
2638 | error = sigprocmask(how, &new_set, NULL); | ||
2639 | if (error) | ||
2640 | return error; | ||
2641 | } | ||
2642 | if (oset) { | ||
2643 | compat_sigset_t old32; | ||
2644 | sigset_to_compat(&old32, &old_set); | ||
2645 | if (copy_to_user(oset, &old_set, sizeof(sigset_t))) | ||
2646 | return -EFAULT; | ||
2647 | } | ||
2648 | return 0; | ||
2649 | #else | ||
2650 | return sys_rt_sigprocmask(how, (sigset_t __user *)nset, | ||
2651 | (sigset_t __user *)oset, sigsetsize); | ||
2652 | #endif | ||
2653 | } | ||
2654 | #endif | ||
2655 | #endif | ||
2656 | |||
2616 | long do_sigpending(void __user *set, unsigned long sigsetsize) | 2657 | long do_sigpending(void __user *set, unsigned long sigsetsize) |
2617 | { | 2658 | { |
2618 | long error = -EINVAL; | 2659 | long error = -EINVAL; |