]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/security/audit/audit.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / security / audit / audit.c
index c5f18ebe4d8c74ee8d918294a947864b85150aa9..0a3217735733fedeaf89c09d6b2bcca3d874b6d4 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 1999-2009 Apple Inc.
+ * Copyright (c) 1999-2020 Apple Inc.
  * Copyright (c) 2006-2007 Robert N. M. Watson
  * All rights reserved.
  *
@@ -74,7 +74,6 @@
 #include <mach/audit_triggers_server.h>
 
 #include <kern/host.h>
-#include <kern/kalloc.h>
 #include <kern/zalloc.h>
 #include <kern/sched_prim.h>
 
@@ -87,6 +86,7 @@
 MALLOC_DEFINE(M_AUDITDATA, "audit_data", "Audit data storage");
 MALLOC_DEFINE(M_AUDITPATH, "audit_path", "Audit path storage");
 MALLOC_DEFINE(M_AUDITTEXT, "audit_text", "Audit text storage");
+KALLOC_HEAP_DEFINE(KHEAP_AUDIT, "Audit", KHEAP_ID_DEFAULT);
 
 /*
  * Audit control settings that are set/read by system calls and are hence
@@ -94,41 +94,48 @@ MALLOC_DEFINE(M_AUDITTEXT, "audit_text", "Audit text storage");
  *
  * Define the audit control flags.
  */
-int                    audit_enabled;
-int                    audit_suspended;
+int                     audit_enabled;
+int                     audit_suspended;
 
-int                    audit_syscalls;
-au_class_t             audit_kevent_mask;
+int                     audit_syscalls;
+au_class_t              audit_kevent_mask;
+
+/*
+ * The audit control mode is used to ensure configuration settings are only
+ * accepted from appropriate sources based on the current mode.
+ */
+au_ctlmode_t audit_ctl_mode;
+au_expire_after_t audit_expire_after;
 
 /*
  * Flags controlling behavior in low storage situations.  Should we panic if
  * a write fails?  Should we fail stop if we're out of disk space?
  */
-int                    audit_panic_on_write_fail;
-int                    audit_fail_stop;
-int                    audit_argv;
-int                    audit_arge;
+int                     audit_panic_on_write_fail;
+int                     audit_fail_stop;
+int                     audit_argv;
+int                     audit_arge;
 
 /*
  * Are we currently "failing stop" due to out of disk space?
  */
-int                    audit_in_failure;
+int                     audit_in_failure;
 
 /*
  * Global audit statistics.
  */
-struct audit_fstat     audit_fstat;
+struct audit_fstat      audit_fstat;
 
 /*
  * Preselection mask for non-attributable events.
  */
-struct au_mask         audit_nae_mask;
+struct au_mask          audit_nae_mask;
 
 /*
  * Mutex to protect global variables shared between various threads and
  * processes.
  */
-struct mtx             audit_mtx;
+struct mtx              audit_mtx;
 
 /*
  * Queue of audit records ready for delivery to disk.  We insert new records
@@ -138,42 +145,43 @@ struct mtx                audit_mtx;
  * needed to estimate the total size of the combined set of records
  * outstanding in the system.
  */
-struct kaudit_queue    audit_q;
-int                    audit_q_len;
-int                    audit_pre_q_len;
+struct kaudit_queue     audit_q;
+int                     audit_q_len;
+int                     audit_pre_q_len;
 
 /*
  * Audit queue control settings (minimum free, low/high water marks, etc.)
  */
-struct au_qctrl                audit_qctrl;
+struct au_qctrl         audit_qctrl;
 
 /*
  * Condition variable to signal to the worker that it has work to do: either
  * new records are in the queue, or a log replacement is taking place.
  */
-struct cv              audit_worker_cv;
+struct cv               audit_worker_cv;
 
 /*
  * Condition variable to signal when the worker is done draining the audit
  * queue.
  */
-struct cv              audit_drain_cv;
+struct cv               audit_drain_cv;
 
 /*
  * Condition variable to flag when crossing the low watermark, meaning that
  * threads blocked due to hitting the high watermark can wake up and continue
  * to commit records.
  */
-struct cv              audit_watermark_cv;
+struct cv               audit_watermark_cv;
 
 /*
  * Condition variable for  auditing threads wait on when in fail-stop mode.
  * Threads wait on this CV forever (and ever), never seeing the light of day
  * again.
  */
-static struct cv       audit_fail_cv;
+static struct cv        audit_fail_cv;
 
-static zone_t          audit_record_zone;
+static ZONE_DECLARE(audit_record_zone, "audit_zone",
+    sizeof(struct kaudit_record), ZC_NONE);
 
 /*
  * Kernel audit information.  This will store the current audit address
@@ -181,20 +189,19 @@ static zone_t             audit_record_zone;
  * audit records.  This data is modified by the A_GET{SET}KAUDIT auditon(2)
  * command.
  */
-static struct auditinfo_addr   audit_kinfo;
-static struct rwlock           audit_kinfo_lock;
+static struct auditinfo_addr    audit_kinfo;
+static struct rwlock            audit_kinfo_lock;
 
-#define        KINFO_LOCK_INIT()       rw_init(&audit_kinfo_lock,              \
-                                       "audit_kinfo_lock")
-#define        KINFO_RLOCK()           rw_rlock(&audit_kinfo_lock)
-#define KINFO_WLOCK()          rw_wlock(&audit_kinfo_lock)
-#define        KINFO_RUNLOCK()         rw_runlock(&audit_kinfo_lock)
-#define        KINFO_WUNLOCK()         rw_wunlock(&audit_kinfo_lock)
+#define KINFO_LOCK_INIT()       rw_init(&audit_kinfo_lock,              \
+                                       "audit_kinfo_lock")
+#define KINFO_RLOCK()           rw_rlock(&audit_kinfo_lock)
+#define KINFO_WLOCK()           rw_wlock(&audit_kinfo_lock)
+#define KINFO_RUNLOCK()         rw_runlock(&audit_kinfo_lock)
+#define KINFO_WUNLOCK()         rw_wunlock(&audit_kinfo_lock)
 
 void
 audit_set_kinfo(struct auditinfo_addr *ak)
 {
-
        KASSERT(ak->ai_termid.at_type == AU_IPv4 ||
            ak->ai_termid.at_type == AU_IPv6,
            ("audit_set_kinfo: invalid address type"));
@@ -207,7 +214,6 @@ audit_set_kinfo(struct auditinfo_addr *ak)
 void
 audit_get_kinfo(struct auditinfo_addr *ak)
 {
-
        KASSERT(audit_kinfo.ai_termid.at_type == AU_IPv4 ||
            audit_kinfo.ai_termid.at_type == AU_IPv6,
            ("audit_set_kinfo: invalid address type"));
@@ -233,8 +239,8 @@ audit_record_ctor(proc_t p, struct kaudit_record *ar)
                cred = kauth_cred_proc_ref(p);
 
                /*
-                * Export the subject credential.
-                */
+                * Export the subject credential.
+                */
                cru2x(cred, &ar->k_ar.ar_subj_cred);
                ar->k_ar.ar_subj_ruid = kauth_cred_getruid(cred);
                ar->k_ar.ar_subj_rgid = kauth_cred_getrgid(cred);
@@ -243,7 +249,7 @@ audit_record_ctor(proc_t p, struct kaudit_record *ar)
                ar->k_ar.ar_subj_auid = cred->cr_audit.as_aia_p->ai_auid;
                ar->k_ar.ar_subj_asid = cred->cr_audit.as_aia_p->ai_asid;
                bcopy(&cred->cr_audit.as_mask, &ar->k_ar.ar_subj_amask,
-                   sizeof(struct au_mask));
+                   sizeof(struct au_mask));
                bcopy(&cred->cr_audit.as_aia_p->ai_termid,
                    &ar->k_ar.ar_subj_term_addr, sizeof(struct au_tid_addr));
                kauth_cred_unref(&cred);
@@ -253,27 +259,37 @@ audit_record_ctor(proc_t p, struct kaudit_record *ar)
 static void
 audit_record_dtor(struct kaudit_record *ar)
 {
-
-       if (ar->k_ar.ar_arg_upath1 != NULL)
+       if (ar->k_ar.ar_arg_upath1 != NULL) {
                free(ar->k_ar.ar_arg_upath1, M_AUDITPATH);
-       if (ar->k_ar.ar_arg_upath2 != NULL)
+       }
+       if (ar->k_ar.ar_arg_upath2 != NULL) {
                free(ar->k_ar.ar_arg_upath2, M_AUDITPATH);
-       if (ar->k_ar.ar_arg_kpath1 != NULL)
+       }
+       if (ar->k_ar.ar_arg_kpath1 != NULL) {
                free(ar->k_ar.ar_arg_kpath1, M_AUDITPATH);
-       if (ar->k_ar.ar_arg_kpath2 != NULL)
+       }
+       if (ar->k_ar.ar_arg_kpath2 != NULL) {
                free(ar->k_ar.ar_arg_kpath2, M_AUDITPATH);
-       if (ar->k_ar.ar_arg_text != NULL)
+       }
+       if (ar->k_ar.ar_arg_text != NULL) {
                free(ar->k_ar.ar_arg_text, M_AUDITTEXT);
-       if (ar->k_ar.ar_arg_opaque != NULL)
+       }
+       if (ar->k_ar.ar_arg_opaque != NULL) {
                free(ar->k_ar.ar_arg_opaque, M_AUDITDATA);
-       if (ar->k_ar.ar_arg_data != NULL)
+       }
+       if (ar->k_ar.ar_arg_data != NULL) {
                free(ar->k_ar.ar_arg_data, M_AUDITDATA);
-       if (ar->k_udata != NULL)
+       }
+       if (ar->k_udata != NULL) {
                free(ar->k_udata, M_AUDITDATA);
-       if (ar->k_ar.ar_arg_argv != NULL)
+       }
+       if (ar->k_ar.ar_arg_argv != NULL) {
                free(ar->k_ar.ar_arg_argv, M_AUDITTEXT);
-       if (ar->k_ar.ar_arg_envv != NULL)
+       }
+       if (ar->k_ar.ar_arg_envv != NULL) {
                free(ar->k_ar.ar_arg_envv, M_AUDITTEXT);
+       }
+       audit_identity_info_destruct(&ar->k_ar.ar_arg_identity);
 }
 
 /*
@@ -284,7 +300,6 @@ audit_record_dtor(struct kaudit_record *ar)
 void
 audit_init(void)
 {
-
        audit_enabled = 0;
        audit_syscalls = 0;
        audit_kevent_mask = 0;
@@ -294,8 +309,12 @@ audit_init(void)
        audit_in_failure = 0;
        audit_argv = 0;
        audit_arge = 0;
+       audit_ctl_mode = AUDIT_CTLMODE_NORMAL;
+       audit_expire_after.age = 0;
+       audit_expire_after.size = 0;
+       audit_expire_after.op_type = AUDIT_EXPIRE_OP_AND;
 
-       audit_fstat.af_filesz = 0;      /* '0' means unset, unbounded. */
+       audit_fstat.af_filesz = 0;      /* '0' means unset, unbounded. */
        audit_fstat.af_currsz = 0;
        audit_nae_mask.am_success = 0;
        audit_nae_mask.am_failure = 0;
@@ -311,7 +330,6 @@ audit_init(void)
        audit_kinfo.ai_termid.at_type = AU_IPv4;
        audit_kinfo.ai_termid.at_addr[0] = INADDR_ANY;
 
-       _audit_lck_grp_init();
        mtx_init(&audit_mtx, "audit_mtx", NULL, MTX_DEF);
        KINFO_LOCK_INIT();
        cv_init(&audit_worker_cv, "audit_worker_cv");
@@ -319,11 +337,6 @@ audit_init(void)
        cv_init(&audit_watermark_cv, "audit_watermark_cv");
        cv_init(&audit_fail_cv, "audit_fail_cv");
 
-       audit_record_zone = zinit(sizeof(struct kaudit_record),
-           AQ_HIWATER*sizeof(struct kaudit_record), 8192, "audit_zone");
-#if CONFIG_MACF
-       audit_mac_init();
-#endif
        /* Init audit session subsystem. */
        audit_session_init();
 
@@ -347,7 +360,6 @@ audit_init(void)
 void
 audit_shutdown(void)
 {
-
        audit_rotate_vnode(NULL, NULL);
 }
 
@@ -357,8 +369,7 @@ audit_shutdown(void)
 struct kaudit_record *
 currecord(void)
 {
-
-       return (curthread()->uu_ar);
+       return curthread()->uu_ar;
 }
 
 /*
@@ -387,12 +398,13 @@ audit_new(int event, proc_t p, __unused struct uthread *uthread)
        audit_override = (AUE_SESSION_START == event ||
            AUE_SESSION_UPDATE == event || AUE_SESSION_END == event ||
            AUE_SESSION_CLOSE == event);
-       
+
        mtx_lock(&audit_mtx);
        no_record = (audit_suspended || !audit_enabled);
        mtx_unlock(&audit_mtx);
-       if (!audit_override && no_record)
-               return (NULL);
+       if (!audit_override && no_record) {
+               return NULL;
+       }
 
        /*
         * Initialize the audit record header.
@@ -403,8 +415,9 @@ audit_new(int event, proc_t p, __unused struct uthread *uthread)
         * in the kernel.
         */
        ar = zalloc(audit_record_zone);
-       if (ar == NULL)
+       if (ar == NULL) {
                return NULL;
+       }
        audit_record_ctor(p, ar);
        ar->k_ar.ar_event = event;
 
@@ -412,27 +425,28 @@ audit_new(int event, proc_t p, __unused struct uthread *uthread)
        if (PROC_NULL != p) {
                if (audit_mac_new(p, ar) != 0) {
                        zfree(audit_record_zone, ar);
-                       return (NULL);
+                       return NULL;
                }
-       } else
+       } else {
                ar->k_ar.ar_mac_records = NULL;
+       }
 #endif
 
        mtx_lock(&audit_mtx);
        audit_pre_q_len++;
        mtx_unlock(&audit_mtx);
 
-       return (ar);
+       return ar;
 }
 
 void
 audit_free(struct kaudit_record *ar)
 {
-
        audit_record_dtor(ar);
 #if CONFIG_MACF
-       if (NULL != ar->k_ar.ar_mac_records)
+       if (NULL != ar->k_ar.ar_mac_records) {
                audit_mac_free(ar);
+       }
 #endif
        zfree(audit_record_zone, ar);
 }
@@ -447,24 +461,27 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
        struct au_mask *aumask;
        int audit_override;
 
-       if (ar == NULL)
+       if (ar == NULL) {
                return;
+       }
 
        /*
         * Decide whether to commit the audit record by checking the error
         * value from the system call and using the appropriate audit mask.
         */
-       if (ar->k_ar.ar_subj_auid == AU_DEFAUDITID)
+       if (ar->k_ar.ar_subj_auid == AU_DEFAUDITID) {
                aumask = &audit_nae_mask;
-       else
+       } else {
                aumask = &ar->k_ar.ar_subj_amask;
+       }
 
-       if (error)
+       if (error) {
                sorf = AU_PRS_FAILURE;
-       else
+       } else {
                sorf = AU_PRS_SUCCESS;
+       }
 
-       switch(ar->k_ar.ar_event) {
+       switch (ar->k_ar.ar_event) {
        case AUE_OPEN_RWTC:
                /*
                 * The open syscall always writes a AUE_OPEN_RWTC event;
@@ -472,7 +489,7 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
                 * and the error value.
                 */
                ar->k_ar.ar_event = audit_flags_and_error_to_openevent(
-                   ar->k_ar.ar_arg_fflags, error);
+                       ar->k_ar.ar_arg_fflags, error);
                break;
 
        case AUE_OPEN_EXTENDED_RWTC:
@@ -482,7 +499,7 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
                 * event based on the flags and the error value.
                 */
                ar->k_ar.ar_event = audit_flags_and_error_to_openextendedevent(
-                   ar->k_ar.ar_arg_fflags, error);
+                       ar->k_ar.ar_arg_fflags, error);
                break;
 
        case AUE_OPENAT_RWTC:
@@ -492,7 +509,7 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
                 * event based on the flags and the error value.
                 */
                ar->k_ar.ar_event = audit_flags_and_error_to_openatevent(
-                   ar->k_ar.ar_arg_fflags, error);
+                       ar->k_ar.ar_arg_fflags, error);
                break;
 
        case AUE_OPENBYID_RWT:
@@ -502,12 +519,12 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
                 * event based on the flags and the error value.
                 */
                ar->k_ar.ar_event = audit_flags_and_error_to_openbyidevent(
-                   ar->k_ar.ar_arg_fflags, error);
+                       ar->k_ar.ar_arg_fflags, error);
                break;
 
        case AUE_SYSCTL:
                ar->k_ar.ar_event = audit_ctlname_to_sysctlevent(
-                   ar->k_ar.ar_arg_ctlname, ar->k_ar.ar_valid_arg);
+                       ar->k_ar.ar_arg_ctlname, ar->k_ar.ar_valid_arg);
                break;
 
        case AUE_AUDITON:
@@ -518,7 +535,7 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
        case AUE_FCNTL:
                /* Convert some fcntl() commands to their own events. */
                ar->k_ar.ar_event = audit_fcntl_command_event(
-                   ar->k_ar.ar_arg_cmd, ar->k_ar.ar_arg_fflags, error);
+                       ar->k_ar.ar_arg_cmd, ar->k_ar.ar_arg_fflags, error);
                break;
        }
 
@@ -538,11 +555,13 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
            AUE_SESSION_CLOSE == event);
 
        ar->k_ar_commit |= AR_COMMIT_KERNEL;
-       if (au_preselect(event, class, aumask, sorf) != 0)
+       if (au_preselect(event, class, aumask, sorf) != 0) {
                ar->k_ar_commit |= AR_PRESELECT_TRAIL;
+       }
        if (audit_pipe_preselect(auid, event, class, sorf,
-           ar->k_ar_commit & AR_PRESELECT_TRAIL) != 0)
+           ar->k_ar_commit & AR_PRESELECT_TRAIL) != 0) {
                ar->k_ar_commit |= AR_PRESELECT_PIPE;
+       }
        if ((ar->k_ar_commit & (AR_PRESELECT_TRAIL | AR_PRESELECT_PIPE |
            AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE |
            AR_PRESELECT_FILTER)) == 0) {
@@ -573,8 +592,9 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
         * Constrain the number of committed audit records based on the
         * configurable parameter.
         */
-       while (audit_q_len >= audit_qctrl.aq_hiwater)
+       while (audit_q_len >= audit_qctrl.aq_hiwater) {
                cv_wait(&audit_watermark_cv, &audit_mtx);
+       }
 
        TAILQ_INSERT_TAIL(&audit_q, ar, k_q);
        audit_q_len++;
@@ -610,11 +630,13 @@ audit_syscall_enter(unsigned int code, proc_t proc, struct uthread *uthread)
         * the syscall table(s).  This table is generated by makesyscalls.sh
         * from syscalls.master and stored in audit_kevents.c.
         */
-       if (code > NUM_SYSENT)
+       if (code >= nsysent) {
                return;
+       }
        event = sys_au_event[code];
-       if (event == AUE_NULL)
+       if (event == AUE_NULL) {
                return;
+       }
 
        KASSERT(uthread->uu_ar == NULL,
            ("audit_syscall_enter: uthread->uu_ar != NULL"));
@@ -625,10 +647,11 @@ audit_syscall_enter(unsigned int code, proc_t proc, struct uthread *uthread)
         */
        cred = kauth_cred_proc_ref(proc);
        auid = cred->cr_audit.as_aia_p->ai_auid;
-       if (auid == AU_DEFAUDITID) 
+       if (auid == AU_DEFAUDITID) {
                aumask = &audit_nae_mask;
-       else
+       } else {
                aumask = &cred->cr_audit.as_mask;
+       }
 
        /*
         * Allocate an audit record, if preselection allows it, and store in
@@ -640,8 +663,9 @@ audit_syscall_enter(unsigned int code, proc_t proc, struct uthread *uthread)
         * 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)
+       if (audit_mac_syscall_enter(code, proc, uthread, cred, event) == 0) {
                goto out;
+       }
 #endif
        if (au_preselect(event, class, aumask, AU_PRS_BOTH)) {
                /*
@@ -661,12 +685,22 @@ audit_syscall_enter(unsigned int code, proc_t proc, struct uthread *uthread)
                        cv_wait(&audit_fail_cv, &audit_mtx);
                        panic("audit_failing_stop: thread continued");
                }
-               if (uthread->uu_ar == NULL)
+               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)
+               if (uthread->uu_ar == NULL) {
                        uthread->uu_ar = audit_new(event, proc, uthread);
-       } 
+               }
+       }
+
+       /*
+        * All audited events will contain an identity
+        *
+        * Note: Identity should be obtained prior to the syscall implementation
+        * being called to handle cases like execve(2) where the process changes
+        */
+       AUDIT_ARG(identity);
 
 out:
        kauth_cred_unref(&cred);
@@ -698,14 +732,16 @@ audit_syscall_exit(int error, __unsed proc_t proc, struct uthread *uthread)
         * If there was an error, the return value is set to -1, imitating
         * the behavior of the cerror routine.
         */
-       if (error)
+       if (error) {
                retval = -1;
-       else
+       } else {
                retval = uthread->uu_rval[0];
+       }
 
 #if CONFIG_MACF
-       if (audit_mac_syscall_exit(code, uthread, error, retval) != 0)
+       if (audit_mac_syscall_exit(code, uthread, error, retval) != 0) {
                goto out;
+       }
 #endif
        audit_commit(uthread->uu_ar, error, retval);
 
@@ -713,6 +749,77 @@ out:
        uthread->uu_ar = NULL;
 }
 
+/*
+ * For system calls such as posix_spawn(2) the sub operations (i.e., file actions
+ * and port actions) need to be audited as their own events. Like with system
+ * calls we need to determine if the sub operation needs to be audited by
+ * examining preselection masks.
+ */
+void
+audit_subcall_enter(au_event_t event, proc_t proc, struct uthread *uthread)
+{
+       struct au_mask *aumask;
+       au_class_t class;
+       au_id_t auid;
+       kauth_cred_t cred;
+
+       /*
+        * 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 (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)) {
+               if (uthread->uu_ar == NULL) {
+                       uthread->uu_ar = audit_new(event, proc, uthread);
+               }
+       }
+
+       kauth_cred_unref(&cred);
+}
+
+void
+audit_subcall_exit(int error, struct uthread *uthread)
+{
+       /* A subcall doesn't have a return value so always zero. */
+       audit_commit(uthread->uu_ar, error, 0 /* retval */);
+
+       uthread->uu_ar = NULL;
+}
+
 /*
  * Calls to set up and tear down audit structures used during Mach system
  * calls.
@@ -727,16 +834,19 @@ audit_mach_syscall_enter(unsigned short event)
        au_class_t class;
        au_id_t auid;
 
-       if (event == AUE_NULL)
+       if (event == AUE_NULL) {
                return;
+       }
 
        uthread = curthread();
-       if (uthread == NULL)
+       if (uthread == NULL) {
                return;
+       }
 
        proc = current_proc();
-       if (proc == NULL)
+       if (proc == NULL) {
                return;
+       }
 
        KASSERT(uthread->uu_ar == NULL,
            ("audit_mach_syscall_enter: uthread->uu_ar != NULL"));
@@ -748,22 +858,24 @@ audit_mach_syscall_enter(unsigned short event)
         * Check which audit mask to use; either the kernel non-attributable
         * event mask or the process audit mask.
         */
-       if (auid == AU_DEFAUDITID) 
+       if (auid == AU_DEFAUDITID) {
                aumask = &audit_nae_mask;
-       else
+       } else {
                aumask = &cred->cr_audit.as_mask;
+       }
 
        /*
         * Allocate an audit record, if desired, and store in the BSD thread
         * for later use.
         */
        class = au_event_class(event);
-       if (au_preselect(event, class, aumask, AU_PRS_BOTH))
+       if (au_preselect(event, class, aumask, AU_PRS_BOTH)) {
                uthread->uu_ar = audit_new(event, proc, uthread);
-       else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0))
+       } else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) {
                uthread->uu_ar = audit_new(event, proc, uthread);
-       else
+       } else {
                uthread->uu_ar = NULL;
+       }
 
        kauth_cred_unref(&cred);
 }
@@ -788,10 +900,10 @@ audit_mach_syscall_exit(int retval, struct uthread *uthread)
 int
 kau_will_audit(void)
 {
-
-       return (audit_enabled && currecord() != NULL);
+       return audit_enabled && currecord() != NULL;
 }
 
+#if CONFIG_COREDUMP
 void
 audit_proc_coredump(proc_t proc, char *path, int errcode)
 {
@@ -811,23 +923,26 @@ audit_proc_coredump(proc_t proc, char *path, int errcode)
         */
        my_cred = kauth_cred_proc_ref(proc);
        auid = my_cred->cr_audit.as_aia_p->ai_auid;
-       if (auid == AU_DEFAUDITID) 
+       if (auid == AU_DEFAUDITID) {
                aumask = &audit_nae_mask;
-       else
+       } else {
                aumask = &my_cred->cr_audit.as_mask;
+       }
        kauth_cred_unref(&my_cred);
        /*
         * It's possible for coredump(9) generation to fail.  Make sure that
         * we handle this case correctly for preselection.
         */
-       if (errcode != 0)
+       if (errcode != 0) {
                sorf = AU_PRS_FAILURE;
-       else
+       } else {
                sorf = AU_PRS_SUCCESS;
+       }
        class = au_event_class(AUE_CORE);
        if (au_preselect(AUE_CORE, class, aumask, sorf) == 0 &&
-           audit_pipe_preselect(auid, AUE_CORE, class, sorf, 0) == 0)
+           audit_pipe_preselect(auid, AUE_CORE, class, sorf, 0) == 0) {
                return;
+       }
        /*
         * If we are interested in seeing this audit record, allocate it.
         * Where possible coredump records should contain a pathname and arg32
@@ -835,19 +950,25 @@ audit_proc_coredump(proc_t proc, char *path, int errcode)
         */
        uthread = curthread();
        ar = audit_new(AUE_CORE, proc, uthread);
+       if (ar == NULL) {
+               return;
+       }
        if (path != NULL) {
                pathp = &ar->k_ar.ar_arg_upath1;
                *pathp = malloc(MAXPATHLEN, M_AUDITPATH, M_WAITOK);
                if (audit_canon_path(vfs_context_cwd(vfs_context_current()), path,
-                   *pathp))
+                   *pathp)) {
                        free(*pathp, M_AUDITPATH);
-               else
+               } else {
                        ARG_SET_VALID(ar, ARG_UPATH1);
+               }
        }
        ar->k_ar.ar_arg_signum = proc->p_sigacts->ps_sig;
        ARG_SET_VALID(ar, ARG_SIGNUM);
-       if (errcode != 0)
+       if (errcode != 0) {
                ret = 1;
+       }
        audit_commit(ar, errcode, ret);
 }
+#endif /* CONFIG_COREDUMP */
 #endif /* CONFIG_AUDIT */