+ /*
+ * BORROW PARENT TASK, THREAD, UTHREAD FOR CHILD
+ *
+ * Note: this is where we would "push" state instead of setting
+ * it for nested vfork() support (see proc_vfork_end() for
+ * description if issues here).
+ */
+ child_proc->task = parent_proc->task;
+
+ child_proc->p_lflag |= P_LINVFORK;
+ child_proc->p_vforkact = parent_thread;
+ child_proc->p_stat = SRUN;
+
+ parent_uthread->uu_flag |= UT_VFORK;
+ parent_uthread->uu_proc = child_proc;
+ parent_uthread->uu_userstate = (void *)act_thread_csave();
+ parent_uthread->uu_vforkmask = parent_uthread->uu_sigmask;
+
+ /* temporarily drop thread-set-id state */
+ if (parent_uthread->uu_flag & UT_SETUID) {
+ parent_uthread->uu_flag |= UT_WASSETUID;
+ parent_uthread->uu_flag &= ~UT_SETUID;
+ }
+
+ /* blow thread state information */
+ /* XXX is this actually necessary, given syscall return? */
+ thread_set_child(parent_thread, child_proc->p_pid);
+
+ child_proc->p_acflag = AFORK; /* forked but not exec'ed */
+
+ /*
+ * Preserve synchronization semantics of vfork. If
+ * waiting for child to exec or exit, set P_PPWAIT
+ * on child, and sleep on our proc (in case of exit).
+ */
+ child_proc->p_lflag |= P_LPPWAIT;
+ pinsertchild(parent_proc, child_proc); /* set visible */
+
+ break;
+
+ case PROC_CREATE_SPAWN:
+ /*
+ * A spawned process differs from a forked process in that
+ * the spawned process does not carry around the parents
+ * baggage with regard to address space copying, dtrace,
+ * and so on.
+ */
+ spawn = 1;
+
+ /* FALLSTHROUGH */
+
+ case PROC_CREATE_FORK:
+ /*
+ * When we clone the parent process, we are going to inherit
+ * its task attributes and memory, since when we fork, we
+ * will, in effect, create a duplicate of it, with only minor
+ * differences. Contrarily, spawned processes do not inherit.
+ */
+ if ((child_thread = cloneproc(parent_proc->task, parent_proc, spawn ? FALSE : TRUE)) == NULL) {
+ /* Failed to create thread */
+ err = EAGAIN;
+ goto bad;
+ }
+
+ /* copy current thread state into the child thread (only for fork) */
+ if (!spawn) {
+ thread_dup(child_thread);
+ }
+
+ /* child_proc = child_thread->task->proc; */
+ child_proc = (proc_t)(get_bsdtask_info(get_threadtask(child_thread)));
+
+// XXX BEGIN: wants to move to be common code (and safe)
+#if CONFIG_MACF
+ /*
+ * allow policies to associate the credential/label that
+ * we referenced from the parent ... with the child
+ * JMM - this really isn't safe, as we can drop that
+ * association without informing the policy in other
+ * situations (keep long enough to get policies changed)
+ */
+ mac_cred_label_associate_fork(child_proc->p_ucred, child_proc);
+#endif
+
+ /*
+ * Propogate change of PID - may get new cred if auditing.
+ *
+ * NOTE: This has no effect in the vfork case, since
+ * child_proc->task != current_task(), but we duplicate it
+ * because this is probably, ultimately, wrong, since we
+ * will be running in the "child" which is the parent task
+ * with the wrong token until we get to the execve() or
+ * _exit() call; a lot of "undefined" can happen before
+ * that.
+ *
+ * <rdar://6640530> disallow everything but exeve()/_exit()?
+ */
+ set_security_token(child_proc);
+
+ AUDIT_ARG(pid, child_proc->p_pid);
+
+// XXX END: wants to move to be common code (and safe)
+
+ /*
+ * Blow thread state information; this is what gives the child
+ * process its "return" value from a fork() call.
+ *
+ * Note: this should probably move to fork() proper, since it
+ * is not relevent to spawn, and the value won't matter
+ * until we resume the child there. If you are in here
+ * refactoring code, consider doing this at the same time.
+ */
+ thread_set_child(child_thread, child_proc->p_pid);
+
+ child_proc->p_acflag = AFORK; /* forked but not exec'ed */
+
+// <rdar://6598155> dtrace code cleanup needed
+#if CONFIG_DTRACE
+ /*
+ * This code applies to new processes who are copying the task
+ * and thread state and address spaces of their parent process.
+ */
+ if (!spawn) {
+// <rdar://6598155> call dtrace specific function here instead of all this...
+ /*
+ * APPLE NOTE: Solaris does a sprlock() and drops the
+ * proc_lock here. We're cheating a bit and only taking
+ * the p_dtrace_sprlock lock. A full sprlock would
+ * task_suspend the parent.
+ */
+ lck_mtx_lock(&parent_proc->p_dtrace_sprlock);
+
+ /*
+ * Remove all DTrace tracepoints from the child process. We
+ * need to do this _before_ duplicating USDT providers since
+ * any associated probes may be immediately enabled.
+ */
+ if (parent_proc->p_dtrace_count > 0) {
+ dtrace_fasttrap_fork(parent_proc, child_proc);
+ }
+
+ lck_mtx_unlock(&parent_proc->p_dtrace_sprlock);
+
+ /*
+ * Duplicate any lazy dof(s). This must be done while NOT
+ * holding the parent sprlock! Lock ordering is
+ * dtrace_dof_mode_lock, then sprlock. It is imperative we
+ * always call dtrace_lazy_dofs_duplicate, rather than null
+ * check and call if !NULL. If we NULL test, during lazy dof
+ * faulting we can race with the faulting code and proceed
+ * from here to beyond the helpers copy. The lazy dof
+ * faulting will then fail to copy the helpers to the child
+ * process.
+ */
+ dtrace_lazy_dofs_duplicate(parent_proc, child_proc);
+
+ /*
+ * Duplicate any helper actions and providers. The SFORKING
+ * we set above informs the code to enable USDT probes that
+ * sprlock() may fail because the child is being forked.
+ */
+ /*
+ * APPLE NOTE: As best I can tell, Apple's sprlock() equivalent
+ * never fails to find the child. We do not set SFORKING.
+ */
+ if (parent_proc->p_dtrace_helpers != NULL && dtrace_helpers_fork) {
+ (*dtrace_helpers_fork)(parent_proc, child_proc);
+ }
+
+ }
+#endif /* CONFIG_DTRACE */
+
+ break;
+
+ default:
+ panic("fork1 called with unknown kind %d", kind);
+ break;
+ }