- 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;
+ /*
+ * 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.
+ */
+ for (;;) {
+ kauth_cred_t my_cred, 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.
+ */
+ 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_rele(my_cred);
+ kauth_cred_rele(my_new_cred);
+ /* try again */
+ continue;
+ }
+ tp->p_ucred = my_new_cred;
+ proc_unlock(tp);
+ }
+ /* drop our extra reference */
+ kauth_cred_rele(my_cred);
+ break;
+ }