RuntimeProtector::RuntimeProtector()
    : m_pImpl( new Impl( this ) )
    , m_bHashadException( false )
{
    if( !Impl::ms_bMachPortSet )
    {
        // prevent OS X debugger from catching signals in a none re-catchable way
        task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
        task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_INSTRUCTION, MACH_PORT_NULL, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
    }
}
void RegisterExceptionHandler(void) {
  mach_port_t task = mach_task_self();
  mach_port_t handler_port;
  kern_return_t rc;
  pthread_t tid;
  int err;

  /* Use the same mask as Breakpad. */
  exception_mask_t exception_mask =
    EXC_MASK_BAD_ACCESS |
    EXC_MASK_BAD_INSTRUCTION |
    EXC_MASK_ARITHMETIC |
    EXC_MASK_BREAKPOINT;

  rc = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &handler_port);
  CHECK(rc == KERN_SUCCESS);

  rc = mach_port_insert_right(task, handler_port, handler_port,
                              MACH_MSG_TYPE_MAKE_SEND);
  CHECK(rc == KERN_SUCCESS);

  err = pthread_create(&tid, NULL, ExceptionHandlerThread,
                       (void *) (uintptr_t) handler_port);
  CHECK(err == 0);
  err = pthread_detach(tid);
  CHECK(err == 0);

  rc = task_set_exception_ports(mach_task_self(), exception_mask,
                                handler_port, EXCEPTION_DEFAULT,
                                THREAD_STATE_NONE);
  CHECK(rc == KERN_SUCCESS);
}
Beispiel #3
0
EXPORT
int start(mach_port_t task, pid_t infoPid) {
    kern_return_t kret;
    pthread_t tid[2];
    interface* face = find_interface(task);

    kret = mach_port_allocate(current_task(), MACH_PORT_RIGHT_RECEIVE, &face->server_port);
    RETURN_ON_MACH_ERROR("[-start] mach_port_allocate failed", kret);

    kret = mach_port_insert_right(current_task(), face->server_port, face->server_port, MACH_MSG_TYPE_MAKE_SEND);
    RETURN_ON_MACH_ERROR("[-start] mach_port_insert_right failed", kret);

    kret = task_set_exception_ports(task, EXC_MASK_ALL, face->server_port, EXCEPTION_DEFAULT|MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
    RETURN_ON_MACH_ERROR("[-start] task_set_exception_ports failed", kret);

    int err = pthread_create(&tid[0], NULL, (void *(*)(void*))kqueue_loop, (void *)(unsigned long long)infoPid);
    if (err != 0)
        DEBUG_PRINT("\n[-start] can't create thread :[%s]", strerror(err));
    else
        DEBUG_PRINT("\n[-start] Thread created successfully %d\n", 0);

    err = pthread_create(&tid[1], NULL, (void *(*)(void*))exception_server, (void *(*)(void*))(unsigned long long)face->server_port);
    if (err != 0)
        DEBUG_PRINT("\n[-start] can't create thread :[%s]", strerror(err));
    else
        DEBUG_PRINT("\n[-start] Thread created successfully %d\n", 0);

    return 1;
}
/** Restore the original mach exception ports.
 */
void ksmachexc_i_restoreExceptionPorts(void)
{
    KSLOG_DEBUG("Restoring original exception ports.");
    if(g_previousExceptionPorts.count == 0)
    {
        KSLOG_DEBUG("Original exception ports were already restored.");
        return;
    }

    const task_t thisTask = mach_task_self();
    kern_return_t kr;

    // Reinstall old exception ports.
    for(mach_msg_type_number_t i = 0; i < g_previousExceptionPorts.count; i++)
    {
        KSLOG_TRACE("Restoring port index %d", i);
        kr = task_set_exception_ports(thisTask,
                                      g_previousExceptionPorts.masks[i],
                                      g_previousExceptionPorts.ports[i],
                                      g_previousExceptionPorts.behaviors[i],
                                      g_previousExceptionPorts.flavors[i]);
        if(kr != KERN_SUCCESS)
        {
            KSLOG_ERROR("task_set_exception_ports: %s",
                        mach_error_string(kr));
        }
    }
    KSLOG_DEBUG("Exception ports restored.");
    g_previousExceptionPorts.count = 0;
}
Beispiel #5
0
int vm_init(void)
{
#ifdef HAVE_MMAP_VM
#ifndef zero_fd
	zero_fd = open("/dev/zero", O_RDWR);
	if (zero_fd < 0)
		return -1;
#endif
#endif

// On 10.4 and earlier, reset CrashReporter's task signal handler to
// avoid having it show up for signals that get handled.
#if defined(__APPLE__) && defined(__MACH__)
	struct utsname info;

	if (!uname(&info) && atoi(info.release) <= 8) {
		task_set_exception_ports(mach_task_self(),
			EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC,
			MACH_PORT_NULL,
			EXCEPTION_STATE_IDENTITY,
			MACHINE_THREAD_STATE);
	}
#endif

	return 0;
}
void next_restore_exception_ports
(task_t task, struct next_exception_info *info)
{
  int i;
  kern_return_t kret;

  for (i = 0; i < info->count; i++) {
    kret = task_set_exception_ports
      (task, info->masks[i], info->ports[i], info->behaviors[i], info->flavors[i]);
    MACH_CHECK_ERROR (kret);
  }
}
void setMachExceptionPort(mach_port_t exceptionPort)
{
    // Assert that we dont try to call setMachExceptionPort more than once per process.
#if !ASSERT_DISABLED
    static mach_port_t taskExceptionPort = MACH_PORT_NULL;
    ASSERT(taskExceptionPort == MACH_PORT_NULL);
    taskExceptionPort = exceptionPort;
#endif

    if (task_set_exception_ports(mach_task_self(), EXC_MASK_CRASH, exceptionPort, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, MACHINE_THREAD_STATE) != KERN_SUCCESS)
        ASSERT_NOT_REACHED();
}
static void EnableMachExceptionHandler(
    MachExceptionHandlerData *saved_handlers) {
  for (size_t index = 0; index < saved_handlers->count; ++index) {
    if (saved_handlers->ports[index] != MACH_PORT_NULL) {
      kern_return_t kr = task_set_exception_ports(
          mach_task_self(),
          saved_handlers->masks[index],
          saved_handlers->ports[index],
          saved_handlers->behaviors[index],
          saved_handlers->flavors[index]);
      CHECK(kr == KERN_SUCCESS);
    }
  }
}
Beispiel #9
0
void
osfmach3_trap_syscall_self(
	boolean_t		catch_them,
	exception_behavior_t	behavior,
	thread_state_flavor_t	flavor)
{
	kern_return_t		kr;
	exception_mask_t	mask;
	mach_port_t		syscall_port;
	exception_behavior_t	syscall_behavior;
	thread_state_flavor_t	syscall_flavor;

	if (current != &init_task)
		panic("osfmach3_trap_syscall_self: "
		      "current=0x%p is not init_task\n",
		      current);

	if (! parent_server)
		return;
	
	/*
	 * Change the way the server syscalls are handled.
	 */
	if (catch_them) {
		/* catch our own syscalls */
		syscall_port = current->osfmach3.thread->mach_trap_port;
		syscall_behavior = behavior;
		syscall_flavor = flavor;
	} else {
		/* let our syscalls go to the parent server */
		syscall_port = parent_server_syscall_port;
		syscall_behavior = parent_server_syscall_behavior;
		syscall_flavor = parent_server_syscall_flavor;
	}
	mask = parent_server_syscall_exc_mask();

	kr = task_set_exception_ports(current->osfmach3.task->mach_task_port,
				      mask,
				      syscall_port,
				      syscall_behavior,
				      syscall_flavor);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_trap_syscall_self(catch_them=%d): "
			     "thread_set_exception_ports",
			     catch_them));
		panic("osfmach3_trap_syscall_self: can't set exception port");
	}

}
Beispiel #10
0
static bool xnu_restore_exception_ports (int pid) {
	kern_return_t kr;
	int i;
	task_t task = pid_to_task (pid);
	for (i = 0; i < ex.count; i++) {
		kr = task_set_exception_ports (task, ex.masks[i], ex.ports[i],
					       ex.behaviors[i], ex.flavors[i]);
		if (kr != KERN_SUCCESS) {
			eprintf ("fail to restore exception ports\n");
			return false;
		}
	}
	return true;
}
Beispiel #11
0
void mach_exn_init() {
    kern_return_t r;
    mach_port_t me;
    pthread_t thread;
    pthread_attr_t attr;
    exception_mask_t mask;
    
    me = mach_task_self();
    r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&exception_port);
    if(r != MACH_MSG_SUCCESS) DIE("mach_port_allocate");
    
    r = mach_port_insert_right(me,exception_port,exception_port,
    	MACH_MSG_TYPE_MAKE_SEND);
    if(r != MACH_MSG_SUCCESS) DIE("mach_port_insert_right");
    
    /* for others see mach/exception_types.h */
    mask = EXC_MASK_BAD_ACCESS;
    
    /* get the old exception ports */
    r = task_get_exception_ports(
        me,
        mask,
        old_exc_ports.masks,
        &old_exc_ports.count,
        old_exc_ports.ports,
        old_exc_ports.behaviors,
        old_exc_ports.flavors
    );
    if(r != MACH_MSG_SUCCESS) DIE("task_get_exception_ports");
    
    /* set the new exception ports */
    r = task_set_exception_ports(
        me,
        mask,
        exception_port,
        EXCEPTION_DEFAULT,
        MACHINE_THREAD_STATE
    );
    if(r != MACH_MSG_SUCCESS) DIE("task_set_exception_ports");
    
    if(pthread_attr_init(&attr) != 0) DIE("pthread_attr_init");
    if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0) 
        DIE("pthread_attr_setdetachedstate");
    
    if(pthread_create(&thread,&attr,exc_thread,NULL) != 0)
        DIE("pthread_create");
    pthread_attr_destroy(&attr);
}
Beispiel #12
0
int main() {
  kern_return_t kr = 0;
  mach_port_t exc_port;
  mach_port_t task = mach_task_self();
  pthread_t exception_thread;
  int err;
  
	mach_msg_type_number_t maskCount = 1;
	exception_mask_t mask;
	exception_handler_t handler;
	exception_behavior_t behavior;
	thread_state_flavor_t flavor;

	if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) {
		fprintf(stderr, "mach_port_allocate: %#x\n", kr);
		exit(1);
	}

	if ((kr = mach_port_insert_right(task, exc_port, exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) {
		fprintf(stderr, "mach_port_allocate: %#x\n", kr);
		exit(1);
	}

	if ((kr = task_get_exception_ports(task, EXC_MASK_ALL, &mask, &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) {
		fprintf(stderr,"task_get_exception_ports: %#x\n", kr);
		exit(1);
	}

	if ((err = pthread_create(&exception_thread, NULL, server_thread, &exc_port)) != 0) {
		fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err));
		exit(1);
	}
  
	pthread_detach(exception_thread);

  if ((kr = task_set_exception_ports(task, EXC_MASK_ALL, exc_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
    fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
    exit(1);
  }
  puts("Starting exception stuff");
  int a = 1;
  int b = 0;
  float c = a / b;
  int cat = *(int *)(0x13371337);
  printf("Have c %f and cat %d\n", c, cat);
  puts("End.");

}
Beispiel #13
0
void registerDarwinExceptionHandler(void) {
    // Create the Mach exception port
    mach_port_t self = mach_task_self();
    assert(mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &mach_ex_port) == KERN_SUCCESS);
    assert(mach_port_insert_right(self, mach_ex_port, mach_ex_port, MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
    
    // Create the thread which receives the exceptions
    pthread_t thread;
    pthread_attr_t attr;
    assert(!pthread_attr_init(&attr));
    assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
    assert(!pthread_create(&thread, &attr, exceptionHandlerEntryPoint, NULL));
    pthread_attr_destroy(&attr);
    
    assert(task_set_exception_ports(self, EXC_MASK_BAD_ACCESS, mach_ex_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE) == KERN_SUCCESS);
}
Beispiel #14
0
/* Initialize the Mach exception handler thread.
   Return 0 if OK, -1 on error.  */
static int
mach_initialize ()
{
  mach_port_t self;
  exception_mask_t mask;
  pthread_attr_t attr;
  pthread_t thread;

  self = mach_task_self ();

  /* Allocate a port on which the thread shall listen for exceptions.  */
  if (mach_port_allocate (self, MACH_PORT_RIGHT_RECEIVE, &our_exception_port)
      != KERN_SUCCESS)
    return -1;

  /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html.  */
  if (mach_port_insert_right (self, our_exception_port, our_exception_port,
                              MACH_MSG_TYPE_MAKE_SEND)
      != KERN_SUCCESS)
    return -1;

  /* The exceptions we want to catch.  Only EXC_BAD_ACCESS is interesting
     for us (see above in function catch_exception_raise).  */
  mask = EXC_MASK_BAD_ACCESS;

  /* Create the thread listening on the exception port.  */
  if (pthread_attr_init (&attr) != 0)
    return -1;
  if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED) != 0)
    return -1;
  if (pthread_create (&thread, &attr, mach_exception_thread, NULL) != 0)
    return -1;
  pthread_attr_destroy (&attr);

  /* Replace the exception port info for these exceptions with our own.
     Note that we replace the exception port for the entire task, not only
     for a particular thread.  This has the effect that when our exception
     port gets the message, the thread specific exception port has already
     been asked, and we don't need to bother about it.
     See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html.  */
  if (task_set_exception_ports (self, mask, our_exception_port,
                                EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)
      != KERN_SUCCESS)
    return -1;

  return 0;
}
Beispiel #15
0
bool exception_handler_install_platform() {
  if (s_installed) {
    return true;
  }

  // allocate port to listen for exceptions
  if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
                         &s_listen_port) != KERN_SUCCESS) {
    return false;
  }

  // http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html
  if (mach_port_insert_right(mach_task_self(), s_listen_port, s_listen_port,
                             MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) {
    return false;
  }

  // filter out any exception other than EXC_BAD_ACCESS
  // http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html
  if (task_set_exception_ports(mach_task_self(), exception_mask, s_listen_port,
                               EXCEPTION_DEFAULT,
                               MACHINE_THREAD_STATE) != KERN_SUCCESS) {
    return false;
  }

  // launch thread to listen for exceptions
  pthread_attr_t attr;
  pthread_t thread;

  if (pthread_attr_init(&attr) != 0) {
    return false;
  }

  if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) {
    return false;
  }

  if (pthread_create(&thread, &attr, &mach_exception_thread, NULL) != 0) {
    return -1;
  }

  pthread_attr_destroy(&attr);

  s_installed = true;

  return true;
}
Beispiel #16
0
static bool xnu_create_exception_thread(RDebug *dbg) {
	kern_return_t kr;
	int ret;
	mach_port_t exception_port = MACH_PORT_NULL;
        // Got the mach port for the current process
	mach_port_t task_self = mach_task_self ();
	task_t task = pid_to_task (dbg->pid);
	if (task == -1) {
		eprintf ("error to get task for the debugging process"
			" xnu_start_exception_thread\n");
		return false;
	}
	if (!MACH_PORT_VALID (task_self)) {
		eprintf ("error to get the task for the current process"
			" xnu_start_exception_thread\n");
		return false;
	}
        // Allocate an exception port that we will use to track our child process
        kr = mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE,
				&exception_port);
	RETURN_ON_MACH_ERROR ("error to allocate mach_port exception\n", R_FALSE);
        // Add the ability to send messages on the new exception port
        kr  = mach_port_insert_right (task_self, exception_port,
				exception_port, MACH_MSG_TYPE_MAKE_SEND);
	RETURN_ON_MACH_ERROR ("error to allocate insert right\n", R_FALSE);
        // Save the original state of the exception ports for our child process
        ret = xnu_save_exception_ports (dbg);
	if (ret == R_FALSE) {
		eprintf ("error to save exception port info\n");
		return false;
	}
        // Set the ability to get all exceptions on this port
	kr = task_set_exception_ports (task, EXC_MASK_ALL, exception_port,
				EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
				THREAD_STATE_NONE);
	RETURN_ON_MACH_ERROR ("error to set port to receive exceptions\n", R_FALSE);
        // Create the exception thread
	//TODO where to save the exception thread
	//TODO see options pthread_create
        ret = pthread_create (&dbg->ex->thread, NULL, xnu_exception_thread, dbg);
	if (ret) {
		perror ("pthread_create");
		return false;
	}
	return true;
}
Beispiel #17
0
bool TargetException::setExceptionCallback(ExceptionCallback callback)
{
	m_callback = std::move(callback);
    auto kr = mach_port_allocate(mach_task_self(),MACH_PORT_RIGHT_RECEIVE,&m_exceptionPort);
    if (kr != KERN_SUCCESS)
    {
        log(QString("mach_port_allocate failde: %1").arg(mach_error_string(kr)), LogType::Error);
        return false;
    }

    kr = mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND);
    if (kr != KERN_SUCCESS)
    {
        log(QString("mach_port_insert_right failde: %1").arg(mach_error_string(kr)), LogType::Error);
        return false;
    }

    kr = task_get_exception_ports(
            g_task,
            EXC_MASK_ALL,
            m_oldExcPorts.masks,
            &m_oldExcPorts.count,
            m_oldExcPorts.ports,
            m_oldExcPorts.behaviors,
            m_oldExcPorts.flavors
    );
    if (kr != KERN_SUCCESS)
    {
        log(QString("task_get_exception_ports failde: %1").arg(mach_error_string(kr)), LogType::Error);
        return false;
    }

    kr = task_set_exception_ports(
            g_task, EXC_MASK_ALL, m_exceptionPort,
            EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
            THREAD_STATE_NONE
    );

    if (kr != KERN_SUCCESS)
    {
        log(QString("task_set_exception_ports failde: %1").arg(mach_error_string(kr)), LogType::Error);
        return false;
    }

    return true;
}
Beispiel #18
0
// s/inferior_task/port/
static int debug_attach(int pid) {
        task_t task = pid_to_task (pid);
        if (task == -1)
                return -1;
        eprintf ("pid: %d\ntask: %d\n", pid, task);
#if 0
	// TODO : move this code into debug
        if (task_threads (task, &inferior_threads, &inferior_thread_count)
			!= KERN_SUCCESS) {
                eprintf ("Failed to get list of task's threads.\n");
                return -1;
        }
        eprintf ("Thread count: %d\n", inferior_thread_count);
#endif

#if SUSPEND
	if (task_suspend (this->port) != KERN_SUCCESS) {
		eprintf ("cannot suspend task\n");
		return -1; // R_FALSE
	}
#endif
	/* is this required for arm ? */
#if EXCEPTION_PORT
	int exception_port;
        if (mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
			&exception_port) != KERN_SUCCESS) {
                eprintf ("Failed to create exception port.\n");
                return -1;
        }
        if (mach_port_insert_right(mach_task_self(), exception_port,
			exception_port, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) {
                eprintf ("Failed to acquire insertion rights on the port.\n");
                return -1;
        }
        if (task_set_exception_ports(inferior_task, EXC_MASK_ALL, exception_port,
			EXCEPTION_DEFAULT, THREAD_STATE_NONE) != KERN_SUCCESS) {
                eprintf ("Failed to set the inferior's exception ports.\n");
                return -1;
        }
#endif
        return task;
}
Beispiel #19
0
/*++
Function :
    SEHCleanupExceptionPort

    Restore default exception port handler

    (no parameters, no return value)
    
Note :
During PAL_Terminate, we reach a point where SEH isn't possible any more
(handle manager is off, etc). Past that point, we can't avoid crashing on
an exception.
--*/
void SEHCleanupExceptionPort (void)
{
#if !DISABLE_EXCEPTIONS
    kern_return_t MachRet;

    TRACE("Restoring default exception ports\n");
    // Set the port that listens to exceptions for this task.
    MachRet = task_set_exception_ports(mach_task_self(),
                                       PAL_EXC_MASK | (s_DebugInitialized ? PAL_EXC_DEBUGGING_MASK : 0),
                                       MACH_PORT_NULL,
                                       EXCEPTION_DEFAULT,
                                       PPC_THREAD_STATE);
    if (MachRet != KERN_SUCCESS)
    {
       UTIL_SetLastErrorFromMach(MachRet);
    }

    s_DebugInitialized = FALSE;
#endif // !DISABLE_EXCEPTIONS
}
Beispiel #20
0
/*++
Function :
    MachExceptionInitializeDebug 

    Initialize the mach exception handlers necessary for a managed debugger
    to work

Return value :
    None
--*/
void MachExceptionInitializeDebug(void)
{
#if !DISABLE_EXCEPTIONS
    if (s_DebugInitialized == FALSE)
    {
        kern_return_t MachRet;
        MachRet = task_set_exception_ports(mach_task_self(),
                                           PAL_EXC_DEBUGGING_MASK,
                                           s_ExceptionPort,
                                           EXCEPTION_DEFAULT,
                                           PPC_THREAD_STATE);
        if (MachRet != KERN_SUCCESS)
        {
            TerminateProcess(GetCurrentProcess(), -1);
        }

        s_DebugInitialized = TRUE;
    }
#endif // !DISABLE_EXCEPTIONS
}
IOReturn com_enkript_driver_Service::hello(task_t target)
{
  EKDebugLog("hello task 0x%x", target);
  kern_return_t ret = KERN_SUCCESS;
  /* allocate receive port
   */
  ret = ipc_port_alloc(get_task_ipcspace(current_task()), &exception_port_name, &exception_port);
  EKDebugLog("ipc_port_alloc() ret=%d", ret);
  if (ret) return kIOReturnError;  
  /* set task exception port
   */
  ret = task_set_exception_ports(target, EXC_MASK_ALL, ipc_port_make_send(exception_port), EXCEPTION_DEFAULT, THREAD_STATE_NONE);
  EKDebugLog("task_set_exception_ports() ret=%d", ret);
  if (ret) return kIOReturnError;  
  /* create exception handler thread
   */
  (void) kernel_thread(kernel_task, exception_handler);

  return kIOReturnSuccess;
}
void
MemoryProtectionExceptionHandler::uninstall()
{
    if (sExceptionHandlerInstalled) {
        mach_port_t task = mach_task_self();

        // Restore the previous exception handler.
        MachExceptionParameters& previous = sMachExceptionState.previous;
        task_set_exception_ports(task, previous.mask, previous.port,
                                 previous.behavior, previous.flavor);

        TerminateMachExceptionHandlerThread();

        // Release the Mach IPC port we used.
        mach_port_deallocate(task, sMachExceptionState.current.port);

        sMachExceptionState.current = {};
        sMachExceptionState.previous = {};

        sExceptionHandlerInstalled = false;
    }
}
Beispiel #23
0
static void
macosx_register_exception_handler (void)
{
	mach_port_t task;
	pthread_attr_t attr;
	pthread_t thread;

	if (mach_exception_port != VM_MAP_NULL)
		return;

	task = mach_task_self ();

	/* create the "mach_exception_port" with send & receive rights */
	g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
				      &mach_exception_port) == KERN_SUCCESS);
	g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
					  MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);

	/* create the exception handler thread */
	g_assert (!pthread_attr_init (&attr));
	g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
	g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
	pthread_attr_destroy (&attr);

	/*
	 * register "mach_exception_port" as a receiver for the
	 * EXC_BAD_ACCESS exception
	 *
	 * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
	 */
	g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
					    mach_exception_port,
					    EXCEPTION_DEFAULT,
					    MACHINE_THREAD_STATE) == KERN_SUCCESS);

	mono_gc_register_mach_exception_thread (thread);
}
Beispiel #24
0
/* Initialize the Mach exception handler thread. */
void mach_initialize() {
  mach_port_t self;
  exception_mask_t mask;

  self = mach_task_self();

  /* Allocate a port on which the thread shall listen for exceptions. */
  if (mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &our_exception_port) !=
      KERN_SUCCESS)
    fatal_error("mach_port_allocate() failed", 0);

  /* See
   * http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html.
   */
  if (mach_port_insert_right(self, our_exception_port, our_exception_port,
                             MACH_MSG_TYPE_MAKE_SEND) !=
      KERN_SUCCESS)
    fatal_error("mach_port_insert_right() failed", 0);

  /* The exceptions we want to catch. */
  mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC;

  /* Create the thread listening on the exception port. */
  start_thread(mach_exception_thread, NULL);

  /* Replace the exception port info for these exceptions with our own.
     Note that we replace the exception port for the entire task, not only
     for a particular thread. This has the effect that when our exception
     port gets the message, the thread specific exception port has already
     been asked, and we don't need to bother about it. See
     http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html.	*/
  if (task_set_exception_ports(self, mask, our_exception_port,
                               EXCEPTION_DEFAULT, MACHINE_THREAD_STATE) !=
      KERN_SUCCESS)
    fatal_error("task_set_exception_ports() failed", 0);
}
Beispiel #25
0
void
osfmach3_trap_init(
	exception_behavior_t	behavior,
	thread_state_flavor_t	flavor)
{
	kern_return_t		kr;
	mach_port_t		trap_port_name, trap_port;
	exception_mask_t	mask;

	thread_exception_behavior = behavior;
	thread_exception_flavor = flavor;

	init_task.osfmach3.task->mach_task_port = mach_task_self();

	trap_port_name = ((mach_port_t) &init_task) + 1;

	kr = serv_port_allocate_name(&trap_port,
				     (void *) trap_port_name);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_trap_init: "
			     "serv_port_allocate_name(%x)",
			     trap_port_name));
		panic("osfmach3_trap_init: "
		      "can't allocate exception port");
	}
	init_task.osfmach3.thread->mach_trap_port = trap_port;

	kr = mach_port_insert_right(mach_task_self(),
				    trap_port,
				    trap_port,
				    MACH_MSG_TYPE_MAKE_SEND);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_trap_init: "
			     "mach_port_insert_right"));
		panic("osfmach3_trap_init: can't insert send right");
	}

	mask = EXC_MASK_ALL & ~EXC_MASK_RPC_ALERT;
	if (parent_server) {
		exception_mask_t		syscall_exc_mask;
		exception_mask_t		old_exc_mask;
		mach_msg_type_number_t		old_exc_count;
		mach_port_t			old_exc_port;
		exception_behavior_t		old_exc_behavior;
		thread_state_flavor_t		old_exc_flavor;

		/*
		 * Don't catch syscall exceptions that are directed to
		 * the parent server. But save the port, behavior and flavor
		 * to be able to restore them later.
		 */
		syscall_exc_mask = parent_server_syscall_exc_mask();
		old_exc_count = 1;
		kr = task_get_exception_ports(mach_task_self(),
					      syscall_exc_mask,
					      &old_exc_mask,
					      &old_exc_count,
					      &old_exc_port,
					      &old_exc_behavior,
					      &old_exc_flavor);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(0, kr,
				    ("osfmach3_trap_init(FIRST_TASK): "
				     "task_get_exception_ports(mask=0x%x)",
				     syscall_exc_mask));
			panic("can't get syscall exc port (parent server)");
		}
		if (old_exc_count == 1) {
			parent_server_syscall_port = old_exc_port;
			parent_server_syscall_behavior = old_exc_behavior;
			parent_server_syscall_flavor = old_exc_flavor;
		} else {
			printk("osfmach3_trap_init: "
			       "couldn't get our syscall exc port");
		}

		mask &= ~syscall_exc_mask;
		/* let breakpoints go to the debugger (if any) */
		mask &= ~EXC_MASK_BREAKPOINT;
		/* let Mach syscalls go to Mach */
		mask &= ~EXC_MASK_MACH_SYSCALL;
	}
	kr = task_set_exception_ports(mach_task_self(),
				      mask,
				      trap_port,
				      behavior,
				      flavor);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_trap_init: "
			     "task_set_exception_ports"));
		panic("osfmach3_trap_init: "
		      "can't set server's task exception ports");
	}
#if 0	/* obsolete */
	if (parent_server) {
		/*
		 * Hide the EXC_BAD_INSTRUCTION exceptions to avoid 
		 * interferences from the parent_server when we do
		 * syscalls to ourselves (see start_kernel() and init()).
		 */
		kr = thread_set_exception_ports(mach_thread_self(),
						EXC_MASK_BAD_INSTRUCTION,
						MACH_PORT_NULL,
						behavior,
						flavor);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_init: "
				     "thread_set_exception_ports"));
			panic("can't unset thread exception port");
		}
	}
#endif
	ASSERT(server_exception_port == MACH_PORT_NULL);
	server_exception_port = trap_port;
	server_thread_start(server_exception_catcher, (void *) 0);

	/*
	 * Create a global exception port for user tasks to detect
	 * new user threads.
	 */
	kr = mach_port_allocate(mach_task_self(),
				MACH_PORT_RIGHT_RECEIVE,
				&user_trap_port);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_trap_init: "
			     "mach_port_allocate()"));
		panic("osfmach3_trap_init: "
		      "can't allocate user trap port");
	}

	kr = mach_port_insert_right(mach_task_self(),
				    user_trap_port,
				    user_trap_port,
				    MACH_MSG_TYPE_MAKE_SEND);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_trap_init: "
			     "mach_port_insert_right"));
		panic("osfmach3_trap_init: can't insert send right "
		      "for user trap port");
	}

	server_thread_start(task_exception_catcher, (void *) 0);
}
Beispiel #26
0
void
osfmach3_trap_setup_task(
	struct task_struct	*task,
	exception_behavior_t	behavior,
	thread_state_flavor_t	flavor)
{
	kern_return_t		kr;
	mach_port_t		trap_port_name, trap_port;
	mach_port_t		task_port, thread_port;
	exception_mask_t	mask;

	if (task == &init_task) 
		return;

	task_port = task->osfmach3.task->mach_task_port;
	thread_port = task->osfmach3.thread->mach_thread_port;

	if (task->pid == 1) {
#if 0
		/*
		 * Remove the boostrap port for init.
		 */
		kr = task_set_bootstrap_port(task_port, MACH_PORT_NULL);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_setup_task: "
				     "task_set_bootstrap_port"));
			panic("osfmach3_trap_setup_task: "
			      "can't unset bootstrap port");
		}
#endif

		/*
		 * For the first process, setup a task exception port
		 * for all exceptions. These exception will be
		 * directed to the global "user_trap_port" and will
		 * allow us to detect threads created by user programs
		 * directly (using Mach system calls).
		 * This exception port will be inherited by the
		 * other tasks on task_create().
		 */
		kr = task_set_exception_ports(task_port,
					      (EXC_MASK_ALL &
					       ~EXC_MASK_RPC_ALERT),
					      user_trap_port,
					      EXCEPTION_STATE_IDENTITY,
					      flavor);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(0, kr,
				    ("osfmach3_trap_setup_task: "
				     "task_set_exception_ports"));
			panic("osfmach3_trap_setup_task: "
			      "can't set global user task exception ports");
		}
	}

	trap_port_name = ((mach_port_t) task) + 1;
	if (use_activations) {
		kr = serv_port_allocate_subsystem(exc_subsystem_port,
						  &trap_port,
						  (void *) trap_port_name);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(0, kr,
				    ("osfmach3_trap_setup_task: "
				     "serv_port_allocate_subsystem(%x)",
				     trap_port_name));
			panic("osfmach3_trap_setup_task: "
			      "can't allocate exception port");
		}
	} else {
		kr = serv_port_allocate_name(&trap_port,
					     (void *) trap_port_name);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(0, kr,
				    ("osfmach3_trap_setup_task: "
				     "serv_port_allocate_name(%x)",
				     trap_port_name));
			panic("osfmach3_trap_setup_task: "
			      "can't allocate exception port");
		}
	}
	task->osfmach3.thread->mach_trap_port = trap_port;
	task->osfmach3.thread->mach_trap_port_srights = 0;

	kr = mach_port_insert_right(mach_task_self(),
				    trap_port,
				    trap_port,
				    MACH_MSG_TYPE_MAKE_SEND);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_trap_setup_task: "
			     "mach_port_insert_right"));
		panic("osfmach3_trap_setup_task: can't insert send right");
	}

	if (thread_port != MACH_PORT_NULL) {
		mask = EXC_MASK_ALL & ~EXC_MASK_RPC_ALERT;
		if (suser() || task->osfmach3.task->mach_aware) {
			/* let Mach syscalls go to Mach */
			mask &= ~EXC_MASK_MACH_SYSCALL;
			/* the exception port is inherited from the parent */
		}

		kr = thread_set_exception_ports(thread_port,
						mask,
						trap_port,
						behavior,
						flavor);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(0, kr,
				    ("osfmach3_trap_setup_task: "
				     "thread_set_exception_ports"));
			panic("osfmach3_trap_setup_task: "
			      "can't set user thread exception ports");
		}
	} else {
		/* we'll set the exception ports later... maybe */
	}

	/*
	 * Add the exception port to the port set.
	 * The exceptions from the server task itself go to 
	 * the "server_exception_catcher" thread.
	 */
	ux_server_add_port(trap_port);
}
Beispiel #27
0
void julia_init(char *imageFile)
{
    jl_page_size = jl_getpagesize();
    jl_find_stack_bottom();
    jl_dl_handle = jl_load_dynamic_library(NULL, JL_RTLD_DEFAULT);
#ifdef _OS_WINDOWS_
    uv_dlopen("ntdll.dll",jl_ntdll_handle); //bypass julia's pathchecking for system dlls
    uv_dlopen("Kernel32.dll",jl_kernel32_handle);
    uv_dlopen("msvcrt.dll",jl_crtdll_handle);
    uv_dlopen("Ws2_32.dll",jl_winsock_handle);
    _jl_exe_handle.handle = GetModuleHandleA(NULL);
    if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
                          GetCurrentProcess(), (PHANDLE)&hMainThread, 0,
                          TRUE, DUPLICATE_SAME_ACCESS )) {
        JL_PRINTF(JL_STDERR, "Couldn't access handle to main thread\n");
    }
#if defined(_CPU_X86_64_)
    SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
    SymInitialize(GetCurrentProcess(), NULL, 1);
    needsSymRefreshModuleList = 0;
#endif
#endif
    jl_io_loop = uv_default_loop(); //this loop will internal events (spawining process etc.)
    init_stdio();

#if defined(__linux__)
    int ncores = jl_cpu_cores();
    if (ncores > 1) {
        cpu_set_t cpumask;
        CPU_ZERO(&cpumask);
        for(int i=0; i < ncores; i++) {
            CPU_SET(i, &cpumask);
        }
        sched_setaffinity(0, sizeof(cpu_set_t), &cpumask);
    }
#endif

#ifdef JL_GC_MARKSWEEP
    jl_gc_init();
    jl_gc_disable();
#endif
    jl_init_frontend();
    jl_init_types();
    jl_init_tasks(jl_stack_lo, jl_stack_hi-jl_stack_lo);
    jl_init_codegen();
    jl_an_empty_cell = (jl_value_t*)jl_alloc_cell_1d(0);

    jl_init_serializer();

    if (!imageFile) {
        jl_main_module = jl_new_module(jl_symbol("Main"));
        jl_main_module->parent = jl_main_module;
        jl_core_module = jl_new_module(jl_symbol("Core"));
        jl_core_module->parent = jl_main_module;
        jl_set_const(jl_main_module, jl_symbol("Core"),
                     (jl_value_t*)jl_core_module);
        jl_module_using(jl_main_module, jl_core_module);
        jl_current_module = jl_core_module;
        jl_init_intrinsic_functions();
        jl_init_primitives();
        jl_load("boot.jl");
        jl_get_builtin_hooks();
        jl_boot_file_loaded = 1;
        jl_init_box_caches();
    }

    if (imageFile) {
        JL_TRY {
            jl_restore_system_image(imageFile);
        }
        JL_CATCH {
            JL_PRINTF(JL_STDERR, "error during init:\n");
            jl_show(jl_stderr_obj(), jl_exception_in_transit);
            JL_PRINTF(JL_STDERR, "\n");
            jl_exit(1);
        }
    }

    // set module field of primitive types
    int i;
    void **table = jl_core_module->bindings.table;
    for(i=1; i < jl_core_module->bindings.size; i+=2) {
        if (table[i] != HT_NOTFOUND) {
            jl_binding_t *b = (jl_binding_t*)table[i];
            if (b->value && jl_is_datatype(b->value)) {
                jl_datatype_t *tt = (jl_datatype_t*)b->value;
                tt->name->module = jl_core_module;
            }
        }
    }

    // the Main module is the one which is always open, and set as the
    // current module for bare (non-module-wrapped) toplevel expressions.
    // it does "using Base" if Base is available.
    if (jl_base_module != NULL) {
        jl_add_standard_imports(jl_main_module);
    }
    // eval() uses Main by default, so Main.eval === Core.eval
    jl_module_import(jl_main_module, jl_core_module, jl_symbol("eval"));
    jl_current_module = jl_main_module;


#ifndef _OS_WINDOWS_
    signal_stack = malloc(SIGSTKSZ);
    struct sigaction actf;
    memset(&actf, 0, sizeof(struct sigaction));
    sigemptyset(&actf.sa_mask);
    actf.sa_handler = fpe_handler;
    actf.sa_flags = 0;
    if (sigaction(SIGFPE, &actf, NULL) < 0) {
        JL_PRINTF(JL_STDERR, "sigaction: %s\n", strerror(errno));
        jl_exit(1);
    }
#if defined(_OS_LINUX_)
    stack_t ss;
    ss.ss_flags = 0;
    ss.ss_size = SIGSTKSZ;
    ss.ss_sp = signal_stack;
    if (sigaltstack(&ss, NULL) < 0) {
        JL_PRINTF(JL_STDERR, "sigaltstack: %s\n", strerror(errno));
        jl_exit(1);
    }

    struct sigaction act;
    memset(&act, 0, sizeof(struct sigaction));
    sigemptyset(&act.sa_mask);
    act.sa_sigaction = segv_handler;
    act.sa_flags = SA_ONSTACK | SA_SIGINFO;
    if (sigaction(SIGSEGV, &act, NULL) < 0) {
        JL_PRINTF(JL_STDERR, "sigaction: %s\n", strerror(errno));
        jl_exit(1);
    }

    if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) {
        JL_PRINTF(JL_STDERR, "Couldn't set SIGPIPE\n");
        jl_exit(1);
    }
#elif defined (_OS_DARWIN_)
    kern_return_t ret;
    mach_port_t self = mach_task_self();
    ret = mach_port_allocate(self,MACH_PORT_RIGHT_RECEIVE,&segv_port);
    HANDLE_MACH_ERROR("mach_port_allocate",ret);
    ret = mach_port_insert_right(self,segv_port,segv_port,MACH_MSG_TYPE_MAKE_SEND);
    HANDLE_MACH_ERROR("mach_port_insert_right",ret);

    // Alright, create a thread to serve as the listener for exceptions
    pthread_t thread;
    pthread_attr_t attr;
    if (pthread_attr_init(&attr) != 0)
    {
        JL_PRINTF(JL_STDERR, "pthread_attr_init failed");
        jl_exit(1);
    }
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    if (pthread_create(&thread,&attr,mach_segv_listener,NULL) != 0)
    {
        JL_PRINTF(JL_STDERR, "pthread_create failed");
        jl_exit(1);
    }
    pthread_attr_destroy(&attr);

    ret = task_set_exception_ports(self,EXC_MASK_BAD_ACCESS,segv_port,EXCEPTION_DEFAULT,MACHINE_THREAD_STATE);
    HANDLE_MACH_ERROR("task_set_exception_ports",ret);
#endif
#else
    if (signal(SIGFPE, (void (__cdecl *)(int))fpe_handler) == SIG_ERR) {
        JL_PRINTF(JL_STDERR, "Couldn't set SIGFPE\n");
        jl_exit(1);
    }
#endif


#ifdef JL_GC_MARKSWEEP
    jl_gc_enable();
#endif
}
Beispiel #28
0
int main(int argc, char *argv[])
{
    posix_spawnattr_t	attrs;
    uint64_t		percent, interval;
    int			i, err, ret = 0;

    kern_return_t		kr;
    mach_port_t		task = mach_task_self();
    mach_port_t		child_task;
    char                    **child_args;

    pthread_t		exception_thread;
    pthread_t		timer_thread;
    pthread_t		wait_thread;

    mach_msg_type_number_t	maskCount = 1;
    exception_mask_t	mask;
    exception_handler_t	handler;
    exception_behavior_t	behavior;
    thread_state_flavor_t   flavor;

    pid_t			child_pid;
    int			test_case_id = -1;

    if (argc > 1)
        test_case_id = atoi(argv[1]);

    /* Initialize mutex and condition variable */
    if ((err = pthread_mutex_init(&lock, NULL)) != 0) {
        fprintf(stderr,"pthread_mutex_init: %s\n", strerror(err));
        exit(1);
    }

    if ((err = pthread_cond_init(&cv, NULL)) != 0) {
        fprintf(stderr, "pthread_cond_init: %s\n", strerror(err));
        exit(1);
    }

    /* Allocate and initialize new exception port */
    if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) {
        fprintf(stderr, "mach_port_allocate: %s\n", mach_error_string(kr));
        exit(1);
    }

    if ((kr = mach_port_insert_right(task, exc_port,
                                     exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) {
        fprintf(stderr, "mach_port_allocate: %s\n", mach_error_string(kr));
        exit(1);
    }

    /* Get Current exception ports */
    if ((kr = task_get_exception_ports(task, EXC_MASK_RESOURCE, &mask,
                                       &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) {
        fprintf(stderr,"task_get_exception_ports: %s\n", mach_error_string(kr));
        exit(1);
    }

    /* Create exception serving thread */
    if ((err = pthread_create(&exception_thread, NULL, server_thread, 0)) != 0) {
        fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err));
        exit(1);
    }

    fprintf(stderr, "---------------System Configuration------------------------------------------\n");
    fprintf(stderr, "System Kernel Version: ");
    system("uname -a");
    fprintf(stderr, "System SDK Version: ");
    system("sw_vers");

    for (i = 0; i < NUMTESTS; i++) {
        indiv_results[i] = -1;
    }

    /* Run Tests */
    for(i=0; i<NUMTESTS; i++) {
        int j;

        if (test_case_id != -1 && test_case_id != i)
            continue;

        fprintf(stderr, "---------------Test [%d] Configuration------------------------------------------\n", i);
        fprintf(stderr, "Test Case ID: %d\n", i);
        fprintf(stderr, "Description: %s\n", test_description[i]);

        switch(i) {
        case 0:
            child_args = test_argv_0;
            break;
        case 1:
            child_args = test_argv_1;
            break;
        case 2:
            child_args = test_argv_2;
            break;
        case 3:
            child_args = test_argv_3;
            break;
        case 4:
            child_args = test_argv_4;
            break;
        case 5:
            child_args = test_argv_5;
            break;
        case 6:
            child_args = test_argv_6;
            break;
        default:
            fprintf(stderr, "no test argv found\n");
            exit(1);
        }

        /* Test cases which do not need to run for certain platforms */
        if (child_args == NULL) {
            fprintf(stderr, "Test case unimplemented for current platform.\n");
            fprintf(stderr, "[PASSED]\n");
            fprintf(stderr, "-------------------------------------------------------------------------------\n");
            continue;
        }

        fprintf(stderr, "Helper args: ");
        for (j = 0; child_args[j] != NULL; j++) {
            fprintf(stderr, "%s ", child_args[j]);
        }
        fprintf(stderr, "\n");

        /* Print Test Case Configuration */
        fprintf(stderr, "Test Case expects EXC_RESOURCE?: %s\n", test_exception_code[i] ? "Yes":"No");
        if (test_exception_code[i])
            fprintf(stderr, "Expected EXC_RESOURCE code: 0x%llx\n", test_exception_code[i]);
        if (timeout_secs[i])
            fprintf(stderr, "Timeout for Test Program: %d secs\n", timeout_secs[i]);
        if (exc_expected_at[i])
            fprintf(stderr, "Exception Expected After: %d secs\n", exc_expected_at[i]);

        /* Initialize posix_spawn attributes */
        posix_spawnattr_init(&attrs);

        if ((err = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC)) != 0) {
            fprintf(stderr, "posix_spawnattr_setflags: %s\n", strerror(err));
            exit(1);
        }

        /* Use high values so the system defaults take effect (spawn attrs are capped) */
        percent = 100;
        interval = 10000;

        /* Enable CPU Monitor */
        if ((err = posix_spawnattr_setcpumonitor(&attrs, percent, interval)) != 0) {
            fprintf(stderr, "posix_spawnattr_setcpumonitor: %s\n", strerror(err));
            exit(1);
        }


        exception_code = 0;
        time_for_exc = -1;

        /* Set Exception Ports for Current Task */
        if ((kr = task_set_exception_ports(task, EXC_MASK_RESOURCE, exc_port,
                                           EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
            fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
            exit(1);
        }

        /*
         * Note the time at start of test.
         */
        start_time = time(NULL);

        fprintf(stderr, "---------------Test [%d] Runtime------------------------------------------------\n", i);

        /* Fork and exec child */
        if ((child_pid = fork()) == 0) {
            if ((err = posix_spawn(NULL, child_args[0], NULL, &attrs, &child_args[0], environ)) != 0) {
                fprintf(stderr, "posix_spawn: %s\n", strerror(err));
                exit(1);
            }
        }

        /* Restore exception ports for parent */
        if ((kr = task_set_exception_ports(task, EXC_MASK_RESOURCE, handler,
                                           EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
            fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
            exit(1);
        }

        /* Create Timer Thread if timeout specified */
        if (timeout_secs[i]) {
            if ((err = pthread_create(&timer_thread, NULL, timeout_thread, (void *)timeout_secs[i])) != 0) {
                fprintf(stderr, "pthread_create timeout_thread: %s\n", strerror(err));
                test_status = 1;
                goto cleanup;
            }
        }

        /* Create waiting for child thread */
        if ((err = pthread_create(&wait_thread, NULL, wait4_child_thread, NULL)) != 0) {
            fprintf(stderr, "pthread_create wait4_child_thread: %s\n", strerror(err));
            test_status = 1;
            goto cleanup;
        }

        pthread_mutex_lock(&lock);
        pthread_cond_wait(&cv, &lock);
        pthread_mutex_unlock(&lock);

        kill(child_pid, SIGKILL);
        pthread_join(timer_thread, NULL);
        pthread_join(wait_thread, NULL);

        int test_case_status = 0;
        indiv_results[i] = 0;

        fprintf(stderr, "---------------Test [%d] Results------------------------------------------------\n", i);

        if (exception_code)
            fprintf(stderr, "EXC_RESOURCE Received with Code: 0x%llx\n", exception_code);
        else
            fprintf(stderr, "No EXC_RESOURCE Received!\n");

        if (time_for_exc > 0)
            fprintf(stderr, "EXC_RESOURCE Received after %d secs\n", time_for_exc);

        if (!!exception_code != !!test_exception_code[i]) {
            test_status = 1;
            test_case_status = 1;
            indiv_results[i] = 1;
        }

        if (exception_code) {
            /* Validate test success by checking code and expected time */
            if ((exception_code & test_exception_code[i]) != test_exception_code[i]) {
                fprintf(stderr, "Test Failure Reason: EXC_RESOURCE code did not match expected exception code!\n");
                fprintf(stderr, "Expected: 0x%llx Found: 0x%llx\n", test_exception_code[i], exception_code);
                test_status = 1;
                test_case_status = 1;
                indiv_results[i] = 1;
            }
            if(exc_expected_at[i] &&
                    (time_for_exc < (exc_expected_at[i] - 10) ||
                     time_for_exc > (exc_expected_at[i] + 10))) {
                fprintf(stderr, "Test Failure Reason: Test case did not receive EXC_RESOURCE within expected time!\n");
                test_status = 1;
                test_case_status = 1;
                indiv_results[i] = 1;
            }
        }

        if(test_case_status)
            fprintf(stderr, "[FAILED]\n");
        else
            fprintf(stderr, "[PASSED]\n");
        fprintf(stderr, "-------------------------------------------------------------------------------\n");

    }

    if (test_case_id == -1) {
        fprintf(stderr, "--------------- Results Summary -----------------------------------------------\n");

        for (i = 0; i < NUMTESTS; i++) {
            fprintf(stderr, "%2d: %s\n", i, (indiv_results[i] < 0) ? "N/A" :
                    (indiv_results[i] == 0) ? "PASSED" : "FAILED");
        }
    }

cleanup:
    kill(child_pid, SIGKILL);
    exit(test_status);
}
Beispiel #29
0
static tb_bool_t it_inject(pid_t pid, tb_char_t const* path) 
{
    // check
    tb_assert_and_check_return_val(pid && path, tb_false);

    // trace
    tb_trace_d("inject: pid: %lu, path: %s: ..", (tb_size_t)pid, path);

#ifdef TB_ARCH_ARM64
    // uses libsubstrate first?
    if (tb_file_info("/usr/lib/libsubstrate.dylib", tb_null))
    {
        // init library
        tb_bool_t   ok = tb_false;
        tb_handle_t library = tb_dynamic_init("/usr/lib/libsubstrate.dylib");
        if (library)
        {
            // trace
            tb_trace_d("library: %p", library);

            // the func
            it_MSHookProcess_t pMSHookProcess = tb_dynamic_func(library, "MSHookProcess");
            if (pMSHookProcess)
            {
                // trace
                tb_trace_d("MSHookProcess: %p", pMSHookProcess);

                // hook process
                ok = pMSHookProcess(pid, path)? tb_true : tb_false;
            }

            // exit library
            tb_dynamic_exit(library);

            // trace
            tb_trace_i("%s", ok? "ok" : "no");

            // ok?
            return ok;
        }
    }
#endif

    // pid => task
    task_t task = 0;
    if (task_for_pid(mach_task_self(), (tb_int_t)pid, &task)) 
    {
        tb_trace_i("task_for_pid: %lu failed, errno: %d", (tb_size_t)pid, errno);
        return tb_false;
    }

    // trace
    tb_trace_d("task: %u", task);

    // stuff
    cpu_type_t cputype; it_addr_bundle_t addrs;
    if (!it_stuff(task, &cputype, &addrs)) return tb_false;

    // trace
    tb_trace_d("dlopen: %p", addrs.dlopen);
    tb_trace_d("syscall: %p", addrs.syscall);

    // alloc stack 
    mach_vm_address_t stack_address = 0;
    if (mach_vm_allocate(task, &stack_address, it_stack_size, VM_FLAGS_ANYWHERE)) return tb_false;

    // write path
    mach_vm_address_t stack_end = stack_address + it_stack_size - 0x100;
    if (mach_vm_write(task, stack_address, (vm_offset_t)it_address_cast(path), strlen(path) + 1)) return tb_false;

    /* the first one is the return address
     *
     * syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0)
     */
    tb_uint32_t args_32[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0};
    tb_uint64_t args_64[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0};

    // init thread state 
    union
    {
        it_arm_thread_state_t       arm;
        it_arm_thread_state64_t     arm64;
        it_x86_thread_state32_t     x86;
        it_x86_thread_state64_t     x64;
        natural_t                   nat;

    }state;
    thread_state_flavor_t           state_flavor;
    mach_msg_type_number_t          state_count;
    memset(&state, 0, sizeof(state));   

    // init thread state for the cpu type
    switch (cputype)
    {
    case CPU_TYPE_ARM:
        {
            tb_trace_i("cputype: arm");
            memcpy(&state.arm.r[0], args_32 + 1, 4 * sizeof(tb_uint32_t));
            if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32 + 5), 2 * sizeof(tb_uint32_t))) return tb_false;

            state.arm.sp    = (tb_uint32_t) stack_end;
            state.arm.pc    = (tb_uint32_t) addrs.syscall;
            state.arm.lr    = (tb_uint32_t) args_32[0];

            state_flavor    = ARM_THREAD_STATE;
            state_count     = sizeof(state.arm) / sizeof(state.nat);

            // trace
            tb_trace_d("init: pc: %x", state.arm.pc);
            tb_trace_d("init: lr: %x", state.arm.lr);
            tb_trace_d("init: sp: %x", state.arm.sp);
        }
        break;
    case CPU_TYPE_ARM64:
        {
            tb_trace_i("cputype: arm64");
            memcpy(&state.arm64.x[0], args_64 + 1, 6 * sizeof(tb_uint64_t));

            state.arm64.sp  = (tb_uint64_t) stack_end;
//          state.arm64.fp  = (tb_uint64_t) stack_end;
            state.arm64.pc  = (tb_uint64_t) addrs.syscall;
            state.arm64.lr  = (tb_uint64_t) args_64[0];

            state_flavor    = ARM_THREAD_STATE64;
            state_count     = sizeof(state.arm64) / sizeof(state.nat);

            // trace
            tb_trace_d("init: pc: %llx", state.arm64.pc);
            tb_trace_d("init: lr: %llx", state.arm64.lr);
            tb_trace_d("init: sp: %llx", state.arm64.sp);
        }
        break;
    case CPU_TYPE_X86:
        {
            tb_trace_i("cputype: x86");
            if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32), 7 * 4)) return tb_false;

            state.x86.esp   = state.x86.ebp = (tb_uint32_t) stack_end;
            state.x86.eip   = (tb_uint32_t)addrs.syscall;

            state_flavor    = x86_THREAD_STATE32;
            state_count     = sizeof(state.x86) / sizeof(state.nat);
        }
        break;
    case CPU_TYPE_X86_64:
        {
            tb_trace_i("cputype: x64");
            state.x64.rdi   = args_64[1];
            state.x64.rsi   = args_64[2];
            state.x64.rdx   = args_64[3];
            state.x64.rcx   = args_64[4];
            state.x64.r8    = args_64[5];
            state.x64.r9    = args_64[6];

            state.x64.rsp   = state.x64.rbp = stack_end;
            state.x64.rip   = addrs.syscall;

            state_flavor    = x86_THREAD_STATE64;
            state_count     = sizeof(state.x64) / sizeof(state.nat);
        }
        break;
    default:
        tb_trace_i("cputype: unknown: %lx", (tb_size_t)cputype);
        return tb_false;
    }

    // init a remote thread
    thread_act_t thread = 0;
    if (thread_create(task, &thread)) return tb_false;

    // trace
    tb_trace_d("init: thread: %x", thread);

    // alloc port
    mach_port_t exc = 0;
    mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exc);
    if (mach_port_insert_right(mach_task_self(), exc, exc, MACH_MSG_TYPE_MAKE_SEND)) return tb_false;

    // swap port
    exception_mask_t        em[2];
    exception_handler_t     eh[2];
    exception_behavior_t    eb[2];
    thread_state_flavor_t   ef[2];
    mach_msg_type_number_t  em_count = 2;
    if (task_swap_exception_ports(task, EXC_MASK_BAD_ACCESS, exc, EXCEPTION_STATE_IDENTITY, state_flavor, em, &em_count, eh, eb, ef)) return tb_false;
    tb_assert_and_check_return_val(em_count <= 1, tb_false);

    // resume thread, done: syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0)
    if (thread_set_state(thread, state_flavor, &state.nat, state_count)) return tb_false;
    if (thread_resume(thread)) return tb_false;

    // we expect three exceptions: one from thread when it returns, one from the new thread when it calls the fake handler, and one from the new thread when it returns from dlopen.
    tb_bool_t started_dlopen = tb_false;
    while (1) 
    {
        // recv msg
        it_exception_message_t msg;
        if (mach_msg_overwrite(tb_null, MACH_RCV_MSG, 0, sizeof(msg), exc, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, (tb_pointer_t) &msg, sizeof(msg))) return tb_false;

        // trace
        tb_trace_d("recv: msg: from thread: %x", msg.thread.name);

        // check
        tb_assert_and_check_return_val((msg.Head.msgh_bits & MACH_MSGH_BITS_COMPLEX), tb_false);
        tb_assert_and_check_return_val((msg.msgh_body.msgh_descriptor_count != 0), tb_false);
        tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state)), tb_false);
        tb_assert_and_check_return_val((msg.old_stateCnt == state_count), tb_false);
        tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state) + msg.old_stateCnt * sizeof(natural_t)), tb_false);

        // the msg state
        memcpy(&state, msg.old_state, sizeof(state));

        // dump
//      tb_dump_data((tb_byte_t const*)&state, sizeof(state));

        // done
        if (msg.thread.name == thread)
        {
            tb_trace_d("terminate");
            if (thread_terminate(thread)) return tb_false;
        } 
        else
        {
            // init cond
            tb_bool_t cond = tb_false;
            switch(cputype)
            {
            case CPU_TYPE_ARM:      
                {
                    // trace
                    tb_trace_d("recv: pc: %x", state.arm.pc);
                    tb_trace_d("recv: lr: %x", state.arm.lr);
                    tb_trace_d("recv: sp: %x", state.arm.sp);

                    // cond
                    cond = ((state.arm.pc & ~1) == 0xdeadbeee)? tb_true : tb_false;
                }
                break;
            case CPU_TYPE_ARM64:
                {
                    // trace
                    tb_trace_d("recv: pc: %llx", state.arm64.pc);
                    tb_trace_d("recv: lr: %llx", state.arm64.lr);
                    tb_trace_d("recv: sp: %llx", state.arm64.sp);

                    // cond
                    cond = ((state.arm64.pc & ~1) == 0xdeadbeee)? tb_true : tb_false;
                }
                break;
            case CPU_TYPE_X86:
                cond = (state.x86.eip == 0xdeadbeef)? tb_true : tb_false; 
                break;
            case CPU_TYPE_X86_64:
                cond = (state.x64.rip == 0xdeadbeef)? tb_true : tb_false;
                break;
            }

            tb_trace_d("cond: %d, started_dlopen: %d", cond, started_dlopen);
            if (!cond)
            {
                // let the normal crash mechanism handle it
                task_set_exception_ports(task, em[0], eh[0], eb[0], ef[0]);
                tb_assert_and_check_return_val(0, tb_false);
            }
            else if (started_dlopen)
            {
                tb_trace_d("terminate");
                if (thread_terminate(msg.thread.name)) return tb_false;
                break;
            }
            else 
            {
                // done: dlopen(path, RTLD_LAZY)
                switch(cputype)
                {
                case CPU_TYPE_ARM:
                    {
                        state.arm.r[0] = (tb_uint32_t) stack_address;
                        state.arm.r[1] = RTLD_LAZY;
                        state.arm.pc = (tb_uint32_t) addrs.dlopen;
                        state.arm.lr = 0xdeadbeef;
                    }
                    break;
                case CPU_TYPE_ARM64:
                    {
                        state.arm64.x[0] = (tb_uint64_t) stack_address;
                        state.arm64.x[1] = RTLD_LAZY;
                        state.arm64.pc = (tb_uint64_t) addrs.dlopen;
                        state.arm64.lr = 0xdeadbeef;
                    }
                    break;
                case CPU_TYPE_X86:
                    {
                        tb_uint32_t stack_stuff[3] = {0xdeadbeef, (tb_uint32_t)stack_address, RTLD_LAZY};
                        if (mach_vm_write(task, (mach_vm_address_t)state.x86.esp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false;
                    }
                    state.x86.eip = (tb_uint32_t) addrs.dlopen;
                    break;
                case CPU_TYPE_X86_64:
                    {
                        tb_uint64_t stack_stuff = 0xdeadbeef;
                        if (mach_vm_write(task, (mach_vm_address_t)state.x64.rsp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false;
                        state.x64.rip = addrs.dlopen;
                        state.x64.rdi = stack_address;
                        state.x64.rsi = RTLD_LAZY;
                    }
                    break;
                }

                it_exception_reply_t reply;
                memcpy(&reply.Head, &msg.Head, sizeof(mach_msg_header_t));
                reply.Head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
                reply.Head.msgh_size = offsetof(it_exception_reply_t, new_state) + state_count * sizeof(natural_t);
                reply.Head.msgh_id += 100;
                memcpy(&reply.NDR, &msg.NDR, sizeof(NDR_record_t));
                reply.RetCode = 0;
                reply.flavor = state_flavor;
                reply.new_stateCnt = state_count;
                memcpy(&reply.new_state, &state, sizeof(state));

                if (thread_set_state(msg.thread.name, state_flavor, &state.nat, state_count)) return tb_false;
                if (mach_msg(&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)) return tb_false;
                started_dlopen = tb_true;
            }
        }
    }

    // exit
    if (stack_address) vm_deallocate(task, stack_address, it_stack_size);
    if (thread)
    {
        thread_terminate(thread);
        mach_port_deallocate(mach_task_self(), thread);
    }
    if (task) mach_port_deallocate(mach_task_self(), task);
    if (exc) mach_port_deallocate(mach_task_self(), exc);

    // ok
    tb_trace_i("ok");
    return tb_true;
}
bool kscrashsentry_installMachHandler(KSCrash_SentryContext* const context)
{
    KSLOG_DEBUG("Installing mach exception handler.");

    bool attributes_created = false;
    pthread_attr_t attr;

    kern_return_t kr;
    int error;

    const task_t thisTask = mach_task_self();
    exception_mask_t mask = EXC_MASK_BAD_ACCESS |
    EXC_MASK_BAD_INSTRUCTION |
    EXC_MASK_ARITHMETIC |
    EXC_MASK_SOFTWARE |
    EXC_MASK_BREAKPOINT;

    if(g_installed)
    {
        KSLOG_DEBUG("Exception handler already installed.");
        return true;
    }
    g_installed = 1;

    if(ksmach_isBeingTraced())
    {
        // Different debuggers hook into different exception types.
        // For example, GDB uses EXC_BAD_ACCESS for single stepping,
        // and LLDB uses EXC_SOFTWARE to stop a debug session.
        // Because of this, it's safer to not hook into the mach exception
        // system at all while being debugged.
        KSLOG_WARN("Process is being debugged. Not installing handler.");
        goto failed;
    }

    g_context = context;

    KSLOG_DEBUG("Backing up original exception ports.");
    kr = task_get_exception_ports(thisTask,
                                  mask,
                                  g_previousExceptionPorts.masks,
                                  &g_previousExceptionPorts.count,
                                  g_previousExceptionPorts.ports,
                                  g_previousExceptionPorts.behaviors,
                                  g_previousExceptionPorts.flavors);
    if(kr != KERN_SUCCESS)
    {
        KSLOG_ERROR("task_get_exception_ports: %s", mach_error_string(kr));
        goto failed;
    }

    if(g_exceptionPort == MACH_PORT_NULL)
    {
        KSLOG_DEBUG("Allocating new port with receive rights.");
        kr = mach_port_allocate(thisTask,
                                MACH_PORT_RIGHT_RECEIVE,
                                &g_exceptionPort);
        if(kr != KERN_SUCCESS)
        {
            KSLOG_ERROR("mach_port_allocate: %s", mach_error_string(kr));
            goto failed;
        }

        KSLOG_DEBUG("Adding send rights to port.");
        kr = mach_port_insert_right(thisTask,
                                    g_exceptionPort,
                                    g_exceptionPort,
                                    MACH_MSG_TYPE_MAKE_SEND);
        if(kr != KERN_SUCCESS)
        {
            KSLOG_ERROR("mach_port_insert_right: %s", mach_error_string(kr));
            goto failed;
        }
    }

    KSLOG_DEBUG("Installing port as exception handler.");
    kr = task_set_exception_ports(thisTask,
                                  mask,
                                  g_exceptionPort,
                                  EXCEPTION_DEFAULT,
                                  THREAD_STATE_NONE);
    if(kr != KERN_SUCCESS)
    {
        KSLOG_ERROR("task_set_exception_ports: %s", mach_error_string(kr));
        goto failed;
    }

    KSLOG_DEBUG("Creating secondary exception thread (suspended).");
    pthread_attr_init(&attr);
    attributes_created = true;
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    error = pthread_create(&g_secondaryThread,
                           &attr,
                           &ksmachexc_i_handleExceptions,
                           kThreadSecondary);
    if(error != 0)
    {
        KSLOG_ERROR("pthread_create_suspended_np: %s", strerror(error));
        goto failed;
    }
    context->reservedThreads[KSCrashReservedThreadTypeMachSecondary] = pthread_mach_thread_np(g_secondaryThread);

    KSLOG_DEBUG("Creating primary exception thread.");
    error = pthread_create(&g_primaryThread,
                           &attr,
                           &ksmachexc_i_handleExceptions,
                           kThreadPrimary);
    if(error != 0)
    {
        KSLOG_ERROR("pthread_create: %s", strerror(error));
        goto failed;
    }
    pthread_attr_destroy(&attr);
    context->reservedThreads[KSCrashReservedThreadTypeMachPrimary] = pthread_mach_thread_np(g_primaryThread);

    KSLOG_DEBUG("Mach exception handler installed.");
    return true;


failed:
    KSLOG_DEBUG("Failed to install mach exception handler.");
    if(attributes_created)
    {
        pthread_attr_destroy(&attr);
    }
    kscrashsentry_uninstallMachHandler();
    return false;
}