do_sigaltstack(): lift copying to/from userland into callers
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
613763a1f0
commit
bcfe8ad8ef
107
kernel/signal.c
107
kernel/signal.c
|
@ -3113,78 +3113,68 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp)
|
do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp)
|
||||||
{
|
{
|
||||||
stack_t oss;
|
struct task_struct *t = current;
|
||||||
int error;
|
|
||||||
|
|
||||||
oss.ss_sp = (void __user *) current->sas_ss_sp;
|
if (oss) {
|
||||||
oss.ss_size = current->sas_ss_size;
|
memset(oss, 0, sizeof(stack_t));
|
||||||
oss.ss_flags = sas_ss_flags(sp) |
|
oss->ss_sp = (void __user *) t->sas_ss_sp;
|
||||||
(current->sas_ss_flags & SS_FLAG_BITS);
|
oss->ss_size = t->sas_ss_size;
|
||||||
|
oss->ss_flags = sas_ss_flags(sp) |
|
||||||
|
(current->sas_ss_flags & SS_FLAG_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
if (uss) {
|
if (ss) {
|
||||||
void __user *ss_sp;
|
void __user *ss_sp = ss->ss_sp;
|
||||||
size_t ss_size;
|
size_t ss_size = ss->ss_size;
|
||||||
unsigned ss_flags;
|
unsigned ss_flags = ss->ss_flags;
|
||||||
int ss_mode;
|
int ss_mode;
|
||||||
|
|
||||||
error = -EFAULT;
|
if (unlikely(on_sig_stack(sp)))
|
||||||
if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
|
return -EPERM;
|
||||||
goto out;
|
|
||||||
error = __get_user(ss_sp, &uss->ss_sp) |
|
|
||||||
__get_user(ss_flags, &uss->ss_flags) |
|
|
||||||
__get_user(ss_size, &uss->ss_size);
|
|
||||||
if (error)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
error = -EPERM;
|
|
||||||
if (on_sig_stack(sp))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ss_mode = ss_flags & ~SS_FLAG_BITS;
|
ss_mode = ss_flags & ~SS_FLAG_BITS;
|
||||||
error = -EINVAL;
|
if (unlikely(ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
|
||||||
if (ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
|
ss_mode != 0))
|
||||||
ss_mode != 0)
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (ss_mode == SS_DISABLE) {
|
if (ss_mode == SS_DISABLE) {
|
||||||
ss_size = 0;
|
ss_size = 0;
|
||||||
ss_sp = NULL;
|
ss_sp = NULL;
|
||||||
} else {
|
} else {
|
||||||
error = -ENOMEM;
|
if (unlikely(ss_size < MINSIGSTKSZ))
|
||||||
if (ss_size < MINSIGSTKSZ)
|
return -ENOMEM;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
current->sas_ss_sp = (unsigned long) ss_sp;
|
t->sas_ss_sp = (unsigned long) ss_sp;
|
||||||
current->sas_ss_size = ss_size;
|
t->sas_ss_size = ss_size;
|
||||||
current->sas_ss_flags = ss_flags;
|
t->sas_ss_flags = ss_flags;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
error = 0;
|
|
||||||
if (uoss) {
|
|
||||||
error = -EFAULT;
|
|
||||||
if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
|
|
||||||
goto out;
|
|
||||||
error = __put_user(oss.ss_sp, &uoss->ss_sp) |
|
|
||||||
__put_user(oss.ss_size, &uoss->ss_size) |
|
|
||||||
__put_user(oss.ss_flags, &uoss->ss_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
|
SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
|
||||||
{
|
{
|
||||||
return do_sigaltstack(uss, uoss, current_user_stack_pointer());
|
stack_t new, old;
|
||||||
|
int err;
|
||||||
|
if (uss && copy_from_user(&new, uss, sizeof(stack_t)))
|
||||||
|
return -EFAULT;
|
||||||
|
err = do_sigaltstack(uss ? &new : NULL, uoss ? &old : NULL,
|
||||||
|
current_user_stack_pointer());
|
||||||
|
if (!err && uoss && copy_to_user(uoss, &old, sizeof(stack_t)))
|
||||||
|
err = -EFAULT;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int restore_altstack(const stack_t __user *uss)
|
int restore_altstack(const stack_t __user *uss)
|
||||||
{
|
{
|
||||||
int err = do_sigaltstack(uss, NULL, current_user_stack_pointer());
|
stack_t new;
|
||||||
|
if (copy_from_user(&new, uss, sizeof(stack_t)))
|
||||||
|
return -EFAULT;
|
||||||
|
(void)do_sigaltstack(&new, NULL, current_user_stack_pointer());
|
||||||
/* squash all but EFAULT for now */
|
/* squash all but EFAULT for now */
|
||||||
return err == -EFAULT ? err : 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __save_altstack(stack_t __user *uss, unsigned long sp)
|
int __save_altstack(stack_t __user *uss, unsigned long sp)
|
||||||
|
@ -3207,29 +3197,24 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack,
|
||||||
{
|
{
|
||||||
stack_t uss, uoss;
|
stack_t uss, uoss;
|
||||||
int ret;
|
int ret;
|
||||||
mm_segment_t seg;
|
|
||||||
|
|
||||||
if (uss_ptr) {
|
if (uss_ptr) {
|
||||||
compat_stack_t uss32;
|
compat_stack_t uss32;
|
||||||
|
|
||||||
memset(&uss, 0, sizeof(stack_t));
|
|
||||||
if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t)))
|
if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
uss.ss_sp = compat_ptr(uss32.ss_sp);
|
uss.ss_sp = compat_ptr(uss32.ss_sp);
|
||||||
uss.ss_flags = uss32.ss_flags;
|
uss.ss_flags = uss32.ss_flags;
|
||||||
uss.ss_size = uss32.ss_size;
|
uss.ss_size = uss32.ss_size;
|
||||||
}
|
}
|
||||||
seg = get_fs();
|
ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
|
||||||
set_fs(KERNEL_DS);
|
|
||||||
ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
|
|
||||||
(stack_t __force __user *) &uoss,
|
|
||||||
compat_user_stack_pointer());
|
compat_user_stack_pointer());
|
||||||
set_fs(seg);
|
|
||||||
if (ret >= 0 && uoss_ptr) {
|
if (ret >= 0 && uoss_ptr) {
|
||||||
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) ||
|
compat_stack_t old;
|
||||||
__put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
|
memset(&old, 0, sizeof(old));
|
||||||
__put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
|
old.ss_sp = ptr_to_compat(uoss.ss_sp);
|
||||||
__put_user(uoss.ss_size, &uoss_ptr->ss_size))
|
old.ss_flags = uoss.ss_flags;
|
||||||
|
old.ss_size = uoss.ss_size;
|
||||||
|
if (copy_to_user(uoss_ptr, &old, sizeof(compat_stack_t)))
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue