- if (udata.au_aupinfo.ap_pid < 1)
- return (EINVAL);
- if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
- return (EINVAL);
-
- tp->p_au->ai_mask.am_success =
- udata.au_aupinfo.ap_mask.am_success;
- tp->p_au->ai_mask.am_failure =
- udata.au_aupinfo.ap_mask.am_failure;
+ if (udata.au_aupinfo.ap_pid < 1) {
+ ret = EINVAL;
+ break;
+ }
+ if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
+ ret = EINVAL;
+ break;
+ }
+
+ /*
+ * we are modifying the audit info in a credential so we need a new
+ * credential (or take another reference on an existing credential that
+ * matches our new one). We must do this because the audit info in the
+ * credential is used as part of our hash key. Get current credential
+ * in the target process and take a reference while we muck with it.
+ */
+ lck_mtx_unlock(audit_mtx);
+ for (;;) {
+ kauth_cred_t my_new_cred;
+ struct auditinfo temp_auditinfo;
+
+ my_cred = kauth_cred_proc_ref(tp);
+ /*
+ * 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.
+ */
+ temp_auditinfo = my_cred->cr_au;
+ temp_auditinfo.ai_mask.am_success =
+ udata.au_aupinfo.ap_mask.am_success;
+ temp_auditinfo.ai_mask.am_failure =
+ udata.au_aupinfo.ap_mask.am_failure;
+ my_new_cred = kauth_cred_setauditinfo(my_cred, &temp_auditinfo);
+
+ if (my_cred != my_new_cred) {
+ proc_lock(tp);
+ /* 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 (tp->p_ucred != my_cred) {
+ proc_unlock(tp);
+ kauth_cred_unref(&my_new_cred);
+ /* try again */
+ continue;
+ }
+ tp->p_ucred = my_new_cred;
+ proc_unlock(tp);
+ }
+ /* drop old proc reference or our extra reference */
+ kauth_cred_unref(&my_cred);
+ break;
+ }
+ proc_rele(tp);
+ lck_mtx_lock(audit_mtx);