diff options
Diffstat (limited to 'kernel/compat.c')
| -rw-r--r-- | kernel/compat.c | 73 |
1 files changed, 47 insertions, 26 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index 74ff8498809a..c28a306ae05c 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
| @@ -372,25 +372,54 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set) | |||
| 372 | 372 | ||
| 373 | #ifdef __ARCH_WANT_SYS_SIGPROCMASK | 373 | #ifdef __ARCH_WANT_SYS_SIGPROCMASK |
| 374 | 374 | ||
| 375 | asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set, | 375 | /* |
| 376 | compat_old_sigset_t __user *oset) | 376 | * sys_sigprocmask SIG_SETMASK sets the first (compat) word of the |
| 377 | * blocked set of signals to the supplied signal set | ||
| 378 | */ | ||
| 379 | static inline void compat_sig_setmask(sigset_t *blocked, compat_sigset_word set) | ||
| 377 | { | 380 | { |
| 378 | old_sigset_t s; | 381 | memcpy(blocked->sig, &set, sizeof(set)); |
| 379 | long ret; | 382 | } |
| 380 | mm_segment_t old_fs; | ||
| 381 | 383 | ||
| 382 | if (set && get_user(s, set)) | 384 | asmlinkage long compat_sys_sigprocmask(int how, |
| 383 | return -EFAULT; | 385 | compat_old_sigset_t __user *nset, |
| 384 | old_fs = get_fs(); | 386 | compat_old_sigset_t __user *oset) |
| 385 | set_fs(KERNEL_DS); | 387 | { |
| 386 | ret = sys_sigprocmask(how, | 388 | old_sigset_t old_set, new_set; |
| 387 | set ? (old_sigset_t __user *) &s : NULL, | 389 | sigset_t new_blocked; |
| 388 | oset ? (old_sigset_t __user *) &s : NULL); | 390 | |
| 389 | set_fs(old_fs); | 391 | old_set = current->blocked.sig[0]; |
| 390 | if (ret == 0) | 392 | |
| 391 | if (oset) | 393 | if (nset) { |
| 392 | ret = put_user(s, oset); | 394 | if (get_user(new_set, nset)) |
| 393 | return ret; | 395 | return -EFAULT; |
| 396 | new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
| 397 | |||
| 398 | new_blocked = current->blocked; | ||
| 399 | |||
| 400 | switch (how) { | ||
| 401 | case SIG_BLOCK: | ||
| 402 | sigaddsetmask(&new_blocked, new_set); | ||
| 403 | break; | ||
| 404 | case SIG_UNBLOCK: | ||
| 405 | sigdelsetmask(&new_blocked, new_set); | ||
| 406 | break; | ||
| 407 | case SIG_SETMASK: | ||
| 408 | compat_sig_setmask(&new_blocked, new_set); | ||
| 409 | break; | ||
| 410 | default: | ||
| 411 | return -EINVAL; | ||
| 412 | } | ||
| 413 | |||
| 414 | set_current_blocked(&new_blocked); | ||
| 415 | } | ||
| 416 | |||
| 417 | if (oset) { | ||
| 418 | if (put_user(old_set, oset)) | ||
| 419 | return -EFAULT; | ||
| 420 | } | ||
| 421 | |||
| 422 | return 0; | ||
| 394 | } | 423 | } |
| 395 | 424 | ||
| 396 | #endif | 425 | #endif |
| @@ -1044,15 +1073,7 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat | |||
| 1044 | if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) | 1073 | if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) |
| 1045 | return -EFAULT; | 1074 | return -EFAULT; |
| 1046 | sigset_from_compat(&newset, &newset32); | 1075 | sigset_from_compat(&newset, &newset32); |
| 1047 | sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); | 1076 | return sigsuspend(&newset); |
| 1048 | |||
| 1049 | current->saved_sigmask = current->blocked; | ||
| 1050 | set_current_blocked(&newset); | ||
| 1051 | |||
| 1052 | current->state = TASK_INTERRUPTIBLE; | ||
| 1053 | schedule(); | ||
| 1054 | set_restore_sigmask(); | ||
| 1055 | return -ERESTARTNOHAND; | ||
| 1056 | } | 1077 | } |
| 1057 | #endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */ | 1078 | #endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */ |
| 1058 | 1079 | ||
