/* * cloneproc * * Description: Create a new process from a specified process. * * Parameters: parent_task The parent task to be cloned, or * TASK_NULL is task characteristics * are not to be inherited * be cloned, or TASK_NULL if the new * task is not to inherit the VM * characteristics of the parent * parent_proc The parent process to be cloned * inherit_memory True if the child is to inherit * memory from the parent; if this is * non-NULL, then the parent_task must * also be non-NULL * memstat_internal Whether to track the process in the * jetsam priority list (if configured) * * Returns: !NULL pointer to new child thread * NULL Failure (unspecified) * * Note: On return newly created child process has signal lock held * to block delivery of signal to it if called with lock set. * fork() code needs to explicity remove this lock before * signals can be delivered * * In the case of bootstrap, this function can be called from * bsd_utaskbootstrap() in order to bootstrap the first process; * the net effect is to provide a uthread structure for the * kernel process associated with the kernel task. * * XXX: Tristating using the value parent_task as the major key * and inherit_memory as the minor key is something we should * refactor later; we owe the current semantics, ultimately, * to the semantics of task_create_internal. For now, we will * live with this being somewhat awkward. */ thread_t cloneproc(task_t parent_task, coalition_t *parent_coalitions, proc_t parent_proc, int inherit_memory, int memstat_internal) { #if !CONFIG_MEMORYSTATUS #pragma unused(memstat_internal) #endif task_t child_task; proc_t child_proc; thread_t child_thread = NULL; if ((child_proc = forkproc(parent_proc)) == NULL) { /* Failed to allocate new process */ goto bad; } child_thread = fork_create_child(parent_task, parent_coalitions, child_proc, inherit_memory, (parent_task == TASK_NULL) ? FALSE : (parent_proc->p_flag & P_LP64)); if (child_thread == NULL) { /* * Failed to create thread; now we must deconstruct the new * process previously obtained from forkproc(). */ forkproc_free(child_proc); goto bad; } child_task = get_threadtask(child_thread); if (parent_proc->p_flag & P_LP64) { task_set_64bit(child_task, TRUE); OSBitOrAtomic(P_LP64, (UInt32 *)&child_proc->p_flag); } else { task_set_64bit(child_task, FALSE); OSBitAndAtomic(~((uint32_t)P_LP64), (UInt32 *)&child_proc->p_flag); } #if CONFIG_MEMORYSTATUS if (memstat_internal) { proc_list_lock(); child_proc->p_memstat_state |= P_MEMSTAT_INTERNAL; proc_list_unlock(); } #endif /* make child visible */ pinsertchild(parent_proc, child_proc); /* * Make child runnable, set start time. */ child_proc->p_stat = SRUN; bad: return(child_thread); }
/* * cloneproc * * Description: Create a new process from a specified process. * * Parameters: parent_task The parent task to be cloned, or * TASK_NULL is task characteristics * are not to be inherited * be cloned, or TASK_NULL if the new * task is not to inherit the VM * characteristics of the parent * parent_proc The parent process to be cloned * inherit_memory True if the child is to inherit * memory from the parent; if this is * non-NULL, then the parent_task must * also be non-NULL * * Returns: !NULL pointer to new child thread * NULL Failure (unspecified) * * Note: On return newly created child process has signal lock held * to block delivery of signal to it if called with lock set. * fork() code needs to explicity remove this lock before * signals can be delivered * * In the case of bootstrap, this function can be called from * bsd_utaskbootstrap() in order to bootstrap the first process; * the net effect is to provide a uthread structure for the * kernel process associated with the kernel task. * * XXX: Tristating using the value parent_task as the major key * and inherit_memory as the minor key is something we should * refactor later; we owe the current semantics, ultimately, * to the semantics of task_create_internal. For now, we will * live with this being somewhat awkward. */ thread_t cloneproc(task_t parent_task, proc_t parent_proc, int inherit_memory) { task_t child_task; proc_t child_proc; thread_t child_thread = NULL; if ((child_proc = forkproc(parent_proc)) == NULL) { /* Failed to allocate new process */ goto bad; } child_thread = fork_create_child(parent_task, child_proc, inherit_memory, (parent_task == TASK_NULL) ? FALSE : (parent_proc->p_flag & P_LP64)); if (child_thread == NULL) { /* * Failed to create thread; now we must deconstruct the new * process previously obtained from forkproc(). */ forkproc_free(child_proc); goto bad; } child_task = get_threadtask(child_thread); if (parent_proc->p_flag & P_LP64) { task_set_64bit(child_task, TRUE); OSBitOrAtomic(P_LP64, (UInt32 *)&child_proc->p_flag); #ifdef __ppc__ /* * PPC51: ppc64 is limited to 51-bit addresses. * Memory above that limit is handled specially at * the pmap level. */ pmap_map_sharedpage(child_task, get_map_pmap(get_task_map(child_task))); #endif /* __ppc__ */ } else { task_set_64bit(child_task, FALSE); OSBitAndAtomic(~((uint32_t)P_LP64), (UInt32 *)&child_proc->p_flag); } /* make child visible */ pinsertchild(parent_proc, child_proc); /* * Make child runnable, set start time. */ child_proc->p_stat = SRUN; bad: return(child_thread); }
__private_extern__ boolean_t chudxnu_thread_set_marked(thread_t thread, boolean_t new_value) { boolean_t old_val; if(thread) { if(new_value) { // set the marked bit old_val = OSBitOrAtomic(T_CHUD_MARKED, &(thread->t_chud)); } else { // clear the marked bit old_val = OSBitAndAtomic(~T_CHUD_MARKED, &(thread->t_chud)); } return (old_val & T_CHUD_MARKED) == T_CHUD_MARKED; } return FALSE; }
/* * cloneproc * * Description: Create a new process from a specified process. * * Parameters: parent_task The parent task to be cloned, or * TASK_NULL is task characteristics * are not to be inherited * be cloned, or TASK_NULL if the new * task is not to inherit the VM * characteristics of the parent * parent_proc The parent process to be cloned * inherit_memory True if the child is to inherit * memory from the parent; if this is * non-NULL, then the parent_task must * also be non-NULL * * Returns: !NULL pointer to new child thread * NULL Failure (unspecified) * * Note: On return newly created child process has signal lock held * to block delivery of signal to it if called with lock set. * fork() code needs to explicity remove this lock before * signals can be delivered * * In the case of bootstrap, this function can be called from * bsd_utaskbootstrap() in order to bootstrap the first process; * the net effect is to provide a uthread structure for the * kernel process associated with the kernel task. * * XXX: Tristating using the value parent_task as the major key * and inherit_memory as the minor key is something we should * refactor later; we owe the current semantics, ultimately, * to the semantics of task_create_internal. For now, we will * live with this being somewhat awkward. */ thread_t cloneproc(task_t parent_task, proc_t parent_proc, int inherit_memory) { task_t child_task; proc_t child_proc; thread_t child_thread = NULL; if ((child_proc = forkproc(parent_proc)) == NULL) { /* Failed to allocate new process */ goto bad; } child_thread = fork_create_child(parent_task, child_proc, inherit_memory, (parent_task == TASK_NULL) ? FALSE : (parent_proc->p_flag & P_LP64)); if (child_thread == NULL) { /* * Failed to create thread; now we must deconstruct the new * process previously obtained from forkproc(). */ forkproc_free(child_proc); goto bad; } child_task = get_threadtask(child_thread); if (parent_proc->p_flag & P_LP64) { task_set_64bit(child_task, TRUE); OSBitOrAtomic(P_LP64, (UInt32 *)&child_proc->p_flag); } else { task_set_64bit(child_task, FALSE); OSBitAndAtomic(~((uint32_t)P_LP64), (UInt32 *)&child_proc->p_flag); } /* make child visible */ pinsertchild(parent_proc, child_proc); /* * Make child runnable, set start time. */ child_proc->p_stat = SRUN; bad: return(child_thread); }
int cttyioctl(__unused dev_t dev, u_long cmd, caddr_t addr, int flag, proc_t p) { vnode_t ttyvp = cttyvp(current_proc()); struct vfs_context context; struct session *sessp; int error = 0; if (ttyvp == NULL) return (EIO); if (cmd == TIOCSCTTY) { /* don't allow controlling tty to be set */ error = EINVAL; /* to controlling tty -- infinite recursion */ goto out; } if (cmd == TIOCNOTTY) { sessp = proc_session(p); if (!SESS_LEADER(p, sessp)) { OSBitAndAtomic(~((uint32_t)P_CONTROLT), &p->p_flag); if (sessp != SESSION_NULL) session_rele(sessp); error = 0; goto out; } else { if (sessp != SESSION_NULL) session_rele(sessp); error = EINVAL; goto out; } } context.vc_thread = current_thread(); context.vc_ucred = NOCRED; error = VNOP_IOCTL(ttyvp, cmd, addr, flag, &context); out: vnode_put(ttyvp); return (error); }
static int vfs_unmount_9p(mount_t mp, int mntflags, __unused vfs_context_t ctx) { mount_9p *nmp; vnode_t vp; int e, flags; TRACE(); nmp = MTO9P(mp); flags = 0; if(ISSET(mntflags,MNT_FORCE)) SET(flags, FORCECLOSE); OSBitOrAtomic(F_UNMOUNTING, &nmp->flags); vp = nmp->root; if ((e=vflush(mp, vp, flags))) goto error; if (vnode_isinuse(vp, 1) && !ISSET(flags, FORCECLOSE)) { e = EBUSY; goto error; } clunk_9p(nmp, NTO9P(vp)->fid); vnode_rele(vp); vflush(mp, NULL, FORCECLOSE); vfs_setfsprivate(mp, NULL); disconnect_9p(nmp); cancelrpcs_9p(nmp); freemount_9p(nmp); return 0; error: OSBitAndAtomic(~F_UNMOUNTING, &nmp->flags); return e; }
/* * shared_region_map_np() * * This system call is intended for dyld. * * dyld uses this to map a shared cache file into a shared region. * This is usually done only the first time a shared cache is needed. * Subsequent processes will just use the populated shared region without * requiring any further setup. */ int shared_region_map_np( struct proc *p, struct shared_region_map_np_args *uap, __unused int *retvalp) { int error; kern_return_t kr; int fd; struct fileproc *fp; struct vnode *vp, *root_vp; struct vnode_attr va; off_t fs; memory_object_size_t file_size; user_addr_t user_mappings; struct shared_file_mapping_np *mappings; #define SFM_MAX_STACK 8 struct shared_file_mapping_np stack_mappings[SFM_MAX_STACK]; unsigned int mappings_count; vm_size_t mappings_size; memory_object_control_t file_control; struct vm_shared_region *shared_region; SHARED_REGION_TRACE_DEBUG( ("shared_region: %p [%d(%s)] -> map\n", current_thread(), p->p_pid, p->p_comm)); shared_region = NULL; mappings_count = 0; mappings_size = 0; mappings = NULL; fp = NULL; vp = NULL; /* get file descriptor for shared region cache file */ fd = uap->fd; /* get file structure from file descriptor */ error = fp_lookup(p, fd, &fp, 0); if (error) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map: " "fd=%d lookup failed (error=%d)\n", current_thread(), p->p_pid, p->p_comm, fd, error)); goto done; } /* make sure we're attempting to map a vnode */ if (fp->f_fglob->fg_type != DTYPE_VNODE) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map: " "fd=%d not a vnode (type=%d)\n", current_thread(), p->p_pid, p->p_comm, fd, fp->f_fglob->fg_type)); error = EINVAL; goto done; } /* we need at least read permission on the file */ if (! (fp->f_fglob->fg_flag & FREAD)) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map: " "fd=%d not readable\n", current_thread(), p->p_pid, p->p_comm, fd)); error = EPERM; goto done; } /* get vnode from file structure */ error = vnode_getwithref((vnode_t) fp->f_fglob->fg_data); if (error) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map: " "fd=%d getwithref failed (error=%d)\n", current_thread(), p->p_pid, p->p_comm, fd, error)); goto done; } vp = (struct vnode *) fp->f_fglob->fg_data; /* make sure the vnode is a regular file */ if (vp->v_type != VREG) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "not a file (type=%d)\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name, vp->v_type)); error = EINVAL; goto done; } /* make sure vnode is on the process's root volume */ root_vp = p->p_fd->fd_rdir; if (root_vp == NULL) { root_vp = rootvnode; } if (vp->v_mount != root_vp->v_mount) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "not on process's root volume\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name)); error = EPERM; goto done; } /* make sure vnode is owned by "root" */ VATTR_INIT(&va); VATTR_WANTED(&va, va_uid); error = vnode_getattr(vp, &va, vfs_context_current()); if (error) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "vnode_getattr(%p) failed (error=%d)\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name, vp, error)); goto done; } if (va.va_uid != 0) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "owned by uid=%d instead of 0\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name, va.va_uid)); error = EPERM; goto done; } /* get vnode size */ error = vnode_size(vp, &fs, vfs_context_current()); if (error) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "vnode_size(%p) failed (error=%d)\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name, vp, error)); goto done; } file_size = fs; /* get the file's memory object handle */ file_control = ubc_getobject(vp, UBC_HOLDOBJECT); if (file_control == MEMORY_OBJECT_CONTROL_NULL) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "no memory object\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name)); error = EINVAL; goto done; } /* get the list of mappings the caller wants us to establish */ mappings_count = uap->count; /* number of mappings */ mappings_size = (vm_size_t) (mappings_count * sizeof (mappings[0])); if (mappings_count == 0) { SHARED_REGION_TRACE_INFO( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "no mappings\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name)); error = 0; /* no mappings: we're done ! */ goto done; } else if (mappings_count <= SFM_MAX_STACK) { mappings = &stack_mappings[0]; } else { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "too many mappings (%d)\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name, mappings_count)); error = EINVAL; goto done; } user_mappings = uap->mappings; /* the mappings, in user space */ error = copyin(user_mappings, mappings, mappings_size); if (error) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "copyin(0x%llx, %d) failed (error=%d)\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name, (uint64_t)user_mappings, mappings_count, error)); goto done; } /* get the process's shared region (setup in vm_map_exec()) */ shared_region = vm_shared_region_get(current_task()); if (shared_region == NULL) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "no shared region\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name)); goto done; } /* map the file into that shared region's submap */ kr = vm_shared_region_map_file(shared_region, mappings_count, mappings, file_control, file_size, (void *) p->p_fd->fd_rdir); if (kr != KERN_SUCCESS) { SHARED_REGION_TRACE_ERROR( ("shared_region: %p [%d(%s)] map(%p:'%s'): " "vm_shared_region_map_file() failed kr=0x%x\n", current_thread(), p->p_pid, p->p_comm, vp, vp->v_name, kr)); switch (kr) { case KERN_INVALID_ADDRESS: error = EFAULT; break; case KERN_PROTECTION_FAILURE: error = EPERM; break; case KERN_NO_SPACE: error = ENOMEM; break; case KERN_FAILURE: case KERN_INVALID_ARGUMENT: default: error = EINVAL; break; } goto done; } /* * The mapping was successful. Let the buffer cache know * that we've mapped that file with these protections. This * prevents the vnode from getting recycled while it's mapped. */ (void) ubc_map(vp, VM_PROT_READ); error = 0; /* update the vnode's access time */ if (! (vnode_vfsvisflags(vp) & MNT_NOATIME)) { VATTR_INIT(&va); nanotime(&va.va_access_time); VATTR_SET_ACTIVE(&va, va_access_time); vnode_setattr(vp, &va, vfs_context_current()); } if (p->p_flag & P_NOSHLIB) { /* signal that this process is now using split libraries */ OSBitAndAtomic(~((uint32_t)P_NOSHLIB), (UInt32 *)&p->p_flag); } done: if (vp != NULL) { /* * release the vnode... * ubc_map() still holds it for us in the non-error case */ (void) vnode_put(vp); vp = NULL; } if (fp != NULL) { /* release the file descriptor */ fp_drop(p, fd, fp, 0); fp = NULL; } if (shared_region != NULL) { vm_shared_region_deallocate(shared_region); } SHARED_REGION_TRACE_DEBUG( ("shared_region: %p [%d(%s)] <- map\n", current_thread(), p->p_pid, p->p_comm)); return error; }
/* * Stop profiling on a process. */ void stopprofclock(struct proc *p) { if (p->p_flag & P_PROFIL) OSBitAndAtomic(~((uint32_t)P_PROFIL), (UInt32 *)&p->p_flag); }