History

x86: get rid of put_user_try in __setup_rt_frame() (both 32bit and 64bit)

Straightforward, except for save_altstack_ex() stuck in those. Replace that thing with an analogue that would use unsafe_put_user() instead of put_user_ex() (called compat_save_altstack()) and be done with that.

Al Viro committed 6 years ago

Commit 119cd591 parent 57d563c2 files · +52 −47Browse files

Unified · Split

2 files
  1. arch/x86/kernel/signal.c +48 −43
  2. include/linux/signal.h +4 −4
arch/x86/kernel/signal.c+48−43
@@ -365,38 +365,37 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, · 364 unmodified lines
365365
366366 frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
367367
368− if (!access_ok(frame, sizeof(*frame)))
368+ if (!user_access_begin(frame, sizeof(*frame)))
369369 return -EFAULT;
370370
371− put_user_try {
372− put_user_ex(sig, &frame->sig);
373− put_user_ex(&frame->info, &frame->pinfo);
374− put_user_ex(&frame->uc, &frame->puc);
371+ unsafe_put_user(sig, &frame->sig, Efault);
372+ unsafe_put_user(&frame->info, &frame->pinfo, Efault);
373+ unsafe_put_user(&frame->uc, &frame->puc, Efault);
375374
376− /* Create the ucontext. */
377− if (static_cpu_has(X86_FEATURE_XSAVE))
378− put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
379− else
380− put_user_ex(0, &frame->uc.uc_flags);
381− put_user_ex(0, &frame->uc.uc_link);
382− save_altstack_ex(&frame->uc.uc_stack, regs->sp);
375+ /* Create the ucontext. */
376+ if (static_cpu_has(X86_FEATURE_XSAVE))
377+ unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
378+ else
379+ unsafe_put_user(0, &frame->uc.uc_flags, Efault);
380+ unsafe_put_user(0, &frame->uc.uc_link, Efault);
381+ unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
383382
384− /* Set up to return from userspace. */
385− restorer = current->mm->context.vdso +
386− vdso_image_32.sym___kernel_rt_sigreturn;
387− if (ksig->ka.sa.sa_flags & SA_RESTORER)
388− restorer = ksig->ka.sa.sa_restorer;
389− put_user_ex(restorer, &frame->pretcode);
383+ /* Set up to return from userspace. */
384+ restorer = current->mm->context.vdso +
385+ vdso_image_32.sym___kernel_rt_sigreturn;
386+ if (ksig->ka.sa.sa_flags & SA_RESTORER)
387+ restorer = ksig->ka.sa.sa_restorer;
388+ unsafe_put_user(restorer, &frame->pretcode, Efault);
390389
391− /*
392− * This is movl $__NR_rt_sigreturn, %ax ; int $0x80
393− *
394− * WE DO NOT USE IT ANY MORE! It's only left here for historical
395− * reasons and because gdb uses it as a signature to notice
396− * signal handler stack frames.
397− */
398− put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
399− } put_user_catch(err);
390+ /*
391+ * This is movl $__NR_rt_sigreturn, %ax ; int $0x80
392+ *
393+ * WE DO NOT USE IT ANY MORE! It's only left here for historical
394+ * reasons and because gdb uses it as a signature to notice
395+ * signal handler stack frames.
396+ */
397+ unsafe_put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode, Efault);
398+ user_access_end();
400399
401400 err |= copy_siginfo_to_user(&frame->info, &ksig->info);
402401 err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
@@ -419,6 +418,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, · 16 unmodified lines
419418 regs->cs = __USER_CS;
420419
421420 return 0;
421+Efault:
422+ user_access_end();
423+ return -EFAULT;
422424 }
423425 #else /* !CONFIG_X86_32 */
424426 static unsigned long frame_uc_flags(struct pt_regs *regs)
@@ -444,6 +446,10 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, · 19 unmodified lines
444446 unsigned long uc_flags;
445447 int err = 0;
446448
449+ /* x86-64 should always use SA_RESTORER. */
450+ if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
451+ return -EFAULT;
452+
447453 frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);
448454
449455 if (!access_ok(frame, sizeof(*frame)))
@@ -455,23 +461,18 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, · 5 unmodified lines
455461 }
456462
457463 uc_flags = frame_uc_flags(regs);
464+ if (!user_access_begin(frame, sizeof(*frame)))
465+ return -EFAULT;
458466
459− put_user_try {
460− /* Create the ucontext. */
461− put_user_ex(uc_flags, &frame->uc.uc_flags);
462− put_user_ex(0, &frame->uc.uc_link);
463− save_altstack_ex(&frame->uc.uc_stack, regs->sp);
464−
465− /* Set up to return from userspace. If provided, use a stub
466− already in userspace. */
467− /* x86-64 should always use SA_RESTORER. */
468− if (ksig->ka.sa.sa_flags & SA_RESTORER) {
469− put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode);
470− } else {
471− /* could use a vstub here */
472− err |= -EFAULT;
473− }
474− } put_user_catch(err);
467+ /* Create the ucontext. */
468+ unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
469+ unsafe_put_user(0, &frame->uc.uc_link, Efault);
470+ unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
471+
472+ /* Set up to return from userspace. If provided, use a stub
473+ already in userspace. */
474+ unsafe_put_user(ksig->ka.sa.sa_restorer, &frame->pretcode, Efault);
475+ user_access_end();
475476
476477 err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
477478 err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
@@ -515,6 +516,10 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, · 37 unmodified lines
515516 force_valid_ss(regs);
516517
517518 return 0;
519+
520+Efault:
521+ user_access_end();
522+ return -EFAULT;
518523 }
519524 #endif /* CONFIG_X86_32 */
520525
include/linux/signal.h+4−4
@@ -444,12 +444,12 @@ void signals_init(void); · 443 unmodified lines
444444 int restore_altstack(const stack_t __user *);
445445 int __save_altstack(stack_t __user *, unsigned long);
446446
447−#define save_altstack_ex(uss, sp) do { \
447+#define unsafe_save_altstack(uss, sp, label) do { \
448448 stack_t __user *__uss = uss; \
449449 struct task_struct *t = current; \
450− put_user_ex((void __user *)t->sas_ss_sp, &__uss->ss_sp); \
451− put_user_ex(t->sas_ss_flags, &__uss->ss_flags); \
452− put_user_ex(t->sas_ss_size, &__uss->ss_size); \
450+ unsafe_put_user((void __user *)t->sas_ss_sp, &__uss->ss_sp, label); \
451+ unsafe_put_user(t->sas_ss_flags, &__uss->ss_flags, label); \
452+ unsafe_put_user(t->sas_ss_size, &__uss->ss_size, label); \
453453 if (t->sas_ss_flags & SS_AUTODISARM) \
454454 sas_ss_reset(t); \
455455 } while (0);