/* * Do a signal return; undo the signal stack. */ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *pax) { void __user *buf; unsigned int tmpflags; unsigned int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; GET_SEG(gs); COPY_SEG(fs); COPY_SEG(es); COPY_SEG(ds); COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(dx); COPY(cx); COPY(ip); COPY_SEG_STRICT(cs); COPY_SEG_STRICT(ss); err |= __get_user(tmpflags, &sc->flags); regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); regs->orig_ax = -1; /* disable syscall checks */ err |= __get_user(buf, &sc->fpstate); err |= restore_i387_xstate(buf); err |= __get_user(*pax, &sc->ax); return err; }
int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned long buf_val; void __user *buf; unsigned int tmpflags; unsigned int err = 0; /* Always make any pending restarted system calls return -EINTR */ current->restart_block.fn = do_no_restart_syscall; get_user_try { #ifdef CONFIG_X86_32 set_user_gs(regs, 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(ax); #ifdef CONFIG_X86_64 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); #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); #endif /* CONFIG_X86_32 */ 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_val, &sc->fpstate); buf = (void __user *)buf_val; } get_user_catch(err); err |= fpu__restore_sig(buf, config_enabled(CONFIG_X86_32)); force_iret(); return err; }
int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *pax) { void __user *buf; unsigned int tmpflags; unsigned int err = 0; /* */ current_thread_info()->restart_block.fn = do_no_restart_syscall; get_user_try { #ifdef CONFIG_X86_32 set_user_gs(regs, GET_SEG(gs)); COPY_SEG(fs); COPY_SEG(es); COPY_SEG(ds); #endif /* */ 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); #endif /* */ #ifdef CONFIG_X86_32 COPY_SEG_CPL3(cs); COPY_SEG_CPL3(ss); #else /* */ /* */ COPY_SEG_CPL3(cs); #endif /* */ get_user_ex(tmpflags, &sc->flags); regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); regs->orig_ax = -1; /* */ get_user_ex(buf, &sc->fpstate); err |= restore_i387_xstate(buf); get_user_ex(*pax, &sc->ax); } get_user_catch(err); return err; }
/* * This sets regs->esp even though we don't actually use sigstacks yet.. */ asmlinkage int sys_sigreturn(unsigned long __unused) { #define COPY(x) regs->x = context.x #ifdef CONFIG_OSFMACH3 #define COPY_SEG(x) #define COPY_SEG_STRICT(x) #else /* CONFIG_OSFMACH3 */ #define COPY_SEG(x) \ if ( (context.x & 0xfffc) /* not a NULL selectors */ \ && (context.x & 0x4) != 0x4 /* not a LDT selector */ \ && (context.x & 3) != 3 /* not a RPL3 GDT selector */ \ ) goto badframe; COPY(x); #define COPY_SEG_STRICT(x) \ if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x); #endif /* CONFIG_OSFMACH3 */ struct sigcontext_struct context; struct pt_regs * regs; regs = (struct pt_regs *) &__unused; if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context))) goto badframe; memcpy_fromfs(&context,(void *) regs->esp, sizeof(context)); current->blocked = context.oldmask & _BLOCKABLE; COPY_SEG(ds); COPY_SEG(es); COPY_SEG(fs); COPY_SEG(gs); COPY_SEG_STRICT(ss); COPY_SEG_STRICT(cs); COPY(eip); COPY(ecx); COPY(edx); COPY(ebx); COPY(esp); COPY(ebp); COPY(edi); COPY(esi); regs->eflags &= ~0x40DD5; regs->eflags |= context.eflags & 0x40DD5; regs->orig_eax = -1; /* disable syscall checks */ if (context.fpstate) { struct _fpstate * buf = context.fpstate; if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; restore_i387(buf); } return context.eax; badframe: do_exit(SIGSEGV); }
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax) { unsigned int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; #define COPY(x) err |= __get_user(regs->x, &sc->x) #define COPY_SEG(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ regs->x##seg = tmp|3; } #define GET_SEG(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ loadsegment(seg,tmp); } #define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_RF | \ X86_EFLAGS_OF | X86_EFLAGS_DF | \ X86_EFLAGS_TF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \ X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF) GET_SEG(gs); COPY_SEG(fs); COPY_SEG(es); COPY_SEG(ds); COPY(edi); COPY(esi); COPY(ebp); COPY(esp); COPY(ebx); COPY(edx); COPY(ecx); COPY(eip); COPY_SEG_STRICT(cs); COPY_SEG_STRICT(ss); { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); regs->eflags = (regs->eflags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); regs->orig_eax = -1; /* disable syscall checks */ } { struct _fpstate __user * buf; err |= __get_user(buf, &sc->fpstate); if (buf) { if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387(buf); } else { struct task_struct *me = current; if (used_math()) { clear_fpu(me); clear_used_math(); } } } err |= __get_user(*peax, &sc->eax); return err; badframe: return 1; }