/* * 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; mach_port_name_t tret = MACH_PORT_NULL; ipc_port_t tfpport; void * sright; int error = 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 *)&t1, 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) { (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t)); AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE); return(KERN_FAILURE); } p = proc_find(pid); if (p == PROC_NULL) { error = KERN_FAILURE; goto tfpout; } #if CONFIG_AUDIT AUDIT_ARG(process, p); #endif if (!(task_for_pid_posix_check(p))) { error = KERN_FAILURE; goto tfpout; } if (p->task != TASK_NULL) { /* If we aren't root and target's task access port is set... */ if (!kauth_cred_issuser(kauth_cred_get()) && p != current_proc() && (task_get_task_access_port(p->task, &tfpport) == 0) && (tfpport != IPC_PORT_NULL)) { if (tfpport == IPC_PORT_DEAD) { error = KERN_PROTECTION_FAILURE; goto tfpout; } /* Call up to the task access server */ error = check_task_access(tfpport, proc_selfpid(), kauth_getgid(), pid); if (error != MACH_MSG_SUCCESS) { if (error == MACH_RCV_INTERRUPTED) error = KERN_ABORTED; else error = KERN_FAILURE; goto tfpout; } } #if CONFIG_MACF error = mac_proc_check_get_task(kauth_cred_get(), p); if (error) { error = KERN_FAILURE; goto tfpout; } #endif /* Grant task port access */ task_reference(p->task); extmod_statistics_incr_task_for_pid(p->task); sright = (void *) convert_task_to_port(p->task); tret = ipc_port_copyout_send( sright, get_task_ipcspace(current_task())); } error = KERN_SUCCESS; tfpout: task_deallocate(t1); AUDIT_ARG(mach_port2, tret); (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t)); if (p != PROC_NULL) proc_rele(p); AUDIT_MACH_SYSCALL_EXIT(error); return(error); }
int pipe_stat(struct pipe *cpipe, void *ub, int isstat64) { #if CONFIG_MACF int error; #endif int pipe_size = 0; int pipe_count; struct stat *sb = (struct stat *)0; /* warning avoidance ; protected by isstat64 */ struct stat64 * sb64 = (struct stat64 *)0; /* warning avoidance ; protected by isstat64 */ if (cpipe == NULL) return (EBADF); PIPE_LOCK(cpipe); #if CONFIG_MACF error = mac_pipe_check_stat(kauth_cred_get(), cpipe); if (error) { PIPE_UNLOCK(cpipe); return (error); } #endif if (cpipe->pipe_buffer.buffer == 0) { /* must be stat'ing the write fd */ if (cpipe->pipe_peer) { /* the peer still exists, use it's info */ pipe_size = MAX_PIPESIZE(cpipe->pipe_peer); pipe_count = cpipe->pipe_peer->pipe_buffer.cnt; } else { pipe_count = 0; } } else { pipe_size = MAX_PIPESIZE(cpipe); pipe_count = cpipe->pipe_buffer.cnt; } /* * since peer's buffer is setup ouside of lock * we might catch it in transient state */ if (pipe_size == 0) pipe_size = MAX(PIPE_SIZE, pipesize_blocks[0]); if (isstat64 != 0) { sb64 = (struct stat64 *)ub; bzero(sb64, sizeof(*sb64)); sb64->st_mode = S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; sb64->st_blksize = pipe_size; sb64->st_size = pipe_count; sb64->st_blocks = (sb64->st_size + sb64->st_blksize - 1) / sb64->st_blksize; sb64->st_uid = kauth_getuid(); sb64->st_gid = kauth_getgid(); sb64->st_atimespec.tv_sec = cpipe->st_atimespec.tv_sec; sb64->st_atimespec.tv_nsec = cpipe->st_atimespec.tv_nsec; sb64->st_mtimespec.tv_sec = cpipe->st_mtimespec.tv_sec; sb64->st_mtimespec.tv_nsec = cpipe->st_mtimespec.tv_nsec; sb64->st_ctimespec.tv_sec = cpipe->st_ctimespec.tv_sec; sb64->st_ctimespec.tv_nsec = cpipe->st_ctimespec.tv_nsec; /* * Return a relatively unique inode number based on the current * address of this pipe's struct pipe. This number may be recycled * relatively quickly. */ sb64->st_ino = (ino64_t)VM_KERNEL_ADDRPERM((uintptr_t)cpipe); } else { sb = (struct stat *)ub; bzero(sb, sizeof(*sb)); sb->st_mode = S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; sb->st_blksize = pipe_size; sb->st_size = pipe_count; sb->st_blocks = (sb->st_size + sb->st_blksize - 1) / sb->st_blksize; sb->st_uid = kauth_getuid(); sb->st_gid = kauth_getgid(); sb->st_atimespec.tv_sec = cpipe->st_atimespec.tv_sec; sb->st_atimespec.tv_nsec = cpipe->st_atimespec.tv_nsec; sb->st_mtimespec.tv_sec = cpipe->st_mtimespec.tv_sec; sb->st_mtimespec.tv_nsec = cpipe->st_mtimespec.tv_nsec; sb->st_ctimespec.tv_sec = cpipe->st_ctimespec.tv_sec; sb->st_ctimespec.tv_nsec = cpipe->st_ctimespec.tv_nsec; /* * Return a relatively unique inode number based on the current * address of this pipe's struct pipe. This number may be recycled * relatively quickly. */ sb->st_ino = (ino_t)VM_KERNEL_ADDRPERM((uintptr_t)cpipe); } PIPE_UNLOCK(cpipe); /* * POSIX: Left as 0: st_dev, st_nlink, st_rdev, st_flags, st_gen, * st_uid, st_gid. * * XXX (st_dev) should be unique, but there is no device driver that * XXX is associated with pipes, since they are implemented via a * XXX struct fileops indirection rather than as FS objects. */ return (0); }
/* * 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. * * 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; struct uthread *uthread; proc_t p = PROC_NULL; task_t t1 = TASK_NULL; mach_port_name_t tret = MACH_PORT_NULL; ipc_port_t tfpport; void * sright; int error = 0; AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID); AUDIT_ARG(pid, pid); AUDIT_ARG(mach_port1, target_tport); #if defined(SECURE_KERNEL) if (0 == pid) { (void ) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t)); AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE); return(KERN_FAILURE); } #endif t1 = port_name_to_task(target_tport); if (t1 == TASK_NULL) { (void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t)); AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE); return(KERN_FAILURE); } /* * Delayed binding of thread credential to process credential, if we * are not running with an explicitly set thread credential. */ uthread = get_bsdthread_info(current_thread()); kauth_cred_uthread_update(uthread, current_proc()); p = proc_find(pid); AUDIT_ARG(process, p); if (!(task_for_pid_posix_check(p))) { error = KERN_FAILURE; goto tfpout; } if (p->task != TASK_NULL) { /* If we aren't root and target's task access port is set... */ if (!kauth_cred_issuser(kauth_cred_get()) && p != current_proc() && (task_get_task_access_port(p->task, &tfpport) == 0) && (tfpport != IPC_PORT_NULL)) { if (tfpport == IPC_PORT_DEAD) { error = KERN_PROTECTION_FAILURE; goto tfpout; } /* Call up to the task access server */ error = check_task_access(tfpport, proc_selfpid(), kauth_getgid(), pid); if (error != MACH_MSG_SUCCESS) { if (error == MACH_RCV_INTERRUPTED) error = KERN_ABORTED; else error = KERN_FAILURE; goto tfpout; } } #if CONFIG_MACF error = mac_proc_check_get_task(kauth_cred_get(), p); if (error) { error = KERN_FAILURE; goto tfpout; } #endif /* Grant task port access */ task_reference(p->task); sright = (void *) convert_task_to_port(p->task); tret = ipc_port_copyout_send( sright, get_task_ipcspace(current_task())); } error = KERN_SUCCESS; tfpout: task_deallocate(t1); AUDIT_ARG(mach_port2, tret); (void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t)); if (p != PROC_NULL) proc_rele(p); AUDIT_MACH_SYSCALL_EXIT(error); return(error); }