/* * Return the current thread's audit record, if any. */ struct kaudit_record * currecord(void) { return (curthread()->uu_ar); }
/* ARGSUSED */ int audit(proc_t p, struct audit_args *uap, __unused int32_t *retval) { int error; void * rec; struct kaudit_record *ar; struct uthread *uthr; error = suser(kauth_cred_get(), &p->p_acflag); if (error) return (error); mtx_lock(&audit_mtx); if ((uap->length <= 0) || (uap->length > (int)audit_qctrl.aq_bufsz)) { mtx_unlock(&audit_mtx); return (EINVAL); } mtx_unlock(&audit_mtx); ar = currecord(); /* * If there's no current audit record (audit() itself not audited) * commit the user audit record. */ if (ar == NULL) { uthr = curthread(); if (uthr == NULL) /* can this happen? */ return (ENOTSUP); /* * This is not very efficient; we're required to allocate a * complete kernel audit record just so the user record can * tag along. */ uthr->uu_ar = audit_new(AUE_NULL, p, uthr); if (uthr->uu_ar == NULL) return (ENOTSUP); ar = uthr->uu_ar; } if (uap->length > MAX_AUDIT_RECORD_SIZE) return (EINVAL); rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); error = copyin(uap->record, rec, uap->length); if (error) goto free_out; #if CONFIG_MACF error = mac_system_check_audit(kauth_cred_get(), rec, uap->length); if (error) goto free_out; #endif /* Verify the record. */ if (bsm_rec_verify(rec) == 0) { error = EINVAL; goto free_out; } /* * Attach the user audit record to the kernel audit record. Because * this system call is an auditable event, we will write the user * record along with the record for this audit event. * * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, * k_ar_commit & AR_COMMIT_USER? */ ar->k_udata = rec; ar->k_ulen = uap->length; ar->k_ar_commit |= AR_COMMIT_USER; /* * Currently we assume that all preselection has been performed in * userspace. We unconditionally set these masks so that the records * get committed both to the trail and pipe. In the future we will * want to setup kernel based preselection. */ ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); return (0); free_out: /* * audit_syscall_exit() will free the audit record on the thread even * if we allocated it above. */ free(rec, M_AUDITDATA); return (error); }