/* Start a new audit session if this has been enabled. */ static gpg_error_t start_audit_session (ctrl_t ctrl) { audit_release (ctrl->audit); ctrl->audit = NULL; if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) ) return gpg_error_from_syserror (); return 0; }
/* ARGSUSED */ int audit(struct thread *td, struct audit_args *uap) { int error; void * rec; struct kaudit_record *ar; if (jailed(td->td_ucred)) return (ENOSYS); error = priv_check(td, PRIV_AUDIT_SUBMIT); if (error) return (error); if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz)) return (EINVAL); ar = currecord(); /* * If there's no current audit record (audit() itself not audited) * commit the user audit record. */ if (ar == NULL) { /* * This is not very efficient; we're required to allocate a * complete kernel audit record just so the user record can * tag along. * * XXXAUDIT: Maybe AUE_AUDIT in the system call context and * special pre-select handling? */ td->td_ar = audit_new(AUE_NULL, td); if (td->td_ar == NULL) return (ENOTSUP); td->td_pflags |= TDP_AUDITREC; ar = td->td_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; /* Verify the record. */ if (bsm_rec_verify(rec) == 0) { error = EINVAL; goto free_out; } #ifdef MAC error = mac_system_check_audit(td->td_ucred, rec, uap->length); if (error) goto free_out; #endif /* * 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); }
/* * audit_syscall_enter() is called on entry to each system call. It is * responsible for deciding whether or not to audit the call (preselection), * and if so, allocating a per-thread audit record. audit_new() will fill in * basic thread/credential properties. */ void audit_syscall_enter(unsigned short code, struct thread *td) { struct au_mask *aumask; au_class_t class; au_event_t event; au_id_t auid; KASSERT(td->td_ar == NULL, ("audit_syscall_enter: td->td_ar != NULL")); KASSERT((td->td_pflags & TDP_AUDITREC) == 0, ("audit_syscall_enter: TDP_AUDITREC set")); /* * In FreeBSD, each ABI has its own system call table, and hence * mapping of system call codes to audit events. Convert the code to * an audit event identifier using the process system call table * reference. In Darwin, there's only one, so we use the global * symbol for the system call table. No audit record is generated * for bad system calls, as no operation has been performed. */ if (code >= td->td_proc->p_sysent->sv_size) return; event = td->td_proc->p_sysent->sv_table[code].sy_auevent; if (event == AUE_NULL) return; /* * Check which audit mask to use; either the kernel non-attributable * event mask or the process audit mask. */ auid = td->td_ucred->cr_audit.ai_auid; if (auid == AU_DEFAUDITID) aumask = &audit_nae_mask; else aumask = &td->td_ucred->cr_audit.ai_mask; /* * Allocate an audit record, if preselection allows it, and store in * the thread for later use. */ class = au_event_class(event); if (au_preselect(event, class, aumask, AU_PRS_BOTH)) { /* * If we're out of space and need to suspend unprivileged * processes, do that here rather than trying to allocate * another audit record. * * Note: we might wish to be able to continue here in the * future, if the system recovers. That should be possible * by means of checking the condition in a loop around * cv_wait(). It might be desirable to reevaluate whether an * audit record is still required for this event by * re-calling au_preselect(). */ if (audit_in_failure && priv_check(td, PRIV_AUDIT_FAILSTOP) != 0) { cv_wait(&audit_fail_cv, &audit_mtx); panic("audit_failing_stop: thread continued"); } td->td_ar = audit_new(event, td); if (td->td_ar != NULL) td->td_pflags |= TDP_AUDITREC; } else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) {
/* * audit_syscall_enter() is called on entry to each system call. It is * responsible for deciding whether or not to audit the call (preselection), * and if so, allocating a per-thread audit record. audit_new() will fill in * basic thread/credential properties. */ void audit_syscall_enter(unsigned int code, proc_t proc, struct uthread *uthread) { struct au_mask *aumask; au_class_t class; au_event_t event; au_id_t auid; kauth_cred_t cred; /* * In FreeBSD, each ABI has its own system call table, and hence * mapping of system call codes to audit events. Convert the code to * an audit event identifier using the process system call table * reference. In Darwin, there's only one, so we use the global * symbol for the system call table. No audit record is generated * for bad system calls, as no operation has been performed. * * In Mac OS X, the audit events are stored in a table seperate from * the syscall table(s). This table is generated by makesyscalls.sh * from syscalls.master and stored in audit_kevents.c. */ if (code > NUM_SYSENT) return; event = sys_au_event[code]; if (event == AUE_NULL) return; KASSERT(uthread->uu_ar == NULL, ("audit_syscall_enter: uthread->uu_ar != NULL")); /* * Check which audit mask to use; either the kernel non-attributable * event mask or the process audit mask. */ cred = kauth_cred_proc_ref(proc); auid = cred->cr_audit.as_aia_p->ai_auid; if (auid == AU_DEFAUDITID) aumask = &audit_nae_mask; else aumask = &cred->cr_audit.as_mask; /* * Allocate an audit record, if preselection allows it, and store in * the thread for later use. */ class = au_event_class(event); #if CONFIG_MACF /* * Note: audit_mac_syscall_enter() may call audit_new() and allocate * memory for the audit record (uu_ar). */ if (audit_mac_syscall_enter(code, proc, uthread, cred, event) == 0) goto out; #endif if (au_preselect(event, class, aumask, AU_PRS_BOTH)) { /* * If we're out of space and need to suspend unprivileged * processes, do that here rather than trying to allocate * another audit record. * * Note: we might wish to be able to continue here in the * future, if the system recovers. That should be possible * by means of checking the condition in a loop around * cv_wait(). It might be desirable to reevaluate whether an * audit record is still required for this event by * re-calling au_preselect(). */ if (audit_in_failure && suser(cred, &proc->p_acflag) != 0) { cv_wait(&audit_fail_cv, &audit_mtx); panic("audit_failing_stop: thread continued"); } if (uthread->uu_ar == NULL) uthread->uu_ar = audit_new(event, proc, uthread); } else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) {
* future, if the system recovers. That should be possible * by means of checking the condition in a loop around * cv_wait(). It might be desirable to reevaluate whether an * audit record is still required for this event by * re-calling au_preselect(). */ if (audit_in_failure && suser(cred, &proc->p_acflag) != 0) { cv_wait(&audit_fail_cv, &audit_mtx); panic("audit_failing_stop: thread continued"); } if (uthread->uu_ar == NULL) uthread->uu_ar = audit_new(event, proc, uthread); } else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) { if (uthread->uu_ar == NULL) uthread->uu_ar = audit_new(event, proc, uthread); } out: kauth_cred_unref(&cred); } /* * audit_syscall_exit() is called from the return of every system call, or in * the event of exit1(), during the execution of exit1(). It is responsible * for committing the audit record, if any, along with return condition. * * Note: The audit_syscall_exit() parameter list was modified to support * mac_audit_check_postselect(), which requires the syscall number. */ #if CONFIG_MACF
/* 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); }