static int check_sigcontext32(struct lwp *l, const struct netbsd32_sigcontext *scp) { struct trapframe *tf; struct pcb *pcb; tf = l->l_md.md_regs; pcb = lwp_getpcb(curlwp); if (((scp->sc_eflags ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 || !VALID_USER_CSEL32(scp->sc_cs)) return EINVAL; if (scp->sc_fs != 0 && !VALID_USER_DSEL32(scp->sc_fs) && !(VALID_USER_FSEL32(scp->sc_fs) && pcb->pcb_fs != 0)) return EINVAL; if (scp->sc_gs != 0 && !VALID_USER_DSEL32(scp->sc_gs) && !(VALID_USER_GSEL32(scp->sc_gs) && pcb->pcb_gs != 0)) return EINVAL; if (scp->sc_es != 0 && !VALID_USER_DSEL32(scp->sc_es)) return EINVAL; if (!VALID_USER_DSEL32(scp->sc_ds) || !VALID_USER_DSEL32(scp->sc_ss)) return EINVAL; if (scp->sc_eip >= VM_MAXUSER_ADDRESS32) return EINVAL; return 0; }
int cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mcp) { const __greg32_t *gr; struct trapframe *tf; struct pcb *pcb; gr = mcp->__gregs; tf = l->l_md.md_regs; pcb = lwp_getpcb(l); if (((gr[_REG32_EFL] ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 || !VALID_USER_CSEL32(gr[_REG32_CS])) return EINVAL; if (gr[_REG32_FS] != 0 && !VALID_USER_DSEL32(gr[_REG32_FS]) && !(VALID_USER_FSEL32(gr[_REG32_FS]) && pcb->pcb_fs != 0)) return EINVAL; if (gr[_REG32_GS] != 0 && !VALID_USER_DSEL32(gr[_REG32_GS]) && !(VALID_USER_GSEL32(gr[_REG32_GS]) && pcb->pcb_gs != 0)) return EINVAL; if (gr[_REG32_ES] != 0 && !VALID_USER_DSEL32(gr[_REG32_ES])) return EINVAL; if (!VALID_USER_DSEL32(gr[_REG32_DS]) || !VALID_USER_DSEL32(gr[_REG32_SS])) return EINVAL; if (gr[_REG32_EIP] >= VM_MAXUSER_ADDRESS32) return EINVAL; return 0; }
static int linux32_restore_sigcontext(struct lwp *l, struct linux32_sigcontext *scp, register_t *retval) { struct trapframe *tf; struct proc *p = l->l_proc; struct sigaltstack *sas = &l->l_sigstk; struct pcb *pcb; sigset_t mask; ssize_t ss_gap; register_t fssel, gssel; /* Restore register context. */ tf = l->l_md.md_regs; pcb = lwp_getpcb(l); DPRINTF(("sigreturn enter rsp=0x%lx rip=0x%lx\n", tf->tf_rsp, tf->tf_rip)); /* * Check for security violations. */ if (((scp->sc_eflags ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 || !USERMODE(scp->sc_cs, scp->sc_eflags)) return EINVAL; if (scp->sc_fs != 0 && !VALID_USER_DSEL32(scp->sc_fs) && !(VALID_USER_FSEL32(scp->sc_fs) && pcb->pcb_fs != 0)) return EINVAL; if (scp->sc_gs != 0 && !VALID_USER_DSEL32(scp->sc_gs) && !(VALID_USER_GSEL32(scp->sc_gs) && pcb->pcb_gs != 0)) return EINVAL; if (scp->sc_es != 0 && !VALID_USER_DSEL32(scp->sc_es)) return EINVAL; if (!VALID_USER_DSEL32(scp->sc_ds) || !VALID_USER_DSEL32(scp->sc_ss)) return EINVAL; if (scp->sc_eip >= VM_MAXUSER_ADDRESS32) return EINVAL; gssel = (register_t)scp->sc_gs & 0xffff; fssel = (register_t)scp->sc_fs & 0xffff; cpu_fsgs_reload(l, fssel, gssel); tf->tf_es = (register_t)scp->sc_es & 0xffff; tf->tf_ds = (register_t)scp->sc_ds & 0xffff; tf->tf_rflags &= ~PSL_USER; tf->tf_rflags |= ((register_t)scp->sc_eflags & PSL_USER); tf->tf_rdi = (register_t)scp->sc_edi & 0xffffffff; tf->tf_rsi = (register_t)scp->sc_esi & 0xffffffff; tf->tf_rbp = (register_t)scp->sc_ebp & 0xffffffff; tf->tf_rbx = (register_t)scp->sc_ebx & 0xffffffff; tf->tf_rdx = (register_t)scp->sc_edx & 0xffffffff; tf->tf_rcx = (register_t)scp->sc_ecx & 0xffffffff; tf->tf_rax = (register_t)scp->sc_eax & 0xffffffff; tf->tf_rip = (register_t)scp->sc_eip & 0xffffffff; tf->tf_cs = (register_t)scp->sc_cs & 0xffff; tf->tf_rsp = (register_t)scp->sc_esp_at_signal & 0xffffffff; tf->tf_ss = (register_t)scp->sc_ss & 0xffff; mutex_enter(p->p_lock); /* Restore signal stack. */ ss_gap = (ssize_t) ((char *)NETBSD32IPTR64(scp->sc_esp_at_signal) - (char *)sas->ss_sp); if (ss_gap >= 0 && ss_gap < sas->ss_size) sas->ss_flags |= SS_ONSTACK; else sas->ss_flags &= ~SS_ONSTACK; /* Restore signal mask. */ linux32_old_to_native_sigset(&mask, &scp->sc_mask); (void) sigprocmask1(l, SIG_SETMASK, &mask, 0); mutex_exit(p->p_lock); DPRINTF(("linux32_sigreturn: rip = 0x%lx, rsp = 0x%lx, flags = 0x%lx\n", tf->tf_rip, tf->tf_rsp, tf->tf_rflags)); return EJUSTRETURN; }