+#if CONFIG_MACF
+/*
+ * kauth_cred_label_update
+ *
+ * Description: Update the MAC label associated with a credential
+ *
+ * Parameters: cred The original credential
+ * label The MAC label to set
+ *
+ * Returns: (kauth_cred_t) The updated credential
+ *
+ * IMPORTANT: This function is implemented via kauth_cred_update(), which,
+ * if it returns a credential other than the one it is passed,
+ * will have dropped the reference on the passed credential. All
+ * callers should be aware of this, and treat this function as an
+ * unref + ref, potentially on different credentials.
+ *
+ * Because of this, the caller is expected to take its own
+ * reference on the credential passed as the first parameter,
+ * and be prepared to release the reference on the credential
+ * that is returned to them, if it is not intended to be a
+ * persistent reference.
+ */
+kauth_cred_t
+kauth_cred_label_update(kauth_cred_t cred, struct label *label)
+{
+ kauth_cred_t newcred;
+ struct ucred temp_cred;
+
+ bcopy(cred, &temp_cred, sizeof(temp_cred));
+
+ mac_cred_label_init(&temp_cred);
+ mac_cred_label_associate(cred, &temp_cred);
+ mac_cred_label_update(&temp_cred, label);
+
+ newcred = kauth_cred_update(cred, &temp_cred, TRUE);
+ mac_cred_label_destroy(&temp_cred);
+ return (newcred);
+}
+
+/*
+ * kauth_cred_label_update_execve
+ *
+ * Description: Update the MAC label associated with a credential as
+ * part of exec
+ *
+ * Parameters: cred The original credential
+ * vp The exec vnode
+ * scriptl The script MAC label
+ * execl The executable MAC label
+ * disjointp Pointer to flag to set if old
+ * and returned credentials are
+ * disjoint
+ *
+ * Returns: (kauth_cred_t) The updated credential
+ *
+ * Implicit returns:
+ * *disjointp Set to 1 for disjoint creds
+ *
+ * IMPORTANT: This function is implemented via kauth_cred_update(), which,
+ * if it returns a credential other than the one it is passed,
+ * will have dropped the reference on the passed credential. All
+ * callers should be aware of this, and treat this function as an
+ * unref + ref, potentially on different credentials.
+ *
+ * Because of this, the caller is expected to take its own
+ * reference on the credential passed as the first parameter,
+ * and be prepared to release the reference on the credential
+ * that is returned to them, if it is not intended to be a
+ * persistent reference.
+ */
+static
+kauth_cred_t
+kauth_cred_label_update_execve(kauth_cred_t cred, vfs_context_t ctx,
+ struct vnode *vp, struct label *scriptl, struct label *execl,
+ int *disjointp)
+{
+ kauth_cred_t newcred;
+ struct ucred temp_cred;
+
+ bcopy(cred, &temp_cred, sizeof(temp_cred));
+
+ mac_cred_label_init(&temp_cred);
+ mac_cred_label_associate(cred, &temp_cred);
+ *disjointp = mac_cred_label_update_execve(ctx, &temp_cred,
+ vp, scriptl, execl);
+
+ newcred = kauth_cred_update(cred, &temp_cred, TRUE);
+ mac_cred_label_destroy(&temp_cred);
+ return (newcred);
+}
+
+/*
+ * kauth_proc_label_update
+ *
+ * Description: Update the label inside the credential associated with the process.
+ *
+ * Parameters: p The process to modify
+ * label The label to place in the process credential
+ *
+ * Notes: The credential associated with the process may change as a result
+ * of this call. The caller should not assume the process reference to
+ * the old credential still exists.
+ */
+int kauth_proc_label_update(struct proc *p, struct label *label)
+{
+ kauth_cred_t my_cred, my_new_cred;
+
+ my_cred = kauth_cred_proc_ref(p);
+
+ DEBUG_CRED_ENTER("kauth_proc_label_update: %p\n", my_cred);
+
+ /* get current credential and take a reference while we muck with it */
+ for (;;) {
+
+ /*
+ * Set the credential with new info. If there is no change,
+ * we get back the same credential we passed in; if there is
+ * a change, we drop the reference on the credential we
+ * passed in. The subsequent compare is safe, because it is
+ * a pointer compare rather than a contents compare.
+ */
+ my_new_cred = kauth_cred_label_update(my_cred, label);
+ if (my_cred != my_new_cred) {
+
+ DEBUG_CRED_CHANGE("kauth_proc_setlabel_unlocked CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
+
+ proc_lock(p);
+ /*
+ * We need to protect for a race where another thread
+ * also changed the credential after we took our
+ * reference. If p_ucred has changed then we should
+ * restart this again with the new cred.
+ */
+ if (p->p_ucred != my_cred) {
+ proc_unlock(p);
+ kauth_cred_unref(&my_new_cred);
+ my_cred = kauth_cred_proc_ref(p);
+ /* try again */
+ continue;
+ }
+ p->p_ucred = my_new_cred;
+ mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
+ proc_unlock(p);
+ }
+ break;
+ }
+ /* Drop old proc reference or our extra reference */
+ kauth_cred_unref(&my_cred);
+
+ return (0);
+}
+
+/*
+ * kauth_proc_label_update_execve
+ *
+ * Description: Update the label inside the credential associated with the
+ * process as part of a transitioning execve. The label will
+ * be updated by the policies as part of this processing, not
+ * provided up front.
+ *
+ * Parameters: p The process to modify
+ * ctx The context of the exec
+ * vp The vnode being exec'ed
+ * scriptl The script MAC label
+ * execl The executable MAC label
+ *
+ * Returns: 0 Label update did not make credential
+ * disjoint
+ * 1 Label update caused credential to be
+ * disjoint
+ *
+ * Notes: The credential associated with the process WILL change as a
+ * result of this call. The caller should not assume the process
+ * reference to the old credential still exists.
+ */
+int
+kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx,
+ struct vnode *vp, struct label *scriptl, struct label *execl)
+{
+ kauth_cred_t my_cred, my_new_cred;
+ int disjoint = 0;
+
+ my_cred = kauth_cred_proc_ref(p);
+
+ DEBUG_CRED_ENTER("kauth_proc_label_update_execve: %p\n", my_cred);
+
+ /* get current credential and take a reference while we muck with it */
+ for (;;) {
+
+ /*
+ * Set the credential with new info. If there is no change,
+ * we get back the same credential we passed in; if there is
+ * a change, we drop the reference on the credential we
+ * passed in. The subsequent compare is safe, because it is
+ * a pointer compare rather than a contents compare.
+ */
+ my_new_cred = kauth_cred_label_update_execve(my_cred, ctx, vp, scriptl, execl, &disjoint);
+ if (my_cred != my_new_cred) {
+
+ DEBUG_CRED_CHANGE("kauth_proc_label_update_execve_unlocked CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
+
+ proc_lock(p);
+ /*
+ * We need to protect for a race where another thread
+ * also changed the credential after we took our
+ * reference. If p_ucred has changed then we should
+ * restart this again with the new cred.
+ */
+ if (p->p_ucred != my_cred) {
+ proc_unlock(p);
+ kauth_cred_unref(&my_new_cred);
+ my_cred = kauth_cred_proc_ref(p);
+ /* try again */
+ continue;
+ }
+ p->p_ucred = my_new_cred;
+ mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
+ proc_unlock(p);
+ }
+ break;
+ }
+ /* Drop old proc reference or our extra reference */
+ kauth_cred_unref(&my_cred);
+
+ return (disjoint);
+}
+
+#if 1