+ /*
+ * Until UT_VFORKING is cleared at the end of the vfork
+ * syscall, the process identity of this thread is slightly
+ * murky.
+ *
+ * As long as UT_VFORK and it's associated field (uu_proc)
+ * is set, current_proc() will always return the child process.
+ *
+ * However dtrace_proc_selfpid() returns the parent pid to
+ * ensure that e.g. the proc:::create probe actions accrue
+ * to the parent. (Otherwise the child magically seems to
+ * have created itself!)
+ */
+ parent_uthread->uu_flag |= UT_VFORK | UT_VFORKING;
+ 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,
+ spawn ? coalitions : NULL,
+ parent_proc,
+ spawn ? FALSE : TRUE,
+ FALSE)) == 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);