|
@@ -51,24 +51,24 @@
|
|
|
#endif
|
|
|
|
|
|
#define COPY(x) { \
|
|
|
- err |= __get_user(regs->x, &sc->x); \
|
|
|
+ get_user_ex(regs->x, &sc->x); \
|
|
|
}
|
|
|
|
|
|
#define COPY_SEG(seg) { \
|
|
|
unsigned short tmp; \
|
|
|
- err |= __get_user(tmp, &sc->seg); \
|
|
|
+ get_user_ex(tmp, &sc->seg); \
|
|
|
regs->seg = tmp; \
|
|
|
}
|
|
|
|
|
|
#define COPY_SEG_CPL3(seg) { \
|
|
|
unsigned short tmp; \
|
|
|
- err |= __get_user(tmp, &sc->seg); \
|
|
|
+ get_user_ex(tmp, &sc->seg); \
|
|
|
regs->seg = tmp | 3; \
|
|
|
}
|
|
|
|
|
|
#define GET_SEG(seg) { \
|
|
|
unsigned short tmp; \
|
|
|
- err |= __get_user(tmp, &sc->seg); \
|
|
|
+ get_user_ex(tmp, &sc->seg); \
|
|
|
loadsegment(seg, tmp); \
|
|
|
}
|
|
|
|
|
@@ -83,45 +83,49 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
|
|
/* Always make any pending restarted system calls return -EINTR */
|
|
|
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
|
|
|
|
|
+ get_user_try {
|
|
|
+
|
|
|
#ifdef CONFIG_X86_32
|
|
|
- GET_SEG(gs);
|
|
|
- COPY_SEG(fs);
|
|
|
- COPY_SEG(es);
|
|
|
- COPY_SEG(ds);
|
|
|
+ GET_SEG(gs);
|
|
|
+ COPY_SEG(fs);
|
|
|
+ COPY_SEG(es);
|
|
|
+ COPY_SEG(ds);
|
|
|
#endif /* CONFIG_X86_32 */
|
|
|
|
|
|
- COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
|
|
- COPY(dx); COPY(cx); COPY(ip);
|
|
|
+ COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
|
|
+ COPY(dx); COPY(cx); COPY(ip);
|
|
|
|
|
|
#ifdef CONFIG_X86_64
|
|
|
- COPY(r8);
|
|
|
- COPY(r9);
|
|
|
- COPY(r10);
|
|
|
- COPY(r11);
|
|
|
- COPY(r12);
|
|
|
- COPY(r13);
|
|
|
- COPY(r14);
|
|
|
- COPY(r15);
|
|
|
+ COPY(r8);
|
|
|
+ COPY(r9);
|
|
|
+ COPY(r10);
|
|
|
+ COPY(r11);
|
|
|
+ COPY(r12);
|
|
|
+ COPY(r13);
|
|
|
+ COPY(r14);
|
|
|
+ COPY(r15);
|
|
|
#endif /* CONFIG_X86_64 */
|
|
|
|
|
|
#ifdef CONFIG_X86_32
|
|
|
- COPY_SEG_CPL3(cs);
|
|
|
- COPY_SEG_CPL3(ss);
|
|
|
+ COPY_SEG_CPL3(cs);
|
|
|
+ COPY_SEG_CPL3(ss);
|
|
|
#else /* !CONFIG_X86_32 */
|
|
|
- /* Kernel saves and restores only the CS segment register on signals,
|
|
|
- * which is the bare minimum needed to allow mixed 32/64-bit code.
|
|
|
- * App's signal handler can save/restore other segments if needed. */
|
|
|
- COPY_SEG_CPL3(cs);
|
|
|
+ /* Kernel saves and restores only the CS segment register on signals,
|
|
|
+ * which is the bare minimum needed to allow mixed 32/64-bit code.
|
|
|
+ * App's signal handler can save/restore other segments if needed. */
|
|
|
+ COPY_SEG_CPL3(cs);
|
|
|
#endif /* CONFIG_X86_32 */
|
|
|
|
|
|
- err |= __get_user(tmpflags, &sc->flags);
|
|
|
- regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
|
|
- regs->orig_ax = -1; /* disable syscall checks */
|
|
|
+ get_user_ex(tmpflags, &sc->flags);
|
|
|
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
|
|
+ regs->orig_ax = -1; /* disable syscall checks */
|
|
|
+
|
|
|
+ get_user_ex(buf, &sc->fpstate);
|
|
|
+ err |= restore_i387_xstate(buf);
|
|
|
|
|
|
- err |= __get_user(buf, &sc->fpstate);
|
|
|
- err |= restore_i387_xstate(buf);
|
|
|
+ get_user_ex(*pax, &sc->ax);
|
|
|
+ } get_user_catch(err);
|
|
|
|
|
|
- err |= __get_user(*pax, &sc->ax);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -131,57 +135,60 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
|
|
|
{
|
|
|
int err = 0;
|
|
|
|
|
|
+ put_user_try {
|
|
|
+
|
|
|
#ifdef CONFIG_X86_32
|
|
|
- {
|
|
|
- unsigned int tmp;
|
|
|
+ {
|
|
|
+ unsigned int tmp;
|
|
|
|
|
|
- savesegment(gs, tmp);
|
|
|
- err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
|
|
|
- }
|
|
|
- err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs);
|
|
|
- err |= __put_user(regs->es, (unsigned int __user *)&sc->es);
|
|
|
- err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds);
|
|
|
+ savesegment(gs, tmp);
|
|
|
+ put_user_ex(tmp, (unsigned int __user *)&sc->gs);
|
|
|
+ }
|
|
|
+ put_user_ex(regs->fs, (unsigned int __user *)&sc->fs);
|
|
|
+ put_user_ex(regs->es, (unsigned int __user *)&sc->es);
|
|
|
+ put_user_ex(regs->ds, (unsigned int __user *)&sc->ds);
|
|
|
#endif /* CONFIG_X86_32 */
|
|
|
|
|
|
- err |= __put_user(regs->di, &sc->di);
|
|
|
- err |= __put_user(regs->si, &sc->si);
|
|
|
- err |= __put_user(regs->bp, &sc->bp);
|
|
|
- err |= __put_user(regs->sp, &sc->sp);
|
|
|
- err |= __put_user(regs->bx, &sc->bx);
|
|
|
- err |= __put_user(regs->dx, &sc->dx);
|
|
|
- err |= __put_user(regs->cx, &sc->cx);
|
|
|
- err |= __put_user(regs->ax, &sc->ax);
|
|
|
+ put_user_ex(regs->di, &sc->di);
|
|
|
+ put_user_ex(regs->si, &sc->si);
|
|
|
+ put_user_ex(regs->bp, &sc->bp);
|
|
|
+ put_user_ex(regs->sp, &sc->sp);
|
|
|
+ put_user_ex(regs->bx, &sc->bx);
|
|
|
+ put_user_ex(regs->dx, &sc->dx);
|
|
|
+ put_user_ex(regs->cx, &sc->cx);
|
|
|
+ put_user_ex(regs->ax, &sc->ax);
|
|
|
#ifdef CONFIG_X86_64
|
|
|
- err |= __put_user(regs->r8, &sc->r8);
|
|
|
- err |= __put_user(regs->r9, &sc->r9);
|
|
|
- err |= __put_user(regs->r10, &sc->r10);
|
|
|
- err |= __put_user(regs->r11, &sc->r11);
|
|
|
- err |= __put_user(regs->r12, &sc->r12);
|
|
|
- err |= __put_user(regs->r13, &sc->r13);
|
|
|
- err |= __put_user(regs->r14, &sc->r14);
|
|
|
- err |= __put_user(regs->r15, &sc->r15);
|
|
|
+ put_user_ex(regs->r8, &sc->r8);
|
|
|
+ put_user_ex(regs->r9, &sc->r9);
|
|
|
+ put_user_ex(regs->r10, &sc->r10);
|
|
|
+ put_user_ex(regs->r11, &sc->r11);
|
|
|
+ put_user_ex(regs->r12, &sc->r12);
|
|
|
+ put_user_ex(regs->r13, &sc->r13);
|
|
|
+ put_user_ex(regs->r14, &sc->r14);
|
|
|
+ put_user_ex(regs->r15, &sc->r15);
|
|
|
#endif /* CONFIG_X86_64 */
|
|
|
|
|
|
- err |= __put_user(current->thread.trap_no, &sc->trapno);
|
|
|
- err |= __put_user(current->thread.error_code, &sc->err);
|
|
|
- err |= __put_user(regs->ip, &sc->ip);
|
|
|
+ put_user_ex(current->thread.trap_no, &sc->trapno);
|
|
|
+ put_user_ex(current->thread.error_code, &sc->err);
|
|
|
+ put_user_ex(regs->ip, &sc->ip);
|
|
|
#ifdef CONFIG_X86_32
|
|
|
- err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
|
|
|
- err |= __put_user(regs->flags, &sc->flags);
|
|
|
- err |= __put_user(regs->sp, &sc->sp_at_signal);
|
|
|
- err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
|
|
|
+ put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
|
|
|
+ put_user_ex(regs->flags, &sc->flags);
|
|
|
+ put_user_ex(regs->sp, &sc->sp_at_signal);
|
|
|
+ put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
|
|
|
#else /* !CONFIG_X86_32 */
|
|
|
- err |= __put_user(regs->flags, &sc->flags);
|
|
|
- err |= __put_user(regs->cs, &sc->cs);
|
|
|
- err |= __put_user(0, &sc->gs);
|
|
|
- err |= __put_user(0, &sc->fs);
|
|
|
+ put_user_ex(regs->flags, &sc->flags);
|
|
|
+ put_user_ex(regs->cs, &sc->cs);
|
|
|
+ put_user_ex(0, &sc->gs);
|
|
|
+ put_user_ex(0, &sc->fs);
|
|
|
#endif /* CONFIG_X86_32 */
|
|
|
|
|
|
- err |= __put_user(fpstate, &sc->fpstate);
|
|
|
+ put_user_ex(fpstate, &sc->fpstate);
|
|
|
|
|
|
- /* non-iBCS2 extensions.. */
|
|
|
- err |= __put_user(mask, &sc->oldmask);
|
|
|
- err |= __put_user(current->thread.cr2, &sc->cr2);
|
|
|
+ /* non-iBCS2 extensions.. */
|
|
|
+ put_user_ex(mask, &sc->oldmask);
|
|
|
+ put_user_ex(current->thread.cr2, &sc->cr2);
|
|
|
+ } put_user_catch(err);
|
|
|
|
|
|
return err;
|
|
|
}
|
|
@@ -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)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- err |= __put_user(sig, &frame->sig);
|
|
|
- err |= __put_user(&frame->info, &frame->pinfo);
|
|
|
- err |= __put_user(&frame->uc, &frame->puc);
|
|
|
- err |= copy_siginfo_to_user(&frame->info, info);
|
|
|
- if (err)
|
|
|
- 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;
|
|
|
+ put_user_try {
|
|
|
+ put_user_ex(sig, &frame->sig);
|
|
|
+ put_user_ex(&frame->info, &frame->pinfo);
|
|
|
+ put_user_ex(&frame->uc, &frame->puc);
|
|
|
+ err |= copy_siginfo_to_user(&frame->info, info);
|
|
|
|
|
|
- /* 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;
|
|
|
- err |= __put_user(restorer, &frame->pretcode);
|
|
|
+ /* Create the ucontext. */
|
|
|
+ if (cpu_has_xsave)
|
|
|
+ put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
|
|
+ else
|
|
|
+ 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
|
|
|
- *
|
|
|
- * 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
|
|
|
- * signal handler stack frames.
|
|
|
- */
|
|
|
- err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
|
|
|
+ /*
|
|
|
+ * This is movl $__NR_rt_sigreturn, %ax ; int $0x80
|
|
|
+ *
|
|
|
+ * 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
|
|
|
+ * signal handler stack frames.
|
|
|
+ */
|
|
|
+ put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
|
|
|
+ } put_user_catch(err);
|
|
|
|
|
|
if (err)
|
|
|
return -EFAULT;
|
|
@@ -436,28 +441,30 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *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(me->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(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
|
|
- 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. */
|
|
|
- /* x86-64 should always use SA_RESTORER. */
|
|
|
- if (ka->sa.sa_flags & SA_RESTORER) {
|
|
|
- err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
|
|
|
- } else {
|
|
|
- /* could use a vstub here */
|
|
|
- return -EFAULT;
|
|
|
- }
|
|
|
+ put_user_try {
|
|
|
+ /* Create the ucontext. */
|
|
|
+ if (cpu_has_xsave)
|
|
|
+ put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
|
|
+ else
|
|
|
+ put_user_ex(0, &frame->uc.uc_flags);
|
|
|
+ put_user_ex(0, &frame->uc.uc_link);
|
|
|
+ put_user_ex(me->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(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
|
|
+ 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. */
|
|
|
+ /* x86-64 should always use SA_RESTORER. */
|
|
|
+ if (ka->sa.sa_flags & SA_RESTORER) {
|
|
|
+ put_user_ex(ka->sa.sa_restorer, &frame->pretcode);
|
|
|
+ } else {
|
|
|
+ /* could use a vstub here */
|
|
|
+ err |= -EFAULT;
|
|
|
+ }
|
|
|
+ } put_user_catch(err);
|
|
|
|
|
|
if (err)
|
|
|
return -EFAULT;
|
|
@@ -509,31 +516,41 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
|
|
|
struct old_sigaction __user *oact)
|
|
|
{
|
|
|
struct k_sigaction new_ka, old_ka;
|
|
|
- int ret;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (act) {
|
|
|
old_sigset_t mask;
|
|
|
|
|
|
- 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))
|
|
|
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
|
|
|
- __get_user(mask, &act->sa_mask);
|
|
|
+ get_user_try {
|
|
|
+ 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);
|
|
|
}
|
|
|
|
|
|
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
|
|
|
|
|
|
if (!ret && 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))
|
|
|
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
|
|
|
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
|
|
|
+ put_user_try {
|
|
|
+ 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;
|