aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-05-27 00:29:34 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-05-27 15:38:17 -0400
commitbcfe8ad8ef55a1cf3c935c2667e8e5ae598b3b7e (patch)
treeb94e3ebf18142c1c2fde4d7d1da4d68035100b86
parent613763a1f056211522bac77ff39f25706e678fdd (diff)
do_sigaltstack(): lift copying to/from userland into callers
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--kernel/signal.c107
1 files changed, 46 insertions, 61 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index ca92bcfeb322..d1eed0d7ca64 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3113,78 +3113,68 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
3113} 3113}
3114 3114
3115static int 3115static int
3116do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp) 3116do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp)
3117{ 3117{
3118 stack_t oss; 3118 struct task_struct *t = current;
3119 int error;
3120 3119
3121 oss.ss_sp = (void __user *) current->sas_ss_sp; 3120 if (oss) {
3122 oss.ss_size = current->sas_ss_size; 3121 memset(oss, 0, sizeof(stack_t));
3123 oss.ss_flags = sas_ss_flags(sp) | 3122 oss->ss_sp = (void __user *) t->sas_ss_sp;
3124 (current->sas_ss_flags & SS_FLAG_BITS); 3123 oss->ss_size = t->sas_ss_size;
3124 oss->ss_flags = sas_ss_flags(sp) |
3125 (current->sas_ss_flags & SS_FLAG_BITS);
3126 }
3125 3127
3126 if (uss) { 3128 if (ss) {
3127 void __user *ss_sp; 3129 void __user *ss_sp = ss->ss_sp;
3128 size_t ss_size; 3130 size_t ss_size = ss->ss_size;
3129 unsigned ss_flags; 3131 unsigned ss_flags = ss->ss_flags;
3130 int ss_mode; 3132 int ss_mode;
3131 3133
3132 error = -EFAULT; 3134 if (unlikely(on_sig_stack(sp)))
3133 if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) 3135 return -EPERM;
3134 goto out;
3135 error = __get_user(ss_sp, &uss->ss_sp) |
3136 __get_user(ss_flags, &uss->ss_flags) |
3137 __get_user(ss_size, &uss->ss_size);
3138 if (error)
3139 goto out;
3140
3141 error = -EPERM;
3142 if (on_sig_stack(sp))
3143 goto out;
3144 3136
3145 ss_mode = ss_flags & ~SS_FLAG_BITS; 3137 ss_mode = ss_flags & ~SS_FLAG_BITS;
3146 error = -EINVAL; 3138 if (unlikely(ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
3147 if (ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK && 3139 ss_mode != 0))
3148 ss_mode != 0) 3140 return -EINVAL;
3149 goto out;
3150 3141
3151 if (ss_mode == SS_DISABLE) { 3142 if (ss_mode == SS_DISABLE) {
3152 ss_size = 0; 3143 ss_size = 0;
3153 ss_sp = NULL; 3144 ss_sp = NULL;
3154 } else { 3145 } else {
3155 error = -ENOMEM; 3146 if (unlikely(ss_size < MINSIGSTKSZ))
3156 if (ss_size < MINSIGSTKSZ) 3147 return -ENOMEM;
3157 goto out;
3158 } 3148 }
3159 3149
3160 current->sas_ss_sp = (unsigned long) ss_sp; 3150 t->sas_ss_sp = (unsigned long) ss_sp;
3161 current->sas_ss_size = ss_size; 3151 t->sas_ss_size = ss_size;
3162 current->sas_ss_flags = ss_flags; 3152 t->sas_ss_flags = ss_flags;
3163 }
3164
3165 error = 0;
3166 if (uoss) {
3167 error = -EFAULT;
3168 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
3169 goto out;
3170 error = __put_user(oss.ss_sp, &uoss->ss_sp) |
3171 __put_user(oss.ss_size, &uoss->ss_size) |
3172 __put_user(oss.ss_flags, &uoss->ss_flags);
3173 } 3153 }
3174 3154 return 0;
3175out:
3176 return error;
3177} 3155}
3156
3178SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss) 3157SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
3179{ 3158{
3180 return do_sigaltstack(uss, uoss, current_user_stack_pointer()); 3159 stack_t new, old;
3160 int err;
3161 if (uss && copy_from_user(&new, uss, sizeof(stack_t)))
3162 return -EFAULT;
3163 err = do_sigaltstack(uss ? &new : NULL, uoss ? &old : NULL,
3164 current_user_stack_pointer());
3165 if (!err && uoss && copy_to_user(uoss, &old, sizeof(stack_t)))
3166 err = -EFAULT;
3167 return err;
3181} 3168}
3182 3169
3183int restore_altstack(const stack_t __user *uss) 3170int restore_altstack(const stack_t __user *uss)
3184{ 3171{
3185 int err = do_sigaltstack(uss, NULL, current_user_stack_pointer()); 3172 stack_t new;
3173 if (copy_from_user(&new, uss, sizeof(stack_t)))
3174 return -EFAULT;
3175 (void)do_sigaltstack(&new, NULL, current_user_stack_pointer());
3186 /* squash all but EFAULT for now */ 3176 /* squash all but EFAULT for now */
3187 return err == -EFAULT ? err : 0; 3177 return 0;
3188} 3178}
3189 3179
3190int __save_altstack(stack_t __user *uss, unsigned long sp) 3180int __save_altstack(stack_t __user *uss, unsigned long sp)
@@ -3207,29 +3197,24 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack,
3207{ 3197{
3208 stack_t uss, uoss; 3198 stack_t uss, uoss;
3209 int ret; 3199 int ret;
3210 mm_segment_t seg;
3211 3200
3212 if (uss_ptr) { 3201 if (uss_ptr) {
3213 compat_stack_t uss32; 3202 compat_stack_t uss32;
3214
3215 memset(&uss, 0, sizeof(stack_t));
3216 if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t))) 3203 if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t)))
3217 return -EFAULT; 3204 return -EFAULT;
3218 uss.ss_sp = compat_ptr(uss32.ss_sp); 3205 uss.ss_sp = compat_ptr(uss32.ss_sp);
3219 uss.ss_flags = uss32.ss_flags; 3206 uss.ss_flags = uss32.ss_flags;
3220 uss.ss_size = uss32.ss_size; 3207 uss.ss_size = uss32.ss_size;
3221 } 3208 }
3222 seg = get_fs(); 3209 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
3223 set_fs(KERNEL_DS);
3224 ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
3225 (stack_t __force __user *) &uoss,
3226 compat_user_stack_pointer()); 3210 compat_user_stack_pointer());
3227 set_fs(seg);
3228 if (ret >= 0 && uoss_ptr) { 3211 if (ret >= 0 && uoss_ptr) {
3229 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) || 3212 compat_stack_t old;
3230 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) || 3213 memset(&old, 0, sizeof(old));
3231 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) || 3214 old.ss_sp = ptr_to_compat(uoss.ss_sp);
3232 __put_user(uoss.ss_size, &uoss_ptr->ss_size)) 3215 old.ss_flags = uoss.ss_flags;
3216 old.ss_size = uoss.ss_size;
3217 if (copy_to_user(uoss_ptr, &old, sizeof(compat_stack_t)))
3233 ret = -EFAULT; 3218 ret = -EFAULT;
3234 } 3219 }
3235 return ret; 3220 return ret;