Task-port access and authorization

bsd/kern/kern_proc.c · 6754 lines · browse source

task_for_pid checks process credentials and task-port policy, applies MAC checks when configured, and may wait for an authorization reply from the task access server. The POSIX check alone does not determine whether a debugger receives a control port.

Related official documentation: Debugger entitlement · Resolving common notarization issues (get-task-allow)

task_for_pid_posix_check source
Routine: task_for_pid_posix_check Purpose: Verify that the current process should be allowed to get the target process's task port. This is only permitted if: - The current process is root OR all of the following are true: - The target process's real, effective, and saved uids are the same as the current proc's euid, - The target process's group set is a subset of the calling process's group set, and - The target process hasn't switched credentials. Returns: TRUE: permitted FALSE: denied
static int
task_for_pid_posix_check(proc_t target)
{
	kauth_cred_t targetcred, mycred;
	bool checkcredentials;
	uid_t myuid;
	int allowed;

	/* No task_for_pid on bad targets */
	if (target->p_stat == SZOMB) {
		return FALSE;
	}

	mycred = kauth_cred_get();
	myuid = kauth_cred_getuid(mycred);

	/* If we're running as root, the check passes */
	if (kauth_cred_issuser(mycred)) {
		return TRUE;
	}

	/* We're allowed to get our own task port */
	if (target == current_proc()) {
		return TRUE;
	}

	/*
	 * Under DENY, only root can get another proc's task port,
	 * so no more checks are needed.
	 */
… more in source
task_for_pid source · task_for_pid reference
Routine: task_for_pid Purpose: Get the task port for another "process", named by its process ID on the same host as "target_task". Only permitted to privileged processes, or processes with the same user ID. Note: if pid == 0, an error is return no matter who is calling. XXX This should be a BSD system call, not a Mach trap!!!
kern_return_t
task_for_pid(
	struct task_for_pid_args *args)
{
	mach_port_name_t        target_tport = args->target_tport;
	int                     pid = args->pid;
	user_addr_t             task_addr = args->t;
	proc_t                  p = PROC_NULL;
	task_t                  t1 = TASK_NULL;
	task_t                  task = TASK_NULL;
	mach_port_name_t        tret = MACH_PORT_NULL;
	ipc_port_t              tfpport = MACH_PORT_NULL;
	void                    * sright = NULL;
	int                     error = 0;
	boolean_t               is_current_proc = FALSE;
	struct proc_ident       pident = {0};

	AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID);
	AUDIT_ARG(pid, pid);
	AUDIT_ARG(mach_port1, target_tport);

	/* Always check if pid == 0 */
	if (pid == 0) {
		(void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
		AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
		return KERN_FAILURE;
	}

	t1 = port_name_to_task(target_tport);
	if (t1 == TASK_NULL) {
… more in source