Commit bcfe8ad8 authored by Al Viro's avatar Al Viro

do_sigaltstack(): lift copying to/from userland into callers

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 613763a1
...@@ -3113,78 +3113,68 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) ...@@ -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;
oss->ss_size = t->sas_ss_size;
oss->ss_flags = sas_ss_flags(sp) |
(current->sas_ss_flags & SS_FLAG_BITS); (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, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment