Example #1
0
static bool xnu_save_exception_ports (int pid) {
	kern_return_t kr;
	task_t task = pid_to_task (pid);
	ex.count = (sizeof (ex.ports) / sizeof (ex.ports[0]));
	kr = task_get_exception_ports (task, EXC_MASK_ALL,
		ex.masks, &ex.count, ex.ports,
		ex.behaviors, ex.flavors);
	return (kr == KERN_SUCCESS);
}
void next_save_exception_ports
(task_t task, struct next_exception_info *info)
{
  kern_return_t kret;

  info->count = (sizeof (info->ports) / sizeof (info->ports[0]));
  kret = task_get_exception_ports
    (task,
     EXC_MASK_ALL,
     info->masks, &info->count, info->ports, info->behaviors, info->flavors);
  MACH_CHECK_ERROR (kret);
}
Example #3
0
//FIXME this will not compile
static bool xnu_save_exception_ports (RDebug *dbg) {
	kern_return_t kr;
	task_t task = pid_to_task (dbg->pid);
	dbg->ex->count = (sizeof (dbg->ex->ports) / sizeof (dbg->ex->ports[0]));
	if (task == -1) {
		perror ("xnu_save_exception_ports: pid_to_task:");
		return false;
	}
	kr = task_get_exception_ports (task, EXC_MASK_ALL,
		dbg->ex->masks, &dbg->ex->count, dbg->ex->ports,
		dbg->ex->behaviors, dbg->ex->flavors);
	return (kr == KERN_SUCCESS);
}
static void
info_mach_exceptions_command (const char *args, int from_tty)
{
  int i;
  task_t task;
  kern_return_t kret;
  darwin_exception_info info;

  info.count = sizeof (info.ports) / sizeof (info.ports[0]);

  if (args != NULL)
    {
      if (strcmp (args, "saved") == 0)
	{
	  if (ptid_equal (inferior_ptid, null_ptid))
	    printf_unfiltered (_("No inferior running\n"));

	  darwin_inferior *priv = get_darwin_inferior (current_inferior ());

	  disp_exception (&priv->exception_info);
	  return;
	}
      else if (strcmp (args, "host") == 0)
	{
	  /* FIXME: This need a privilegied host port!  */
	  kret = host_get_exception_ports
	    (darwin_host_self, EXC_MASK_ALL, info.masks,
	     &info.count, info.ports, info.behaviors, info.flavors);
	  MACH_CHECK_ERROR (kret);
	  disp_exception (&info);
	}
      else
	error (_("Parameter is saved, host or none"));
    }
  else
    {
      struct inferior *inf;

      if (ptid_equal (inferior_ptid, null_ptid))
	printf_unfiltered (_("No inferior running\n"));
      inf = current_inferior ();
      
      darwin_inferior *priv = get_darwin_inferior (inf);

      kret = task_get_exception_ports
	(priv->task, EXC_MASK_ALL, info.masks,
	 &info.count, info.ports, info.behaviors, info.flavors);
      MACH_CHECK_ERROR (kret);
      disp_exception (&info);
    }
}
Example #5
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);
}
Example #6
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.");

}
Example #7
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;
}
mach_port_t machExceptionPort()
{
    exception_mask_t exceptionMasks[EXC_TYPES_COUNT];
    exception_port_t exceptionHandlers[EXC_TYPES_COUNT];
    exception_behavior_t exceptionBehaviors[EXC_TYPES_COUNT];
    thread_state_flavor_t exceptionFlavors[EXC_TYPES_COUNT];
    mach_msg_type_number_t numExceptionMasks;

    kern_return_t kr = task_get_exception_ports(mach_task_self(), EXC_MASK_CRASH, exceptionMasks, &numExceptionMasks, exceptionHandlers, exceptionBehaviors, exceptionFlavors);
    if (kr != KERN_SUCCESS) {
        ASSERT_NOT_REACHED();
        return MACH_PORT_NULL;
    }

    // We're just interested in the first exception handler.
    return exceptionHandlers[0];
}
Example #9
0
void
osfmach3_trap_forward(
	exception_type_t		exc_type,
	exception_data_t		code,
	mach_msg_type_number_t		code_count,
	int				*flavor,
	thread_state_t			old_state,
	mach_msg_type_number_t		*icnt,
	thread_state_t			new_state,
	mach_msg_type_number_t		*ocnt)
{
	kern_return_t		kr;
	mach_msg_type_number_t	exc_count;
	exception_mask_t	exc_mask;
	mach_port_t		exc_port;
	exception_behavior_t	exc_behavior;
	thread_state_flavor_t	exc_flavor;
	mach_port_t		thread_port, task_port;

	/*
	 * Check if a debugger has changed the task exception port:
	 * if so, forward the exception to the debugger.
	 */
	exc_port = MACH_PORT_NULL;
	task_port = current->osfmach3.task->mach_task_port;
	thread_port = current->osfmach3.thread->mach_thread_port;
	exc_count = 1;
	kr = task_get_exception_ports(task_port,
				      1 << exc_type,
				      &exc_mask,
				      &exc_count,
				      &exc_port,
				      &exc_behavior,
				      &exc_flavor);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(1, kr,
			    ("osfmach3_trap_forward: "
			     "task_get_exception_ports(0x%x, 0x%x)",
			     task_port, 1 << exc_type));
		current->osfmach3.thread->exception_completed = FALSE;
		return;
	}
	if (!MACH_PORT_VALID(exc_port)) {
		current->osfmach3.thread->exception_completed = FALSE;
		return;
	}
	ASSERT(exc_mask == 1 << exc_type);
	if (exc_port == user_trap_port) {
		/*
		 * Nothing has changed. Process the exception normally.
		 */
		if (user_trap_port_refs++ >= 0x7000) {
			kr = mach_port_mod_refs(mach_task_self(),
						exc_port,
						MACH_PORT_RIGHT_SEND,
						-0x7000);
			if (kr != KERN_SUCCESS) {
				MACH3_DEBUG(1, kr,
					    ("osfmach3_trap_forward: "
					     "mach_port_mod_refs(0x%x)",
					     exc_port));
			}
			user_trap_port_refs -= 0x7000;
		}
		current->osfmach3.thread->exception_completed = FALSE;
		return;
	}
	/*
	 * A debugger has changed the exception port because it expects
	 * to intercept this type of exception. Forward the exception.
	 */
	switch (exc_behavior) {
	    case EXCEPTION_DEFAULT:
		current->osfmach3.thread->exception_completed = TRUE;
		server_thread_blocking(FALSE);
		kr = exception_raise(exc_port,
				     thread_port,
				     task_port,
				     exc_type,
				     code,
				     code_count);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "exception_raise(0x%x, 0x%x)",
				     exc_port, exc_type));
			break;
		}
		server_thread_blocking(FALSE);
		kr = thread_get_state(thread_port,
				      *flavor,
				      old_state,
				      icnt);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "thread_get_state(0x%x) [1]",
				     thread_port));
		}
		break;

	    case EXCEPTION_STATE:
		if (exc_flavor != *flavor) {
			printk("osfmach3_trap_forward: "
			       "can't forward exception_state - "
			       "got flavor 0x%x, want 0x%x\n",
			       *flavor, exc_flavor);
			current->osfmach3.thread->exception_completed = FALSE;
			break;
		}
		current->osfmach3.thread->exception_completed = TRUE;
		server_thread_blocking(FALSE);
		kr = exception_raise_state(exc_port,
					   exc_type,
					   code,
					   code_count,
					   flavor,
					   old_state,
					   *icnt,
					   new_state,
					   ocnt);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "exception_raise_state(0x%x, 0x%x)",
				     exc_port, exc_type));
		}
		break;

	    case EXCEPTION_STATE_IDENTITY:
		if (exc_flavor != *flavor) {
			printk("osfmach3_trap_forward: "
			       "can't forward exception_state_identity - "
			       "got flavor 0x%x, want 0x%x\n",
			       *flavor, exc_flavor);
			current->osfmach3.thread->exception_completed = FALSE;
			break;
		}
		current->osfmach3.thread->exception_completed = TRUE;
		server_thread_blocking(FALSE);
		kr = exception_raise_state_identity(exc_port,
						    thread_port,
						    task_port,
						    exc_type,
						    code,
						    code_count,
						    flavor,
						    old_state,
						    *icnt,
						    new_state,
						    ocnt);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "exception_raise_state_identity"
				     "(0x%x, 0x%x)",
				     exc_port, exc_type));
		}
		break;

	    default:
		printk("osfmach3_trap_forward: "
		       "unknown behavior 0x%x for task exception 0x%x\n",
		       exc_behavior, exc_type);
		current->osfmach3.thread->exception_completed = FALSE;
		break;
	}

	if (exc_port != MACH_PORT_NULL) {
		kr = mach_port_deallocate(mach_task_self(), exc_port);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "mach_port_deallocate(0x%x)",
				     exc_port));
		}
	}
}
Example #10
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);
}
Example #11
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);
}
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;
}
Example #13
0
int main(int argc, char *argv[])
{
	posix_spawnattr_t       attrs;
	kern_return_t           kr;
	mach_port_t             task = mach_task_self();

	mach_msg_type_number_t  maskCount = 1;
	exception_mask_t        mask;
	exception_handler_t     handler;
	exception_behavior_t    behavior;
	thread_state_flavor_t   flavor;
	pthread_t               exception_thread;
	uint64_t                exc_id;
	unsigned int            exc_fd;

	char *test_prog_name = "./guarded_test";
	char *child_args[MAX_ARGV];
	char test_id[MAX_TEST_ID_LEN];
	int i, err;
	int child_status;
	int test_status = 0;

	/* 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: %#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);
	}

	/* Get Current exception ports */
	if ((kr = task_get_exception_ports(task, EXC_MASK_GUARD, &mask,
					&maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) {
		fprintf(stderr,"task_get_exception_ports: %#x\n", 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);
	}

	pthread_detach(exception_thread);

	/* 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);
	}

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

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

		child_args[0] = test_prog_name;
		sprintf(&test_id[0], "%d", i);
		child_args[1] = &test_id[0];
		child_args[2] = NULL;

		/* Fork and exec child */
		if (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_GUARD, handler,
						EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
			fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
			exit(1);
		} 

		/* Wait for child and check for exception */
		if (-1 == wait4(-1, &child_status, 0, NULL)) {
			exit(1);
		}

		exc_fd = (unsigned int) (exception_code & (uint64_t)EXC_GUARD_FD_MASK);
		exc_id = exception_code & ~((uint64_t)EXC_GUARD_FD_MASK);
		printf("EXC_GUARD Received: ");
		(exception_code != 0)?printf("Yes (Code 0x%llx)\n", exception_code):printf("No\n");
		printf("Test Result: ");
		if((WIFEXITED(child_status) && WEXITSTATUS(child_status)) ||
			(exc_id != test_exception_code[i]) ||
			(test_fd[i] && exc_fd != (unsigned int)TEST_FD)) {
				test_status = 1;
				printf("FAILED\n");
		}
		else {
			printf("PASSED\n");
		}
		printf("-------------------\n");

	}

	exit(test_status);
}