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;
}
Exemple #3
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;
}