Exemplo n.º 1
0
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
		sigset_t *oldset, struct pt_regs *regs)
{
	int ret;

#ifdef DEBUG_SIG
	printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n",
		current->pid, sig,
		regs->rip, regs->rsp, regs);
#endif

	/* Are we from a system call? */
	if (current_syscall(regs) >= 0) {
		/* If so, check system call restarting.. */
		switch (current_syscall_ret(regs)) {
		        case -ERESTART_RESTARTBLOCK:
			case -ERESTARTNOHAND:
				regs->rax = -EINTR;
				break;

			case -ERESTARTSYS:
				if (!(ka->sa.sa_flags & SA_RESTART)) {
					regs->rax = -EINTR;
					break;
				}
				/* fallthrough */
			case -ERESTARTNOINTR:
				regs->rax = regs->orig_rax;
				regs->rip -= 2;
				break;
		}
	}

	/*
	 * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF flag so
	 * that register information in the sigcontext is correct.
	 */
	if (unlikely(regs->eflags & TF_MASK)
	    && likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
		regs->eflags &= ~TF_MASK;

#ifdef CONFIG_IA32_EMULATION
	if (test_thread_flag(TIF_IA32)) {
		if (ka->sa.sa_flags & SA_SIGINFO)
			ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs);
		else
			ret = ia32_setup_frame(sig, ka, oldset, regs);
	} else 
#endif
	ret = setup_rt_frame(sig, ka, info, oldset, regs);

	if (ret == 0) {
		spin_lock_irq(&current->sighand->siglock);
		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
		if (!(ka->sa.sa_flags & SA_NODEFER))
			sigaddset(&current->blocked,sig);
		recalc_sigpending();
		spin_unlock_irq(&current->sighand->siglock);

		/*
		 * Clear TF when entering the signal handler, but
		 * notify any tracer that was single-stepping it.
		 * The tracer may want to single-step inside the
		 * handler too.
		 */
		regs->eflags &= ~(TF_MASK | X86_EFLAGS_DF);
		tracehook_report_handle_signal(sig, ka, oldset, regs);
	}

	return ret;
}
Exemplo n.º 2
0
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 */
static void do_signal(struct pt_regs *regs)
{
	struct k_sigaction ka;
	siginfo_t info;
	int signr;
	sigset_t *oldset;

	/*
	 * We want the common case to go fast, which
	 * is why we may in certain cases get here from
	 * kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
		return;

	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;
	else
		oldset = &current->blocked;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
		/* Reenable any watchpoints before delivering the
		 * signal to user space. The processor register will
		 * have been cleared if the watchpoint triggered
		 * inside the kernel.
		 */
		if (current->thread.debugreg7)
			set_debugreg(current->thread.debugreg7, 7);

		/* Whee!  Actually deliver the signal.  */
		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
			/* a signal was successfully delivered; the saved
			 * sigmask will have been stored in the signal frame,
			 * and will be restored by sigreturn, so we can simply
			 * clear the TIF_RESTORE_SIGMASK flag */
			clear_thread_flag(TIF_RESTORE_SIGMASK);
		}
		return;
	}

	/* Did we come from a system call? */
	if (current_syscall(regs) >= 0) {
		/* Restart the system call - no handlers present */
		switch (current_syscall_ret(regs)) {
		case -ERESTARTNOHAND:
		case -ERESTARTSYS:
		case -ERESTARTNOINTR:
			regs->rax = regs->orig_rax;
			regs->rip -= 2;
			break;
		case -ERESTART_RESTARTBLOCK:
			regs->rax = test_thread_flag(TIF_IA32) ?
					__NR_ia32_restart_syscall :
					__NR_restart_syscall;
			regs->rip -= 2;
			break;
		}
	}

	/* if there's no signal to deliver, we just put the saved sigmask
	   back. */
	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
		clear_thread_flag(TIF_RESTORE_SIGMASK);
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
	}
}
Exemplo n.º 3
0
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
          sigset_t *oldset, struct pt_regs *regs)
{
    int ret;

    /* Are we from a system call? */
    if (current_syscall(regs) >= 0) {
        /* If so, check system call restarting.. */
        switch (current_syscall_ret(regs)) {
        case -ERESTART_RESTARTBLOCK:
        case -ERESTARTNOHAND:
            regs->ax = -EINTR;
            break;

        case -ERESTARTSYS:
            if (!(ka->sa.sa_flags & SA_RESTART)) {
                regs->ax = -EINTR;
                break;
            }
        /* fallthrough */
        case -ERESTARTNOINTR:
            regs->ax = regs->orig_ax;
            regs->ip -= 2;
            break;
        }
    }

    /*
     * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF
     * flag so that register information in the sigcontext is correct.
     */
    if (unlikely(regs->flags & X86_EFLAGS_TF) &&
        likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
        regs->flags &= ~X86_EFLAGS_TF;

#ifdef CONFIG_IA32_EMULATION
    if (test_thread_flag(TIF_IA32)) {
        if (ka->sa.sa_flags & SA_SIGINFO)
            ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs);
        else
            ret = ia32_setup_frame(sig, ka, oldset, regs);
    } else 
#endif
    ret = setup_rt_frame(sig, ka, info, oldset, regs);

    if (ret == 0) {
        /*
         * This has nothing to do with segment registers,
         * despite the name.  This magic affects uaccess.h
         * macros' behavior.  Reset it to the normal setting.
         */
        set_fs(USER_DS);

        /*
         * Clear the direction flag as per the ABI for function entry.
         */
        regs->flags &= ~X86_EFLAGS_DF;

        /*
         * Clear TF when entering the signal handler, but
         * notify any tracer that was single-stepping it.
         * The tracer may want to single-step inside the
         * handler too.
         */
        regs->flags &= ~X86_EFLAGS_TF;
        if (test_thread_flag(TIF_SINGLESTEP))
            ptrace_notify(SIGTRAP);

        spin_lock_irq(&current->sighand->siglock);
        sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
        if (!(ka->sa.sa_flags & SA_NODEFER))
            sigaddset(&current->blocked,sig);
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
    }

    return ret;
}