int
swapcontext(struct thread *td, struct swapcontext_args *uap)
{
	ucontext_t uc;
	int ret;	

	if (uap->oucp == NULL || uap->ucp == NULL)
		ret = EINVAL;
	else {
		get_mcontext(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
		PROC_LOCK(td->td_proc);
		uc.uc_sigmask = td->td_sigmask;
		PROC_UNLOCK(td->td_proc);
		ret = copyout(&uc, uap->oucp, UC_COPY_SIZE);
		if (ret == 0) {
			ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
			if (ret == 0) {
				ret = set_mcontext(td, &uc.uc_mcontext);
				if (ret == 0) {
					SIG_CANTMASK(uc.uc_sigmask);
					PROC_LOCK(td->td_proc);
					td->td_sigmask = uc.uc_sigmask;
					PROC_UNLOCK(td->td_proc);
				}
			}
		}
	}
	return (ret == 0 ? EJUSTRETURN : ret);
}
Пример #2
0
int
_sigsuspend(const sigset_t *set)
{
	struct pthread	*curthread = _get_curthread();
	sigset_t	oldmask, newmask, tempset;
	int             ret = -1;

	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
		return (__sys_sigsuspend(set));

	/* Check if a new signal set was provided by the caller: */
	if (set != NULL) {
		newmask = *set;
		SIG_CANTMASK(newmask);
		THR_LOCK_SWITCH(curthread);

		/* Save current sigmask: */
		oldmask = curthread->sigmask;
		curthread->oldsigmask = &oldmask;

		/* Change the caller's mask: */
		curthread->sigmask = newmask;
		tempset = curthread->sigpend;
		SIGSETNAND(tempset, newmask);
		if (SIGISEMPTY(tempset)) {
			THR_SET_STATE(curthread, PS_SIGSUSPEND);
			/* Wait for a signal: */
			_thr_sched_switch_unlocked(curthread);
		} else {
			curthread->check_pending = 1;
			THR_UNLOCK_SWITCH(curthread);
			/* check pending signal I can handle: */
			_thr_sig_check_pending(curthread);
		}
		if ((curthread->cancelflags & THR_CANCELLING) != 0)
			curthread->oldsigmask = NULL;
		else {
			THR_ASSERT(curthread->oldsigmask == NULL,
		 	          "oldsigmask is not cleared");
		}

		/* Always return an interrupted error: */
		errno = EINTR;
	} else {
		/* Return an invalid argument error: */
		errno = EINVAL;
	}

	/* Return the completion status: */
	return (ret);
}
Пример #3
0
/*
 * MPSAFE
 */
int
sys_osigsetmask(struct osigsetmask_args *uap)
{
	struct lwp *lp = curthread->td_lwp;
	sigset_t set;

	OSIG2SIG(uap->mask, set);
	SIG_CANTMASK(set);
	crit_enter();
	SIG2OSIG(lp->lwp_sigmask, uap->sysmsg_iresult);
	SIGSETLO(lp->lwp_sigmask, set);
	crit_exit();
	return (0);
}
Пример #4
0
/*
 * Copied from amd64/amd64/machdep.c
 *
 * XXX fpu state need? don't think so
 */
int
linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
{
	struct proc *p;
	struct l_ucontext uc;
	struct l_sigcontext *context;
	struct trapframe *regs;
	unsigned long rflags;
	int error;
	ksiginfo_t ksi;

	regs = td->td_frame;
	error = copyin((void *)regs->tf_rbx, &uc, sizeof(uc));
	if (error != 0)
		return (error);

	p = td->td_proc;
	context = &uc.uc_mcontext;
	rflags = context->sc_rflags;

	/*
	 * Don't allow users to change privileged or reserved flags.
	 */
	/*
	 * XXX do allow users to change the privileged flag PSL_RF.
	 * The cpu sets PSL_RF in tf_rflags for faults.  Debuggers
	 * should sometimes set it there too.  tf_rflags is kept in
	 * the signal context during signal handling and there is no
	 * other place to remember it, so the PSL_RF bit may be
	 * corrupted by the signal handler without us knowing.
	 * Corruption of the PSL_RF bit at worst causes one more or
	 * one less debugger trap, so allowing it is fairly harmless.
	 */

#define RFLAG_SECURE(ef, oef)     ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
	if (!RFLAG_SECURE(rflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) {
		printf("linux_rt_sigreturn: rflags = 0x%lx\n", rflags);
		return (EINVAL);
	}

	/*
	 * Don't allow users to load a valid privileged %cs.  Let the
	 * hardware check for invalid selectors, excess privilege in
	 * other selectors, invalid %eip's and invalid %esp's.
	 */
#define CS_SECURE(cs)           (ISPL(cs) == SEL_UPL)
	if (!CS_SECURE(context->sc_cs)) {
		printf("linux_rt_sigreturn: cs = 0x%x\n", context->sc_cs);
		ksiginfo_init_trap(&ksi);
		ksi.ksi_signo = SIGBUS;
		ksi.ksi_code = BUS_OBJERR;
		ksi.ksi_trapno = T_PROTFLT;
		ksi.ksi_addr = (void *)regs->tf_rip;
		trapsignal(td, &ksi);
		return (EINVAL);
	}

	PROC_LOCK(p);
	linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask);
	SIG_CANTMASK(td->td_sigmask);
	signotify(td);
	PROC_UNLOCK(p);

	regs->tf_rdi    = context->sc_rdi;
	regs->tf_rsi    = context->sc_rsi;
	regs->tf_rdx    = context->sc_rdx;
	regs->tf_rbp    = context->sc_rbp;
	regs->tf_rbx    = context->sc_rbx;
	regs->tf_rcx    = context->sc_rcx;
	regs->tf_rax    = context->sc_rax;
	regs->tf_rip    = context->sc_rip;
	regs->tf_rsp    = context->sc_rsp;
	regs->tf_r8     = context->sc_r8;
	regs->tf_r9     = context->sc_r9;
	regs->tf_r10    = context->sc_r10;
	regs->tf_r11    = context->sc_r11;
	regs->tf_r12    = context->sc_r12;
	regs->tf_r13    = context->sc_r13;
	regs->tf_r14    = context->sc_r14;
	regs->tf_r15    = context->sc_r15;
	regs->tf_cs     = context->sc_cs;
	regs->tf_err    = context->sc_err;
	regs->tf_rflags = rflags;

	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
	return (EJUSTRETURN);
}
Пример #5
0
int
sys_sigreturn(struct sigreturn_args *uap)
{
    struct lwp *lp = curthread->td_lwp;
    struct trapframe *regs;
    ucontext_t ucp;
    int cs;
    int eflags;
    int error;

    error = copyin(uap->sigcntxp, &ucp, sizeof(ucp));
    if (error)
        return (error);

    regs = lp->lwp_md.md_regs;
    eflags = ucp.uc_mcontext.mc_eflags;

#if 0
    if (eflags & PSL_VM) {
        struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
        struct vm86_kernel *vm86;

        /*
         * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
         * set up the vm86 area, and we can't enter vm86 mode.
         */
        if (lp->lwp_thread->td_pcb->pcb_ext == 0)
            return (EINVAL);
        vm86 = &lp->lwp_thread->td_pcb->pcb_ext->ext_vm86;
        if (vm86->vm86_inited == 0)
            return (EINVAL);

        /* go back to user mode if both flags are set */
        if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
            trapsignal(lp->lwp_proc, SIGBUS, 0);

        if (vm86->vm86_has_vme) {
            eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
                     (eflags & VME_USERCHANGE) | PSL_VM;
        } else {
            vm86->vm86_eflags = eflags;	/* save VIF, VIP */
            eflags = (tf->tf_eflags & ~VM_USERCHANGE) |					    (eflags & VM_USERCHANGE) | PSL_VM;
        }
        bcopy(&ucp.uc_mcontext.mc_gs, tf, sizeof(struct trapframe));
        tf->tf_eflags = eflags;
        tf->tf_vm86_ds = tf->tf_ds;
        tf->tf_vm86_es = tf->tf_es;
        tf->tf_vm86_fs = tf->tf_fs;
        tf->tf_vm86_gs = tf->tf_gs;
        tf->tf_ds = _udatasel;
        tf->tf_es = _udatasel;
#if 0
        tf->tf_fs = _udatasel;
        tf->tf_gs = _udatasel;
#endif
    } else
#endif
    {
        /*
         * Don't allow users to change privileged or reserved flags.
         */
        /*
         * XXX do allow users to change the privileged flag PSL_RF.
         * The cpu sets PSL_RF in tf_eflags for faults.  Debuggers
         * should sometimes set it there too.  tf_eflags is kept in
         * the signal context during signal handling and there is no
         * other place to remember it, so the PSL_RF bit may be
         * corrupted by the signal handler without us knowing.
         * Corruption of the PSL_RF bit at worst causes one more or
         * one less debugger trap, so allowing it is fairly harmless.
         */
        if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
            kprintf("sigreturn: eflags = 0x%x\n", eflags);
            return(EINVAL);
        }

        /*
         * Don't allow users to load a valid privileged %cs.  Let the
         * hardware check for invalid selectors, excess privilege in
         * other selectors, invalid %eip's and invalid %esp's.
         */
        cs = ucp.uc_mcontext.mc_cs;
        if (!CS_SECURE(cs)) {
            kprintf("sigreturn: cs = 0x%x\n", cs);
            trapsignal(lp, SIGBUS, T_PROTFLT);
            return(EINVAL);
        }
        bcopy(&ucp.uc_mcontext.mc_gs, regs, sizeof(struct trapframe));
    }

    /*
     * Restore the FPU state from the frame
     */
    crit_enter();
    npxpop(&ucp.uc_mcontext);

    if (ucp.uc_mcontext.mc_onstack & 1)
        lp->lwp_sigstk.ss_flags |= SS_ONSTACK;
    else
        lp->lwp_sigstk.ss_flags &= ~SS_ONSTACK;

    lp->lwp_sigmask = ucp.uc_sigmask;
    SIG_CANTMASK(lp->lwp_sigmask);
    crit_exit();
    return(EJUSTRETURN);
}