Commit 98e3d45e authored by Hiroshi Shimamoto's avatar Hiroshi Shimamoto Committed by H. Peter Anvin

x86: signal: use {get|put}_user_try and catch

Impact: use new framework

Use {get|put}_user_try, catch, and _ex in arch/x86/kernel/signal.c.

Note: this patch contains "WARNING: line over 80 characters", because when
introducing new block I insert an indent to avoid mistakes by edit.
Signed-off-by: default avatarHiroshi Shimamoto <h-shimamoto@ct.jp.nec.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent fe40c0af
...@@ -51,24 +51,24 @@ ...@@ -51,24 +51,24 @@
#endif #endif
#define COPY(x) { \ #define COPY(x) { \
err |= __get_user(regs->x, &sc->x); \ get_user_ex(regs->x, &sc->x); \
} }
#define COPY_SEG(seg) { \ #define COPY_SEG(seg) { \
unsigned short tmp; \ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \ get_user_ex(tmp, &sc->seg); \
regs->seg = tmp; \ regs->seg = tmp; \
} }
#define COPY_SEG_CPL3(seg) { \ #define COPY_SEG_CPL3(seg) { \
unsigned short tmp; \ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \ get_user_ex(tmp, &sc->seg); \
regs->seg = tmp | 3; \ regs->seg = tmp | 3; \
} }
#define GET_SEG(seg) { \ #define GET_SEG(seg) { \
unsigned short tmp; \ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \ get_user_ex(tmp, &sc->seg); \
loadsegment(seg, tmp); \ loadsegment(seg, tmp); \
} }
...@@ -83,45 +83,49 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, ...@@ -83,45 +83,49 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
/* Always make any pending restarted system calls return -EINTR */ /* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall; current_thread_info()->restart_block.fn = do_no_restart_syscall;
get_user_try {
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
GET_SEG(gs); GET_SEG(gs);
COPY_SEG(fs); COPY_SEG(fs);
COPY_SEG(es); COPY_SEG(es);
COPY_SEG(ds); COPY_SEG(ds);
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip); COPY(dx); COPY(cx); COPY(ip);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
COPY(r8); COPY(r8);
COPY(r9); COPY(r9);
COPY(r10); COPY(r10);
COPY(r11); COPY(r11);
COPY(r12); COPY(r12);
COPY(r13); COPY(r13);
COPY(r14); COPY(r14);
COPY(r15); COPY(r15);
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
COPY_SEG_CPL3(cs); COPY_SEG_CPL3(cs);
COPY_SEG_CPL3(ss); COPY_SEG_CPL3(ss);
#else /* !CONFIG_X86_32 */ #else /* !CONFIG_X86_32 */
/* Kernel saves and restores only the CS segment register on signals, /* Kernel saves and restores only the CS segment register on signals,
* which is the bare minimum needed to allow mixed 32/64-bit code. * which is the bare minimum needed to allow mixed 32/64-bit code.
* App's signal handler can save/restore other segments if needed. */ * App's signal handler can save/restore other segments if needed. */
COPY_SEG_CPL3(cs); COPY_SEG_CPL3(cs);
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
err |= __get_user(tmpflags, &sc->flags); get_user_ex(tmpflags, &sc->flags);
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
regs->orig_ax = -1; /* disable syscall checks */ regs->orig_ax = -1; /* disable syscall checks */
get_user_ex(buf, &sc->fpstate);
err |= restore_i387_xstate(buf);
err |= __get_user(buf, &sc->fpstate); get_user_ex(*pax, &sc->ax);
err |= restore_i387_xstate(buf); } get_user_catch(err);
err |= __get_user(*pax, &sc->ax);
return err; return err;
} }
...@@ -131,57 +135,60 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, ...@@ -131,57 +135,60 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
{ {
int err = 0; int err = 0;
put_user_try {
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
{ {
unsigned int tmp; unsigned int tmp;
savesegment(gs, tmp); savesegment(gs, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->gs); put_user_ex(tmp, (unsigned int __user *)&sc->gs);
} }
err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs); put_user_ex(regs->fs, (unsigned int __user *)&sc->fs);
err |= __put_user(regs->es, (unsigned int __user *)&sc->es); put_user_ex(regs->es, (unsigned int __user *)&sc->es);
err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds); put_user_ex(regs->ds, (unsigned int __user *)&sc->ds);
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
err |= __put_user(regs->di, &sc->di); put_user_ex(regs->di, &sc->di);
err |= __put_user(regs->si, &sc->si); put_user_ex(regs->si, &sc->si);
err |= __put_user(regs->bp, &sc->bp); put_user_ex(regs->bp, &sc->bp);
err |= __put_user(regs->sp, &sc->sp); put_user_ex(regs->sp, &sc->sp);
err |= __put_user(regs->bx, &sc->bx); put_user_ex(regs->bx, &sc->bx);
err |= __put_user(regs->dx, &sc->dx); put_user_ex(regs->dx, &sc->dx);
err |= __put_user(regs->cx, &sc->cx); put_user_ex(regs->cx, &sc->cx);
err |= __put_user(regs->ax, &sc->ax); put_user_ex(regs->ax, &sc->ax);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
err |= __put_user(regs->r8, &sc->r8); put_user_ex(regs->r8, &sc->r8);
err |= __put_user(regs->r9, &sc->r9); put_user_ex(regs->r9, &sc->r9);
err |= __put_user(regs->r10, &sc->r10); put_user_ex(regs->r10, &sc->r10);
err |= __put_user(regs->r11, &sc->r11); put_user_ex(regs->r11, &sc->r11);
err |= __put_user(regs->r12, &sc->r12); put_user_ex(regs->r12, &sc->r12);
err |= __put_user(regs->r13, &sc->r13); put_user_ex(regs->r13, &sc->r13);
err |= __put_user(regs->r14, &sc->r14); put_user_ex(regs->r14, &sc->r14);
err |= __put_user(regs->r15, &sc->r15); put_user_ex(regs->r15, &sc->r15);
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */
err |= __put_user(current->thread.trap_no, &sc->trapno); put_user_ex(current->thread.trap_no, &sc->trapno);
err |= __put_user(current->thread.error_code, &sc->err); put_user_ex(current->thread.error_code, &sc->err);
err |= __put_user(regs->ip, &sc->ip); put_user_ex(regs->ip, &sc->ip);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs); put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
err |= __put_user(regs->flags, &sc->flags); put_user_ex(regs->flags, &sc->flags);
err |= __put_user(regs->sp, &sc->sp_at_signal); put_user_ex(regs->sp, &sc->sp_at_signal);
err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
#else /* !CONFIG_X86_32 */ #else /* !CONFIG_X86_32 */
err |= __put_user(regs->flags, &sc->flags); put_user_ex(regs->flags, &sc->flags);
err |= __put_user(regs->cs, &sc->cs); put_user_ex(regs->cs, &sc->cs);
err |= __put_user(0, &sc->gs); put_user_ex(0, &sc->gs);
err |= __put_user(0, &sc->fs); put_user_ex(0, &sc->fs);
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
err |= __put_user(fpstate, &sc->fpstate); put_user_ex(fpstate, &sc->fpstate);
/* non-iBCS2 extensions.. */ /* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask); put_user_ex(mask, &sc->oldmask);
err |= __put_user(current->thread.cr2, &sc->cr2); put_user_ex(current->thread.cr2, &sc->cr2);
} put_user_catch(err);
return err; return err;
} }
...@@ -336,43 +343,41 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -336,43 +343,41 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT; return -EFAULT;
err |= __put_user(sig, &frame->sig); put_user_try {
err |= __put_user(&frame->info, &frame->pinfo); put_user_ex(sig, &frame->sig);
err |= __put_user(&frame->uc, &frame->puc); put_user_ex(&frame->info, &frame->pinfo);
err |= copy_siginfo_to_user(&frame->info, info); put_user_ex(&frame->uc, &frame->puc);
if (err) err |= copy_siginfo_to_user(&frame->info, info);
return -EFAULT;
/* Create the ucontext. */
if (cpu_has_xsave)
err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
else
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
return -EFAULT;
/* Set up to return from userspace. */ /* Create the ucontext. */
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); if (cpu_has_xsave)
if (ka->sa.sa_flags & SA_RESTORER) put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
restorer = ka->sa.sa_restorer; else
err |= __put_user(restorer, &frame->pretcode); put_user_ex(0, &frame->uc.uc_flags);
put_user_ex(0, &frame->uc.uc_link);
put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
put_user_ex(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags);
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. */
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
put_user_ex(restorer, &frame->pretcode);
/* /*
* 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.
*/ */
err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode); put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
} put_user_catch(err);
if (err) if (err)
return -EFAULT; return -EFAULT;
...@@ -436,28 +441,30 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -436,28 +441,30 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return -EFAULT; return -EFAULT;
} }
/* Create the ucontext. */ put_user_try {
if (cpu_has_xsave) /* Create the ucontext. */
err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); if (cpu_has_xsave)
else put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_flags); else
err |= __put_user(0, &frame->uc.uc_link); put_user_ex(0, &frame->uc.uc_flags);
err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); put_user_ex(0, &frame->uc.uc_link);
err |= __put_user(sas_ss_flags(regs->sp), put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
&frame->uc.uc_stack.ss_flags); put_user_ex(sas_ss_flags(regs->sp),
err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); &frame->uc.uc_stack.ss_flags);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. If provided, use a stub
already in userspace. */ /* Set up to return from userspace. If provided, use a stub
/* x86-64 should always use SA_RESTORER. */ already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) { /* x86-64 should always use SA_RESTORER. */
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); if (ka->sa.sa_flags & SA_RESTORER) {
} else { put_user_ex(ka->sa.sa_restorer, &frame->pretcode);
/* could use a vstub here */ } else {
return -EFAULT; /* could use a vstub here */
} err |= -EFAULT;
}
} put_user_catch(err);
if (err) if (err)
return -EFAULT; return -EFAULT;
...@@ -509,31 +516,41 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, ...@@ -509,31 +516,41 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact) struct old_sigaction __user *oact)
{ {
struct k_sigaction new_ka, old_ka; struct k_sigaction new_ka, old_ka;
int ret; int ret = 0;
if (act) { if (act) {
old_sigset_t mask; old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) || if (!access_ok(VERIFY_READ, act, sizeof(*act)))
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
__get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
return -EFAULT; return -EFAULT;
__get_user(new_ka.sa.sa_flags, &act->sa_flags); get_user_try {
__get_user(mask, &act->sa_mask); get_user_ex(new_ka.sa.sa_handler, &act->sa_handler);
get_user_ex(new_ka.sa.sa_flags, &act->sa_flags);
get_user_ex(mask, &act->sa_mask);
get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer);
} get_user_catch(ret);
if (ret)
return -EFAULT;
siginitset(&new_ka.sa.sa_mask, mask); siginitset(&new_ka.sa.sa_mask, mask);
} }
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) { if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
__put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
return -EFAULT; return -EFAULT;
__put_user(old_ka.sa.sa_flags, &oact->sa_flags); put_user_try {
__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler);
put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags);
put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer);
} put_user_catch(ret);
if (ret)
return -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