Commit 119cd59f authored by Al Viro's avatar Al Viro

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.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 57d563c8
...@@ -365,38 +365,37 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, ...@@ -365,38 +365,37 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate); frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(frame, sizeof(*frame))) if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT; return -EFAULT;
put_user_try { unsafe_put_user(sig, &frame->sig, Efault);
put_user_ex(sig, &frame->sig); unsafe_put_user(&frame->info, &frame->pinfo, Efault);
put_user_ex(&frame->info, &frame->pinfo); unsafe_put_user(&frame->uc, &frame->puc, Efault);
put_user_ex(&frame->uc, &frame->puc);
/* Create the ucontext. */ /* Create the ucontext. */
if (static_cpu_has(X86_FEATURE_XSAVE)) if (static_cpu_has(X86_FEATURE_XSAVE))
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); unsafe_put_user(UC_FP_XSTATE, &frame->uc.uc_flags, Efault);
else else
put_user_ex(0, &frame->uc.uc_flags); unsafe_put_user(0, &frame->uc.uc_flags, Efault);
put_user_ex(0, &frame->uc.uc_link); unsafe_put_user(0, &frame->uc.uc_link, Efault);
save_altstack_ex(&frame->uc.uc_stack, regs->sp); unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
/* Set up to return from userspace. */ /* Set up to return from userspace. */
restorer = current->mm->context.vdso + restorer = current->mm->context.vdso +
vdso_image_32.sym___kernel_rt_sigreturn; vdso_image_32.sym___kernel_rt_sigreturn;
if (ksig->ka.sa.sa_flags & SA_RESTORER) if (ksig->ka.sa.sa_flags & SA_RESTORER)
restorer = ksig->ka.sa.sa_restorer; restorer = ksig->ka.sa.sa_restorer;
put_user_ex(restorer, &frame->pretcode); unsafe_put_user(restorer, &frame->pretcode, Efault);
/* /*
* This is movl $__NR_rt_sigreturn, %ax ; int $0x80 * This is movl $__NR_rt_sigreturn, %ax ; int $0x80
* *
* WE DO NOT USE IT ANY MORE! It's only left here for historical * WE DO NOT USE IT ANY MORE! It's only left here for historical
* reasons and because gdb uses it as a signature to notice * reasons and because gdb uses it as a signature to notice
* signal handler stack frames. * signal handler stack frames.
*/ */
put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); unsafe_put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode, Efault);
} put_user_catch(err); user_access_end();
err |= copy_siginfo_to_user(&frame->info, &ksig->info); err |= copy_siginfo_to_user(&frame->info, &ksig->info);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
...@@ -419,6 +418,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, ...@@ -419,6 +418,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
regs->cs = __USER_CS; regs->cs = __USER_CS;
return 0; return 0;
Efault:
user_access_end();
return -EFAULT;
} }
#else /* !CONFIG_X86_32 */ #else /* !CONFIG_X86_32 */
static unsigned long frame_uc_flags(struct pt_regs *regs) static unsigned long frame_uc_flags(struct pt_regs *regs)
...@@ -444,6 +446,10 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, ...@@ -444,6 +446,10 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
unsigned long uc_flags; unsigned long uc_flags;
int err = 0; int err = 0;
/* x86-64 should always use SA_RESTORER. */
if (!(ksig->ka.sa.sa_flags & SA_RESTORER))
return -EFAULT;
frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp); frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);
if (!access_ok(frame, sizeof(*frame))) if (!access_ok(frame, sizeof(*frame)))
...@@ -455,23 +461,18 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, ...@@ -455,23 +461,18 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
} }
uc_flags = frame_uc_flags(regs); uc_flags = frame_uc_flags(regs);
if (!user_access_begin(frame, sizeof(*frame)))
return -EFAULT;
put_user_try { /* Create the ucontext. */
/* Create the ucontext. */ unsafe_put_user(uc_flags, &frame->uc.uc_flags, Efault);
put_user_ex(uc_flags, &frame->uc.uc_flags); unsafe_put_user(0, &frame->uc.uc_link, Efault);
put_user_ex(0, &frame->uc.uc_link); unsafe_save_altstack(&frame->uc.uc_stack, regs->sp, Efault);
save_altstack_ex(&frame->uc.uc_stack, regs->sp);
/* Set up to return from userspace. If provided, use a stub
/* Set up to return from userspace. If provided, use a stub already in userspace. */
already in userspace. */ unsafe_put_user(ksig->ka.sa.sa_restorer, &frame->pretcode, Efault);
/* x86-64 should always use SA_RESTORER. */ user_access_end();
if (ksig->ka.sa.sa_flags & SA_RESTORER) {
put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode);
} else {
/* could use a vstub here */
err |= -EFAULT;
}
} put_user_catch(err);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); 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, ...@@ -515,6 +516,10 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
force_valid_ss(regs); force_valid_ss(regs);
return 0; return 0;
Efault:
user_access_end();
return -EFAULT;
} }
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
......
...@@ -444,12 +444,12 @@ void signals_init(void); ...@@ -444,12 +444,12 @@ void signals_init(void);
int restore_altstack(const stack_t __user *); int restore_altstack(const stack_t __user *);
int __save_altstack(stack_t __user *, unsigned long); int __save_altstack(stack_t __user *, unsigned long);
#define save_altstack_ex(uss, sp) do { \ #define unsafe_save_altstack(uss, sp, label) do { \
stack_t __user *__uss = uss; \ stack_t __user *__uss = uss; \
struct task_struct *t = current; \ struct task_struct *t = current; \
put_user_ex((void __user *)t->sas_ss_sp, &__uss->ss_sp); \ unsafe_put_user((void __user *)t->sas_ss_sp, &__uss->ss_sp, label); \
put_user_ex(t->sas_ss_flags, &__uss->ss_flags); \ unsafe_put_user(t->sas_ss_flags, &__uss->ss_flags, label); \
put_user_ex(t->sas_ss_size, &__uss->ss_size); \ unsafe_put_user(t->sas_ss_size, &__uss->ss_size, label); \
if (t->sas_ss_flags & SS_AUTODISARM) \ if (t->sas_ss_flags & SS_AUTODISARM) \
sas_ss_reset(t); \ sas_ss_reset(t); \
} while (0); } while (0);
......
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