X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=kernel%2Fcompat.c;h=54a6f329f4f3834e4cada1568da56bf64cd327ae;hb=652c26eda1f0de21c65ddb9e538b9592681c3da5;hp=74ff8498809a0af4b60c9df461825f80c5007260;hpb=659e45d8a0aca8619f0d308448c480279fa002b6;p=cascardo%2Flinux.git diff --git a/kernel/compat.c b/kernel/compat.c index 74ff8498809a..54a6f329f4f3 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -372,25 +373,54 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set) #ifdef __ARCH_WANT_SYS_SIGPROCMASK -asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set, - compat_old_sigset_t __user *oset) +/* + * sys_sigprocmask SIG_SETMASK sets the first (compat) word of the + * blocked set of signals to the supplied signal set + */ +static inline void compat_sig_setmask(sigset_t *blocked, compat_sigset_word set) { - old_sigset_t s; - long ret; - mm_segment_t old_fs; + memcpy(blocked->sig, &set, sizeof(set)); +} - if (set && get_user(s, set)) - return -EFAULT; - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_sigprocmask(how, - set ? (old_sigset_t __user *) &s : NULL, - oset ? (old_sigset_t __user *) &s : NULL); - set_fs(old_fs); - if (ret == 0) - if (oset) - ret = put_user(s, oset); - return ret; +asmlinkage long compat_sys_sigprocmask(int how, + compat_old_sigset_t __user *nset, + compat_old_sigset_t __user *oset) +{ + old_sigset_t old_set, new_set; + sigset_t new_blocked; + + old_set = current->blocked.sig[0]; + + if (nset) { + if (get_user(new_set, nset)) + return -EFAULT; + new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); + + new_blocked = current->blocked; + + switch (how) { + case SIG_BLOCK: + sigaddsetmask(&new_blocked, new_set); + break; + case SIG_UNBLOCK: + sigdelsetmask(&new_blocked, new_set); + break; + case SIG_SETMASK: + compat_sig_setmask(&new_blocked, new_set); + break; + default: + return -EINVAL; + } + + set_current_blocked(&new_blocked); + } + + if (oset) { + if (put_user(old_set, oset)) + return -EFAULT; + } + + return 0; } #endif @@ -1194,6 +1224,28 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info) return 0; } +/* Note: it is necessary to treat option as an unsigned int, + * with the corresponding cast to a signed int to ensure that the + * proper conversion (sign extension) between the register representation + * of a signed int (msr in 32-bit mode) and the register representation + * of a signed int (msr in 64-bit mode) is performed. + */ +asmlinkage long compat_sys_prctl(u32 option, u32 arg2, u32 arg3, + u32 arg4, u32 arg5) +{ + unsigned long a2 = arg2; + + /* PR_SET_PTRACER_ANY is -1, so can't do an unsigned extension */ + if (option == PR_SET_PTRACER && arg2 == (u32) PR_SET_PTRACER_ANY) + a2 = PR_SET_PTRACER_ANY; + + return sys_prctl((int)option, + (unsigned long) a2, + (unsigned long) arg3, + (unsigned long) arg4, + (unsigned long) arg5); +} + /* * Allocate user-space memory for the duration of a single system call, * in order to marshall parameters inside a compat thunk.