示例#1
0
kern_return_t
catch_mach_exception_raise(
        __unused mach_port_t exception_port,
        mach_port_t thread,
        mach_port_t task,
        exception_type_t exception,
        mach_exception_data_t code,
        __unused mach_msg_type_number_t codeCnt
)
{
	task_t			self = current_task();
	thread_t		th_act;
	ipc_port_t 		thread_port;
	struct proc		*p;
	kern_return_t		result = MACH_MSG_SUCCESS;
	int			ux_signal = 0;
	mach_exception_code_t 	ucode = 0;
	struct uthread 		*ut;
	mach_port_name_t thread_name = CAST_MACH_PORT_TO_NAME(thread);
	mach_port_name_t task_name = CAST_MACH_PORT_TO_NAME(task);

	/*
	 *	Convert local thread name to global port.
	 */
   if (MACH_PORT_VALID(thread_name) &&
       (ipc_object_copyin(get_task_ipcspace(self), thread_name,
		       MACH_MSG_TYPE_PORT_SEND,
		       (void *) &thread_port) == MACH_MSG_SUCCESS)) {
        if (IPC_PORT_VALID(thread_port)) {
	   th_act = convert_port_to_thread(thread_port);
	   ipc_port_release(thread_port);
	} else {
	   th_act = THREAD_NULL;
	}

	/*
	 *	Catch bogus ports
	 */
	if (th_act != THREAD_NULL) {

	    /*
	     *	Convert exception to unix signal and code.
	     */
	    ux_exception(exception, code[0], code[1], &ux_signal, &ucode);

	    ut = get_bsdthread_info(th_act);
	    p = proc_findthread(th_act);

	    /* Can't deliver a signal without a bsd process reference */
	    if (p == NULL) {
		    ux_signal = 0;
		    result = KERN_FAILURE;
	    }

	    /*
	     * Stack overflow should result in a SIGSEGV signal
	     * on the alternate stack.
	     * but we have one or more guard pages after the
	     * stack top, so we would get a KERN_PROTECTION_FAILURE
	     * exception instead of KERN_INVALID_ADDRESS, resulting in
	     * a SIGBUS signal.
	     * Detect that situation and select the correct signal.
	     */
	    if (code[0] == KERN_PROTECTION_FAILURE &&
		ux_signal == SIGBUS) {
		    user_addr_t		sp, stack_min, stack_max;
		    int			mask;
		    struct sigacts	*ps;

		    sp = code[1];

		    stack_max = p->user_stack;
		    stack_min = p->user_stack - MAXSSIZ;
		    if (sp >= stack_min &&
			sp < stack_max) {
			    /*
			     * This is indeed a stack overflow.  Deliver a
			     * SIGSEGV signal.
			     */
			    ux_signal = SIGSEGV;

			    /*
			     * If the thread/process is not ready to handle
			     * SIGSEGV on an alternate stack, force-deliver
			     * SIGSEGV with a SIG_DFL handler.
			     */
			    mask = sigmask(ux_signal);
			    ps = p->p_sigacts;
			    if ((p->p_sigignore & mask) ||
				(ut->uu_sigwait & mask) ||
				(ut->uu_sigmask & mask) ||
				(ps->ps_sigact[SIGSEGV] == SIG_IGN) ||
				(! (ps->ps_sigonstack & mask))) {
				    p->p_sigignore &= ~mask;
				    p->p_sigcatch &= ~mask;
				    ps->ps_sigact[SIGSEGV] = SIG_DFL;
				    ut->uu_sigwait &= ~mask;
				    ut->uu_sigmask &= ~mask;
			    }
		    }
	    }
	    /*
	     *	Send signal.
	     */
	    if (ux_signal != 0) {
			ut->uu_exception = exception;
			//ut->uu_code = code[0]; // filled in by threadsignal
			ut->uu_subcode = code[1];			
			threadsignal(th_act, ux_signal, code[0]);
	    }
	    if (p != NULL) 
		    proc_rele(p);
	    thread_deallocate(th_act);
	}
	else
	    result = KERN_INVALID_ARGUMENT;
    }
    else
    	result = KERN_INVALID_ARGUMENT;

    /*
     *	Delete our send rights to the task port.
     */
    (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self), task_name);

    return (result);
}
示例#2
0
int
cs_invalid_page(
	addr64_t vaddr)
{
	struct proc	*p;
	int		send_kill = 0, retval = 0, verbose = cs_debug;
	uint32_t	csflags;

	p = current_proc();

	if (verbose)
		printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
		    vaddr, p->p_pid, p->p_comm);

	proc_lock(p);

	/* XXX for testing */
	if (cs_force_kill)
		p->p_csflags |= CS_KILL;
	if (cs_force_hard)
		p->p_csflags |= CS_HARD;

	/* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
	if (p->p_csflags & CS_KILL) {
		if (panic_on_cs_killed &&
		    vaddr >= SHARED_REGION_BASE &&
		    vaddr < SHARED_REGION_BASE + SHARED_REGION_SIZE) {
			panic("<rdar://14393620> cs_invalid_page(va=0x%llx): killing p=%p\n", (uint64_t) vaddr, p);
		}
		p->p_csflags |= CS_KILLED;
		cs_procs_killed++;
		send_kill = 1;
		retval = 1;
	}
	
#if __x86_64__
	if (panic_on_cs_killed &&
	    vaddr >= SHARED_REGION_BASE &&
	    vaddr < SHARED_REGION_BASE + SHARED_REGION_SIZE) {
		panic("<rdar://14393620> cs_invalid_page(va=0x%llx): cs error p=%p\n", (uint64_t) vaddr, p);
	}
#endif /* __x86_64__ */

	/* CS_HARD means fail the mapping operation so the process stays valid. */
	if (p->p_csflags & CS_HARD) {
		retval = 1;
	} else {
		if (p->p_csflags & CS_VALID) {
			p->p_csflags &= ~CS_VALID;
			cs_procs_invalidated++;
			verbose = 1;
		}
	}
	csflags = p->p_csflags;
	proc_unlock(p);

	if (verbose)
		printf("CODE SIGNING: cs_invalid_page(0x%llx): "
		       "p=%d[%s] final status 0x%x, %s page%s\n",
		       vaddr, p->p_pid, p->p_comm, p->p_csflags,
		       retval ? "denying" : "allowing (remove VALID)",
		       send_kill ? " sending SIGKILL" : "");

	if (send_kill)
		threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS);


	return retval;
}
示例#3
0
文件: kern_cs.c 项目: onlynone/xnu
int
cs_invalid_page(addr64_t vaddr, boolean_t *cs_killed)
{
	struct proc	*p;
	int		send_kill = 0, retval = 0, verbose = cs_debug;
	uint32_t	csflags;

	p = current_proc();

	if (verbose)
		printf("CODE SIGNING: cs_invalid_page(0x%llx): p=%d[%s]\n",
		    vaddr, p->p_pid, p->p_comm);

	proc_lock(p);

	/* XXX for testing */
	if (cs_force_kill)
		p->p_csflags |= CS_KILL;
	if (cs_force_hard)
		p->p_csflags |= CS_HARD;

	/* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
	if (p->p_csflags & CS_KILL) {
		p->p_csflags |= CS_KILLED;
		cs_procs_killed++;
		send_kill = 1;
		retval = 1;
	}
	
	/* CS_HARD means fail the mapping operation so the process stays valid. */
	if (p->p_csflags & CS_HARD) {
		retval = 1;
	} else {
		if (p->p_csflags & CS_VALID) {
			p->p_csflags &= ~CS_VALID;
			cs_procs_invalidated++;
			verbose = 1;
		}
	}
	csflags = p->p_csflags;
	proc_unlock(p);

	if (verbose)
		printf("CODE SIGNING: cs_invalid_page(0x%llx): "
		       "p=%d[%s] final status 0x%x, %s page%s\n",
		       vaddr, p->p_pid, p->p_comm, p->p_csflags,
		       retval ? "denying" : "allowing (remove VALID)",
		       send_kill ? " sending SIGKILL" : "");

	if (send_kill) {
		/* We will set the exit reason for the thread later */
		threadsignal(current_thread(), SIGKILL, EXC_BAD_ACCESS, FALSE);
		if (cs_killed) {
			*cs_killed = TRUE;
		}
	} else if (cs_killed) {
		*cs_killed = FALSE;
	}


	return retval;
}