]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/security/audit/audit_worker.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / bsd / security / audit / audit_worker.c
index d307a7eb9a0d34b8674abcf941816cc4b255c321..85b5c8241bc1cff5fc77eec9229397e9f472eaae 100644 (file)
@@ -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.
  *
 
 #include <kern/host.h>
 #include <kern/zalloc.h>
-#include <kern/lock.h>
 #include <kern/sched_prim.h>
 #include <kern/task.h>
-#include <kern/wait_queue.h>
 
 #include <net/route.h>
 
@@ -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.
         */