X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b0d623f7f2ae71ed96e60569f61f9a9a27016e80..eee3565979933af707c711411001ba11fe406a3c:/bsd/security/audit/audit_worker.c diff --git a/bsd/security/audit/audit_worker.c b/bsd/security/audit/audit_worker.c index d307a7eb9..85b5c8241 100644 --- a/bsd/security/audit/audit_worker.c +++ b/bsd/security/audit/audit_worker.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2008 Apple Inc. + * Copyright (c) 1999-2016 Apple Inc. * Copyright (c) 2006-2008 Robert N. M. Watson * All rights reserved. * @@ -68,10 +68,8 @@ #include #include -#include #include #include -#include #include @@ -105,10 +103,10 @@ static struct vnode *audit_vp; #define AUDIT_WORKER_SX_DESTROY() slck_destroy(&audit_worker_sl) /* - * The audit_draining flag is set when audit is disabled and the audit + * The audit_q_draining flag is set when audit is disabled and the audit * worker queue is being drained. */ -static int audit_draining; +static int audit_q_draining; /* * The special kernel audit record, audit_drain_kar, is used to mark the end of @@ -203,16 +201,11 @@ audit_record_write(struct vnode *vp, struct vfs_context *ctx, void *data, */ if (audit_qctrl.aq_minfree != 0) { temp = mnt_stat->f_blocks / (100 / audit_qctrl.aq_minfree); - if (mnt_stat->f_bfree < temp) { - if (ppsratecheck(&last_lowspace_trigger, - &cur_lowspace_trigger, 1)) { + if (mnt_stat->f_bfree < temp && + ppsratecheck(&last_lowspace_trigger, + &cur_lowspace_trigger, 1)) (void)audit_send_trigger( AUDIT_TRIGGER_LOW_SPACE); - printf("Warning: audit space low (< %d%% free)" - "on audit log file-system\n", - audit_qctrl.aq_minfree); - } - } } /* @@ -358,7 +351,8 @@ audit_worker_process_record(struct kaudit_record *ar) if (!(ar->k_ar_commit & AR_COMMIT_KERNEL) || ((ar->k_ar_commit & AR_PRESELECT_PIPE) == 0 && - (ar->k_ar_commit & AR_PRESELECT_TRAIL) == 0)) + (ar->k_ar_commit & AR_PRESELECT_TRAIL) == 0 && + (ar->k_ar_commit & AR_PRESELECT_FILTER) == 0)) goto out; auid = ar->k_ar.ar_subj_auid; @@ -395,6 +389,16 @@ audit_worker_process_record(struct kaudit_record *ar) ar->k_ar_commit & AR_PRESELECT_TRAIL, bsm->data, bsm->len); + if (ar->k_ar_commit & AR_PRESELECT_FILTER) { + + /* + * XXXss - This needs to be generalized so new filters can + * be easily plugged in. + */ + audit_sdev_submit(auid, ar->k_ar.ar_subj_asid, bsm->data, + bsm->len); + } + kau_free(bsm); out: if (trail_locked) @@ -410,6 +414,7 @@ out: * Note: this means that the effect bound on the size of the pending record * queue is 2x the length of the global queue. */ +__attribute__((noreturn)) static void audit_worker(void) { @@ -417,7 +422,9 @@ audit_worker(void) struct kaudit_record *ar; int lowater_signal; - audit_ctx.vc_thread = current_thread(); + if (audit_ctx.vc_thread == NULL) + audit_ctx.vc_thread = current_thread(); + TAILQ_INIT(&ar_worklist); mtx_lock(&audit_mtx); while (1) { @@ -427,7 +434,8 @@ audit_worker(void) * Wait for a record. */ while (TAILQ_EMPTY(&audit_q)) - cv_wait(&audit_worker_cv, &audit_mtx); + cv_wait_continuation(&audit_worker_cv, &audit_mtx, + (thread_continue_t)audit_worker); /* * If there are records in the global audit record queue, @@ -451,7 +459,7 @@ audit_worker(void) while ((ar = TAILQ_FIRST(&ar_worklist))) { TAILQ_REMOVE(&ar_worklist, ar, k_q); if (ar->k_ar_commit & AR_DRAIN_QUEUE) { - audit_draining = 0; + audit_q_draining = 0; cv_broadcast(&audit_drain_cv); } else { audit_worker_process_record(ar); @@ -476,51 +484,54 @@ audit_rotate_vnode(kauth_cred_t cred, struct vnode *vp) { kauth_cred_t old_audit_cred; struct vnode *old_audit_vp; - int audit_was_enabled; KASSERT((cred != NULL && vp != NULL) || (cred == NULL && vp == NULL), ("audit_rotate_vnode: cred %p vp %p", cred, vp)); - /* - * Rotate the vnode/cred, and clear the rotate flag so that we will - * send a rotate trigger if the new file fills. - */ - AUDIT_WORKER_SX_XLOCK(); - old_audit_cred = audit_ctx.vc_ucred; - old_audit_vp = audit_vp; - audit_ctx.vc_ucred = cred; - audit_file_rotate_wait = 0; - audit_was_enabled = audit_enabled; - if ((audit_enabled = (NULL != vp))) - audit_vp = vp; - audit_draining = (audit_was_enabled && !audit_enabled); - AUDIT_WORKER_SX_XUNLOCK(); - /* - * If audit (was enabled and) is now disabled then drain the audit - * record queue and wait until it is done. - */ mtx_lock(&audit_mtx); - if (audit_draining) { + if (audit_enabled && (NULL == vp)) { + /* Auditing is currently enabled but will be disabled. */ + + /* + * Disable auditing now so nothing more is added while the + * audit worker thread is draining the audit record queue. + */ + audit_enabled = 0; + /* - * Insert the special drain record in the queue. + * Drain the auditing queue by inserting a drain record at the + * end of the queue and waiting for the audit worker thread + * to find this record and signal that it is done before + * we close the audit trail. */ + audit_q_draining = 1; while (audit_q_len >= audit_qctrl.aq_hiwater) cv_wait(&audit_watermark_cv, &audit_mtx); TAILQ_INSERT_TAIL(&audit_q, &audit_drain_kar, k_q); audit_q_len++; cv_signal(&audit_worker_cv); - - /* - * Wait for the audit worker thread to signal it is done. - */ - while (audit_draining) - cv_wait(&audit_drain_cv, &audit_mtx); - - audit_vp = NULL; } + + /* If the audit queue is draining then wait here until it's done. */ + while (audit_q_draining) + cv_wait(&audit_drain_cv, &audit_mtx); mtx_unlock(&audit_mtx); + + /* + * Rotate the vnode/cred, and clear the rotate flag so that we will + * send a rotate trigger if the new file fills. + */ + AUDIT_WORKER_SX_XLOCK(); + old_audit_cred = audit_ctx.vc_ucred; + old_audit_vp = audit_vp; + audit_ctx.vc_ucred = cred; + audit_vp = vp; + audit_file_rotate_wait = 0; + audit_enabled = (audit_vp != NULL); + AUDIT_WORKER_SX_XUNLOCK(); + /* * If there was an old vnode/credential, close and free. */