+/*
+ * Routine: task_inspect_for_pid
+ * Purpose:
+ * Get the task inspect port for another "process", named by its
+ * process ID on the same host as "target_task".
+ */
+int
+task_inspect_for_pid(struct proc *p __unused, struct task_inspect_for_pid_args *args, int *ret)
+{
+ mach_port_name_t target_tport = args->target_tport;
+ int pid = args->pid;
+ user_addr_t task_addr = args->t;
+
+ proc_t proc = PROC_NULL;
+ task_t t1 = TASK_NULL;
+ task_inspect_t task_insp = TASK_INSPECT_NULL;
+ mach_port_name_t tret = MACH_PORT_NULL;
+ ipc_port_t tfpport = MACH_PORT_NULL;
+ int error = 0;
+ void *sright = NULL;
+ boolean_t is_current_proc = FALSE;
+ struct proc_ident pident = {0};
+
+ /* Disallow inspect port for kernel_task */
+ if (pid == 0) {
+ (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
+ return EPERM;
+ }
+
+ t1 = port_name_to_task(target_tport);
+ if (t1 == TASK_NULL) {
+ (void) copyout((char *) &t1, task_addr, sizeof(mach_port_name_t));
+ return EINVAL;
+ }
+
+ proc = proc_find(pid);
+ if (proc == PROC_NULL) {
+ error = ESRCH;
+ goto tifpout;
+ }
+ pident = proc_ident(proc);
+ is_current_proc = (proc == current_proc());
+
+ if (!(task_for_pid_posix_check(proc))) {
+ error = EPERM;
+ goto tifpout;
+ }
+
+ task_insp = proc->task;
+ if (task_insp == TASK_INSPECT_NULL) {
+ goto tifpout;
+ }
+
+ /*
+ * Grab a task reference and drop the proc reference before making any upcalls.
+ */
+ task_reference(task_insp);
+
+ proc_rele(proc);
+ proc = PROC_NULL;
+
+ /*
+ * For now, it performs the same set of permission checks as task_for_pid. This
+ * will be addressed in rdar://problem/53478660
+ */
+#if CONFIG_MACF
+ error = mac_proc_check_get_task(kauth_cred_get(), &pident);
+ if (error) {
+ error = EPERM;
+ goto tifpout;
+ }
+#endif
+
+ /* If we aren't root and target's task access port is set... */
+ if (!kauth_cred_issuser(kauth_cred_get()) &&
+ !is_current_proc &&
+ (task_get_task_access_port(task_insp, &tfpport) == 0) &&
+ (tfpport != IPC_PORT_NULL)) {
+ if (tfpport == IPC_PORT_DEAD) {
+ error = EACCES;
+ goto tifpout;
+ }
+
+
+ /* Call up to the task access server */
+ error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport, proc_selfpid(), kauth_getgid(), pid);
+
+ if (error != MACH_MSG_SUCCESS) {
+ if (error == MACH_RCV_INTERRUPTED) {
+ error = EINTR;
+ } else {
+ error = EPERM;
+ }
+ goto tifpout;
+ }
+ }
+
+ /* Check if the task has been corpsified */
+ if (is_corpsetask(task_insp)) {
+ error = EACCES;
+ goto tifpout;
+ }
+
+ /* could be IP_NULL, consumes a ref */
+ sright = (void*) convert_task_inspect_to_port(task_insp);
+ task_insp = TASK_INSPECT_NULL;
+ tret = ipc_port_copyout_send(sright, get_task_ipcspace(current_task()));
+
+tifpout:
+ task_deallocate(t1);
+ (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
+ if (proc != PROC_NULL) {
+ proc_rele(proc);
+ }
+ if (tfpport != IPC_PORT_NULL) {
+ ipc_port_release_send(tfpport);
+ }
+ if (task_insp != TASK_INSPECT_NULL) {
+ task_deallocate(task_insp);
+ }
+
+ *ret = error;
+ return error;
+}
+
+/*
+ * Routine: task_read_for_pid
+ * Purpose:
+ * Get the task read port for another "process", named by its
+ * process ID on the same host as "target_task".
+ */
+int
+task_read_for_pid(struct proc *p __unused, struct task_read_for_pid_args *args, int *ret)
+{
+ mach_port_name_t target_tport = args->target_tport;
+ int pid = args->pid;
+ user_addr_t task_addr = args->t;
+
+ proc_t proc = PROC_NULL;
+ task_t t1 = TASK_NULL;
+ task_read_t task_read = TASK_READ_NULL;
+ mach_port_name_t tret = MACH_PORT_NULL;
+ ipc_port_t tfpport = MACH_PORT_NULL;
+ int error = 0;
+ void *sright = NULL;
+ boolean_t is_current_proc = FALSE;
+ struct proc_ident pident = {0};
+
+ /* Disallow read port for kernel_task */
+ if (pid == 0) {
+ (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
+ return EPERM;
+ }
+
+ t1 = port_name_to_task(target_tport);
+ if (t1 == TASK_NULL) {
+ (void) copyout((char *) &t1, task_addr, sizeof(mach_port_name_t));
+ return EINVAL;
+ }
+
+ proc = proc_find(pid);
+ if (proc == PROC_NULL) {
+ error = ESRCH;
+ goto trfpout;
+ }
+ pident = proc_ident(proc);
+ is_current_proc = (proc == current_proc());
+
+ if (!(task_for_pid_posix_check(proc))) {
+ error = EPERM;
+ goto trfpout;
+ }
+
+ task_read = proc->task;
+ if (task_read == TASK_INSPECT_NULL) {
+ goto trfpout;
+ }
+
+ /*
+ * Grab a task reference and drop the proc reference before making any upcalls.
+ */
+ task_reference(task_read);
+
+ proc_rele(proc);
+ proc = PROC_NULL;
+
+ /*
+ * For now, it performs the same set of permission checks as task_for_pid. This
+ * will be addressed in rdar://problem/53478660
+ */
+#if CONFIG_MACF
+ error = mac_proc_check_get_task(kauth_cred_get(), &pident);
+ if (error) {
+ error = EPERM;
+ goto trfpout;
+ }
+#endif
+
+ /* If we aren't root and target's task access port is set... */
+ if (!kauth_cred_issuser(kauth_cred_get()) &&
+ !is_current_proc &&
+ (task_get_task_access_port(task_read, &tfpport) == 0) &&
+ (tfpport != IPC_PORT_NULL)) {
+ if (tfpport == IPC_PORT_DEAD) {
+ error = EACCES;
+ goto trfpout;
+ }
+
+
+ /* Call up to the task access server */
+ error = __KERNEL_WAITING_ON_TASKGATED_CHECK_ACCESS_UPCALL__(tfpport, proc_selfpid(), kauth_getgid(), pid);
+
+ if (error != MACH_MSG_SUCCESS) {
+ if (error == MACH_RCV_INTERRUPTED) {
+ error = EINTR;
+ } else {
+ error = EPERM;
+ }
+ goto trfpout;
+ }
+ }
+
+ /* Check if the task has been corpsified */
+ if (is_corpsetask(task_read)) {
+ error = EACCES;
+ goto trfpout;
+ }
+
+ /* could be IP_NULL, consumes a ref */
+ sright = (void*) convert_task_read_to_port(task_read);
+ task_read = TASK_READ_NULL;
+ tret = ipc_port_copyout_send(sright, get_task_ipcspace(current_task()));
+
+trfpout:
+ task_deallocate(t1);
+ (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
+ if (proc != PROC_NULL) {
+ proc_rele(proc);
+ }
+ if (tfpport != IPC_PORT_NULL) {
+ ipc_port_release_send(tfpport);
+ }
+ if (task_read != TASK_READ_NULL) {
+ task_deallocate(task_read);
+ }
+
+ *ret = error;
+ return error;
+}
+