/*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * NOTICE: This file was modified by McAfee Research in 2004 to introduce
+ * support for mandatory and extensible security protections. This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
*/
-
#include <sys/param.h>
-#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/namei.h>
-#include <sys/proc.h>
+#include <sys/proc_internal.h>
+#include <sys/kauth.h>
#include <sys/queue.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/ucred.h>
#include <sys/uio.h>
#include <sys/unistd.h>
-#include <sys/vnode.h>
+#include <sys/file_internal.h>
+#include <sys/vnode_internal.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/malloc.h>
#include <sys/un.h>
-#include <netinet/in.h>
-#include <sys/socketvar.h>
-#include <sys/protosw.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/vfs_context.h>
#include <sys/domain.h>
-#include <sys/mount.h>
-#include <net/route.h>
-#include <netinet/in_pcb.h>
+#include <sys/protosw.h>
+#include <sys/socketvar.h>
#include <bsm/audit.h>
#include <bsm/audit_kevents.h>
#include <bsm/audit_klib.h>
#include <bsm/audit_kernel.h>
-#include <mach/message.h>
-#include <mach/port.h>
+#include <mach/host_priv.h>
#include <mach/host_special_ports.h>
-#include <mach/audit_triggers.h>
+#include <mach/audit_triggers_server.h>
+#include <kern/host.h>
+#include <kern/kalloc.h>
+#include <kern/zalloc.h>
#include <kern/lock.h>
#include <kern/wait_queue.h>
-#include <kern/zalloc.h>
-#include <kern/kalloc.h>
+#include <kern/sched_prim.h>
+
+#if CONFIG_MACF
+#include <bsm/audit_record.h>
+#include <security/mac.h>
+#include <security/mac_framework.h>
+#include <security/mac_policy.h>
+#define MAC_ARG_PREFIX "arg: "
+#define MAC_ARG_PREFIX_LEN 5
+#endif
-#include <audit.h>
+#include <net/route.h>
-#ifdef AUDIT
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#if AUDIT
/*
* The AUDIT_EXCESSIVELY_VERBOSE define enables a number of
*/
/* #define AUDIT_EXCESSIVELY_VERBOSE */
#ifdef AUDIT_EXCESSIVELY_VERBOSE
+#define AUDIT_PRINTF_ONLY
#define AUDIT_PRINTF(x) printf x
#else
+#define AUDIT_PRINTF_ONLY __unused
#define AUDIT_PRINTF(X)
#endif
#undef assert()
#endif
#define assert(cond) \
- ((void) ((cond) ? 0 : panic("%s:%d (%s)", __FILE__, __LINE__, # cond)))
+ ((void) ((cond) ? 0 : panic("Assert failed: %s", # cond)))
#else
#include <kern/assert.h>
#endif /* DIAGNOSTIC */
* Mutex to protect global variables shared between various threads and
* processes.
*/
-static mutex_t *audit_mtx;
+static lck_grp_t *audit_grp;
+static lck_attr_t *audit_attr;
+static lck_grp_attr_t *audit_grp_attr;
+static lck_mtx_t *audit_mtx;
/*
* Queue of audit records ready for delivery to disk. We insert new
* not yet in the queue, which is needed to estimate the total
* size of the combined set of records outstanding in the system.
*/
-static TAILQ_HEAD(, kaudit_record) audit_q;
-static int audit_q_len;
-static int audit_pre_q_len;
+static TAILQ_HEAD(, kaudit_record) audit_q;
+static size_t audit_q_len;
+static size_t audit_pre_q_len;
static wait_queue_t audit_wait_queue;
static zone_t audit_zone;
+#if CONFIG_MACF
+static zone_t audit_mac_label_zone;
+#endif
/*
* Condition variable to signal to the worker that it has work to do:
static int audit_worker_event;
#define AUDIT_WORKER_EVENT ((event_t)&audit_worker_event)
+/*
+ * The audit worker thread (which is lazy started when we first
+ * rotate the audit log.
+ */
+static thread_t audit_worker_thread = THREAD_NULL;
+
/*
* When an audit log is rotated, the actual rotation must be performed
* by the audit worker thread, as it may have outstanding writes on the
static int audit_replacement_event;
#define AUDIT_REPLACEMENT_EVENT ((event_t)&audit_replacement_event)
-static int audit_replacement_flag;
+static int audit_replacement_flag;
static struct vnode *audit_replacement_vp;
-static struct ucred *audit_replacement_cred;
+static kauth_cred_t audit_replacement_cred;
/*
* Wait queue for auditing threads that cannot commit the audit
/*
* Flags to use on audit files when opening and closing.
*/
-const static int audit_open_flags = FWRITE | O_APPEND;
-const static int audit_close_flags = FWRITE | O_APPEND;
+static const int audit_open_flags = FWRITE | O_APPEND;
+static const int audit_close_flags = FWRITE | O_APPEND;
/*
* Global audit statistiscs.
*/
extern task_t kernel_task;
+extern zone_t mac_audit_data_zone;
static void
audit_free(struct kaudit_record *ar)
{
if (ar->k_ar.ar_arg_upath1 != NULL) {
- kfree((vm_offset_t)ar->k_ar.ar_arg_upath1, MAXPATHLEN);
+ kfree(ar->k_ar.ar_arg_upath1, MAXPATHLEN);
}
if (ar->k_ar.ar_arg_upath2 != NULL) {
- kfree((vm_offset_t)ar->k_ar.ar_arg_upath2, MAXPATHLEN);
+ kfree(ar->k_ar.ar_arg_upath2, MAXPATHLEN);
+
}
if (ar->k_ar.ar_arg_kpath1 != NULL) {
- kfree((vm_offset_t)ar->k_ar.ar_arg_kpath1, MAXPATHLEN);
+ kfree(ar->k_ar.ar_arg_kpath1, MAXPATHLEN);
+
}
if (ar->k_ar.ar_arg_kpath2 != NULL) {
- kfree((vm_offset_t)ar->k_ar.ar_arg_kpath2, MAXPATHLEN);
+ kfree(ar->k_ar.ar_arg_kpath2, MAXPATHLEN);
+
}
if (ar->k_ar.ar_arg_text != NULL) {
- kfree((vm_offset_t)ar->k_ar.ar_arg_text, MAXPATHLEN);
+ kfree(ar->k_ar.ar_arg_text, MAXPATHLEN);
+
}
if (ar->k_udata != NULL) {
- kfree((vm_offset_t)ar->k_udata, (vm_size_t)ar->k_ulen);
+ kfree(ar->k_udata, ar->k_ulen);
+ }
+
+#if CONFIG_MACF
+ if (ar->k_ar.ar_vnode1_mac_labels != NULL) {
+ zfree(audit_mac_label_zone, ar->k_ar.ar_vnode1_mac_labels);
+ }
+ if (ar->k_ar.ar_vnode2_mac_labels != NULL) {
+ zfree(audit_mac_label_zone, ar->k_ar.ar_vnode2_mac_labels);
+ }
+ if (ar->k_ar.ar_cred_mac_labels != NULL) {
+ zfree(audit_mac_label_zone, ar->k_ar.ar_cred_mac_labels);
}
- zfree(audit_zone, (vm_offset_t)ar);
+ if (ar->k_ar.ar_arg_mac_string != NULL) {
+ kfree(ar->k_ar.ar_arg_mac_string,
+ MAC_MAX_LABEL_BUF_LEN + MAC_ARG_PREFIX_LEN);
+ }
+
+ /* Free the audit data from the MAC policies. */
+ do {
+ struct mac_audit_record *head, *next;
+
+ head = LIST_FIRST(ar->k_ar.ar_mac_records);
+ while (head != NULL) {
+ next = LIST_NEXT(head, records);
+ zfree(mac_audit_data_zone, head->data);
+ kfree(head, sizeof(*head));
+ head = next;
+ }
+
+ kfree(ar->k_ar.ar_mac_records,
+ sizeof(*ar->k_ar.ar_mac_records));
+ } while (0);
+#endif
+
+ zfree(audit_zone, ar);
}
+/*
+ * Converts an audit record into the BSM format before writing out to the
+ * audit logfile. Will perform it's own vnode iocounting.
+ *
+ * Returns:
+ * -1 if it could not get an ioreference on the vnode.
+ * EINVAL if the kaudit_record ar is not a valid audit record.
+ */
static int
-audit_write(struct vnode *vp, struct kaudit_record *ar, struct ucred *cred,
- struct proc *p)
+audit_write(struct vnode *vp, struct kaudit_record *ar, vfs_context_t ctx)
{
- struct statfs *mnt_stat = &vp->v_mount->mnt_stat;
- int ret;
+ struct vfsstatfs *mnt_stat = &vp->v_mount->mnt_vfsstat;
+ int ret = 0;
struct au_record *bsm;
- struct vattr vattr;
+ off_t file_size;
mach_port_t audit_port;
- /*
+ if (vnode_getwithref(vp))
+ return ENOENT;
+
+ /*
* First, gather statistics on the audit log file and file system
* so that we know how we're doing on space. In both cases,
* if we're unable to perform the operation, we drop the record
* and return. However, this is arguably an assertion failure.
*/
- ret = VFS_STATFS(vp->v_mount, mnt_stat, p);
- if (ret)
- goto out;
-
- ret = VOP_GETATTR(vp, &vattr, cred, p);
+ ret = vfs_update_vfsstat(vp->v_mount, ctx, VFS_KERNEL_EVENT);
if (ret)
goto out;
/* update the global stats struct */
- audit_fstat.af_currsz = vattr.va_size;
-
+ if ((ret = vnode_size(vp, &file_size, ctx)) != 0)
+ goto out;
+ audit_fstat.af_currsz = file_size;
+
/*
* Send a message to the audit daemon when disk space is getting
* low.
printf("Cannot get audit control port\n");
if (audit_port != MACH_PORT_NULL) {
- long temp;
+ uint64_t temp;
/*
* If we fall below percent free blocks, then trigger the
*/
if ((audit_fstat.af_filesz != 0) &&
(audit_file_rotate_wait == 0) &&
- (vattr.va_size >= audit_fstat.af_filesz)) {
+ (file_size >= (off_t)audit_fstat.af_filesz)) {
audit_file_rotate_wait = 1;
ret = audit_triggers(audit_port,
AUDIT_TRIGGER_FILE_FULL);
*/
if (ar->k_ar_commit & AR_COMMIT_USER) {
ret = vn_rdwr(UIO_WRITE, vp, (void *)ar->k_udata, ar->k_ulen,
- (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, cred, NULL, p);
+ (off_t)0, UIO_SYSSPACE32, IO_APPEND|IO_UNIT, vfs_context_ucred(ctx), NULL, vfs_context_proc(ctx));
if (ret)
goto out;
}
goto out;
}
- /* XXX This function can be called with the kernel funnel held,
- * which is not optimal. We should break the write functionality
+ /* XXX: We should break the write functionality
* away from the BSM record generation and have the BSM generation
* done before this function is called. This function will then
* take the BSM record as a parameter.
*/
ret = (vn_rdwr(UIO_WRITE, vp, (void *)bsm->data, bsm->len,
- (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, cred, NULL, p));
-
+ (off_t)0, UIO_SYSSPACE32, IO_APPEND|IO_UNIT, vfs_context_ucred(ctx), NULL, vfs_context_proc(ctx)));
kau_free(bsm);
out:
*/
if (audit_in_failure &&
audit_q_len == 0 && audit_pre_q_len == 0) {
- VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, p);
- (void)VOP_FSYNC(vp, cred, MNT_WAIT, p);
- VOP_UNLOCK(vp, 0, p);
+ (void)VNOP_FSYNC(vp, MNT_WAIT, ctx);
panic("Audit store overflow; record queue drained.");
}
+ vnode_put(vp);
return (ret);
}
static void
-audit_worker()
+audit_worker(void)
{
- int do_replacement_signal, error, release_funnel;
+ int do_replacement_signal, error;
TAILQ_HEAD(, kaudit_record) ar_worklist;
- struct kaudit_record *ar, *ar_start, *ar_stop;
+ struct kaudit_record *ar;
struct vnode *audit_vp, *old_vp;
-
- struct ucred *audit_cred, *old_cred;
- struct proc *audit_p;
+ kauth_cred_t audit_cred;
+ proc_t audit_p;
AUDIT_PRINTF(("audit_worker starting\n"));
TAILQ_INIT(&ar_worklist);
- audit_cred = NULL;
+ audit_cred = NOCRED;
audit_p = current_proc();
audit_vp = NULL;
- /*
- * XXX: Presumably we can assume Mach threads are started without
- * holding the BSD kernel funnel?
- */
- thread_funnel_set(kernel_flock, FALSE);
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
while (1) {
+ struct vfs_context context;
+
/*
* First priority: replace the audit log target if requested.
- * As we actually close the vnode in the worker thread, we
- * need to grab the funnel, which means releasing audit_mtx.
- * In case another replacement was scheduled while the mutex
- * we released, we loop.
*
* XXX It could well be we should drain existing records
* first to ensure that the timestamps and ordering
*/
do_replacement_signal = 0;
while (audit_replacement_flag != 0) {
- old_cred = audit_cred;
+ kauth_cred_t old_cred = audit_cred;
+
old_vp = audit_vp;
audit_cred = audit_replacement_cred;
audit_vp = audit_replacement_vp;
- audit_replacement_cred = NULL;
+ audit_replacement_cred = NOCRED;
audit_replacement_vp = NULL;
audit_replacement_flag = 0;
audit_enabled = (audit_vp != NULL);
- if (old_vp != NULL || audit_vp != NULL) {
- mutex_unlock(audit_mtx);
- thread_funnel_set(kernel_flock, TRUE);
- release_funnel = 1;
- } else
- release_funnel = 0;
/*
* XXX: What to do about write failures here?
*/
if (old_vp != NULL) {
- AUDIT_PRINTF(("Closing old audit file\n"));
- vn_close(old_vp, audit_close_flags, old_cred,
- audit_p);
- crfree(old_cred);
- old_cred = NULL;
+ AUDIT_PRINTF(("Closing old audit file vnode %p\n", old_vp));
+ if (vnode_get(old_vp) == 0) {
+ vn_close(old_vp, audit_close_flags, vfs_context_kernel());
+ vnode_put(old_vp);
+ AUDIT_PRINTF(("Audit file closed\n"));
+ }
+ else
+ printf("audit_worker(): Couldn't close audit file.\n");
+ kauth_cred_unref(&old_cred);
old_vp = NULL;
- AUDIT_PRINTF(("Audit file closed\n"));
}
if (audit_vp != NULL) {
AUDIT_PRINTF(("Opening new audit file\n"));
}
- if (release_funnel) {
- thread_funnel_set(kernel_flock, FALSE);
- mutex_lock(audit_mtx);
- }
do_replacement_signal = 1;
}
/*
AUDIT_PRINTF(("audit_worker waiting\n"));
ret = wait_queue_assert_wait(audit_wait_queue,
AUDIT_WORKER_EVENT,
- THREAD_UNINT);
- mutex_unlock(audit_mtx);
+ THREAD_UNINT,
+ 0);
+ lck_mtx_unlock(audit_mtx);
assert(ret == THREAD_WAITING);
ret = thread_block(THREAD_CONTINUE_NULL);
AUDIT_PRINTF(("audit_worker woken up\n"));
AUDIT_PRINTF(("audit_worker: new vp = %p; value of flag %d\n",
audit_replacement_vp, audit_replacement_flag));
- mutex_lock(audit_mtx);
+
+ lck_mtx_lock(audit_mtx);
continue;
}
TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q);
}
- mutex_unlock(audit_mtx);
+ lck_mtx_unlock(audit_mtx);
while ((ar = TAILQ_FIRST(&ar_worklist))) {
TAILQ_REMOVE(&ar_worklist, ar, k_q);
audit_free(ar);
}
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
continue;
}
TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q);
}
-
- mutex_unlock(audit_mtx);
- release_funnel = 0;
+ lck_mtx_unlock(audit_mtx);
+ context.vc_thread = current_thread();
+ context.vc_ucred = audit_cred;
while ((ar = TAILQ_FIRST(&ar_worklist))) {
TAILQ_REMOVE(&ar_worklist, ar, k_q);
if (audit_vp != NULL) {
* XXX: What should happen if there's a write
* error here?
*/
- if (!release_funnel) {
- thread_funnel_set(kernel_flock, TRUE);
- release_funnel = 1;
- }
- VOP_LEASE(audit_vp, audit_p, audit_cred,
- LEASE_WRITE);
- error = audit_write(audit_vp, ar, audit_cred,
- audit_p);
- if (error && audit_panic_on_write_fail)
+ error = audit_write(audit_vp, ar, &context);
+ if (error && audit_panic_on_write_fail) {
panic("audit_worker: write error %d\n",
error);
- else if (error)
+ } else if (error) {
printf("audit_worker: write error %d\n",
error);
+ }
}
audit_free(ar);
}
- if (release_funnel)
- thread_funnel_set(kernel_flock, FALSE);
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
}
}
void
audit_init(void)
{
-
- /* Verify that the syscall to audit event table is the same
- * size as the system call table.
- */
- if (nsys_au_event != nsysent) {
- printf("Security auditing service initialization failed, ");
- printf("audit event table doesn't match syscall table.\n");
- return;
- }
-
printf("Security auditing service present\n");
TAILQ_INIT(&audit_q);
audit_q_len = 0;
audit_qctrl.aq_bufsz = AQ_BUFSZ;
audit_qctrl.aq_minfree = AU_FS_MINFREE;
- audit_mtx = mutex_alloc(ETAP_NO_TRACE);
+ audit_grp_attr = lck_grp_attr_alloc_init();
+ audit_grp = lck_grp_alloc_init("audit", audit_grp_attr);
+ audit_attr = lck_attr_alloc_init();
+ audit_mtx = lck_mtx_alloc_init(audit_grp, audit_attr);
+
audit_wait_queue = wait_queue_alloc(SYNC_POLICY_FIFO);
audit_zone = zinit(sizeof(struct kaudit_record),
AQ_HIWATER*sizeof(struct kaudit_record),
8192,
"audit_zone");
+#if CONFIG_MACF
+ /* Assume 3 MAC labels for each audit record: two for vnodes,
+ * one for creds.
+ */
+ audit_mac_label_zone = zinit(MAC_AUDIT_LABEL_LEN,
+ AQ_HIWATER * 3*MAC_AUDIT_LABEL_LEN,
+ 8192,
+ "audit_mac_label_zone");
+#endif
/* Initialize the BSM audit subsystem. */
kau_init();
-
- kernel_thread(kernel_task, audit_worker);
}
static void
-audit_rotate_vnode(struct ucred *cred, struct vnode *vp)
+audit_rotate_vnode(kauth_cred_t cred, struct vnode *vp)
{
int ret;
* If other parallel log replacements have been requested, we wait
* until they've finished before continuing.
*/
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
while (audit_replacement_flag != 0) {
AUDIT_PRINTF(("audit_rotate_vnode: sleeping to wait for "
"flag\n"));
ret = wait_queue_assert_wait(audit_wait_queue,
AUDIT_REPLACEMENT_EVENT,
- THREAD_UNINT);
- mutex_unlock(audit_mtx);
+ THREAD_UNINT,
+ 0);
+ lck_mtx_unlock(audit_mtx);
assert(ret == THREAD_WAITING);
ret = thread_block(THREAD_CONTINUE_NULL);
AUDIT_PRINTF(("audit_rotate_vnode: woken up (flag %d)\n",
audit_replacement_flag));
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
}
audit_replacement_cred = cred;
audit_replacement_flag = 1;
audit_replacement_vp = vp;
/*
- * Wake up the audit worker to perform the exchange once we
- * release the mutex.
+ * Start or wake up the audit worker to perform the exchange.
+ * It will have to wait until we release the mutex.
*/
- wait_queue_wakeup_one(audit_wait_queue, AUDIT_WORKER_EVENT, THREAD_AWAKENED);
+ if (audit_worker_thread == THREAD_NULL)
+ audit_worker_thread = kernel_thread(kernel_task,
+ audit_worker);
+ else
+ wait_queue_wakeup_one(audit_wait_queue,
+ AUDIT_WORKER_EVENT,
+ THREAD_AWAKENED);
/*
* Wait for the audit_worker to broadcast that a replacement has
"replacement\n"));
ret = wait_queue_assert_wait(audit_wait_queue,
AUDIT_REPLACEMENT_EVENT,
- THREAD_UNINT);
- mutex_unlock(audit_mtx);
+ THREAD_UNINT,
+ 0);
+ lck_mtx_unlock(audit_mtx);
assert(ret == THREAD_WAITING);
ret = thread_block(THREAD_CONTINUE_NULL);
void
audit_shutdown(void)
{
- audit_rotate_vnode(NULL, NULL);
+ if (audit_mtx)
+ audit_rotate_vnode(NULL, NULL);
}
static __inline__ struct uthread *
curuthread(void)
{
- return (get_bsdthread_info(current_act()));
+ return (get_bsdthread_info(current_thread()));
}
static __inline__ struct kaudit_record *
* work, since we pre-select only based on the AUE_audit event type,
* not the event type submitted as part of the user audit data.
*/
-struct audit_args {
- void * record;
- int length;
-};
/* ARGSUSED */
int
-audit(struct proc *p, struct audit_args *uap, register_t *retval)
+audit(proc_t p, struct audit_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
int error;
void * rec;
struct kaudit_record *ar;
struct uthread *uthr;
- error = suser(pc->pc_ucred, &p->p_acflag);
+ error = suser(kauth_cred_get(), &p->p_acflag);
if (error)
return (error);
- if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
+ lck_mtx_lock(audit_mtx);
+ if ((uap->length <= 0) || (uap->length > (int)audit_qctrl.aq_bufsz)) {
+ lck_mtx_unlock(audit_mtx);
return (EINVAL);
+ }
+ lck_mtx_unlock(audit_mtx);
ar = currecord();
if (ar == NULL) {
uthr = curuthread();
if (uthr == NULL) /* can this happen? */
- return (ENOTSUP);
+ return (ENOTSUP);
/* This is not very efficient; we're required to allocate
* a complete kernel audit record just so the user record
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;
/* audit_syscall_exit() will free the audit record on the thread
* even if we allocated it above.
*/
- kfree((vm_offset_t)rec, (vm_size_t)uap->length);
+ kfree(rec, uap->length);
return (error);
}
/*
* System call to manipulate auditing.
*/
-struct auditon_args {
- int cmd;
- void * data;
- int length;
-};
/* ARGSUSED */
int
-auditon(struct proc *p, struct auditon_args *uap, register_t *retval)
+auditon(proc_t p, struct auditon_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
int ret;
int len;
union auditon_udata udata;
- struct proc *tp;
+ proc_t tp = PROC_NULL;
+ kauth_cred_t my_cred;
AUDIT_ARG(cmd, uap->cmd);
- ret = suser(pc->pc_ucred, &p->p_acflag);
+ ret = suser(kauth_cred_get(), &p->p_acflag);
if (ret)
return (ret);
+#if CONFIG_MACF
+ ret = mac_system_check_auditon(kauth_cred_get(), uap->cmd);
+ if (ret)
+ return (ret);
+#endif
+
len = uap->length;
- if ((len <= 0) || (len > sizeof(union auditon_udata)))
+ if ((len <= 0) || (len > (int)sizeof(union auditon_udata)))
return (EINVAL);
memset((void *)&udata, 0, sizeof(udata));
/* XXX Need to implement these commands by accessing the global
* values associated with the commands.
*/
+ lck_mtx_lock(audit_mtx);
switch (uap->cmd) {
case A_GETPOLICY:
if (!audit_fail_stop)
udata.au_policy |= AUDIT_AHLT;
break;
case A_SETPOLICY:
- if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT))
- return (EINVAL);
+ if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT)) {
+ ret = EINVAL;
+ break;
+ }
/*
* XXX - Need to wake up waiters if the policy relaxes?
*/
(udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
(udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
(udata.au_qctrl.aq_minfree < 0) ||
- (udata.au_qctrl.aq_minfree > 100))
- return (EINVAL);
+ (udata.au_qctrl.aq_minfree > 100)) {
+ ret = EINVAL;
+ break;
+ }
audit_qctrl = udata.au_qctrl;
/* XXX The queue delay value isn't used with the kernel. */
audit_qctrl.aq_delay = -1;
break;
case A_GETCWD:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_GETCAR:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_GETSTAT:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_SETSTAT:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_SETUMASK:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_SETSMASK:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_GETCOND:
if (audit_enabled && !audit_suspended)
udata.au_evclass.ec_class);
break;
case A_GETPINFO:
- if (udata.au_aupinfo.ap_pid < 1)
- return (EINVAL);
- if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
- return (EINVAL);
+ if (udata.au_aupinfo.ap_pid < 1) {
+ ret = EINVAL;
+ break;
+ }
+ if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
+ ret = EINVAL;
+ break;
+ }
+
+ lck_mtx_unlock(audit_mtx);
+ my_cred = kauth_cred_proc_ref(tp);
- udata.au_aupinfo.ap_auid = tp->p_au->ai_auid;
+ udata.au_aupinfo.ap_auid = my_cred->cr_au.ai_auid;
udata.au_aupinfo.ap_mask.am_success =
- tp->p_au->ai_mask.am_success;
+ my_cred->cr_au.ai_mask.am_success;
udata.au_aupinfo.ap_mask.am_failure =
- tp->p_au->ai_mask.am_failure;
+ my_cred->cr_au.ai_mask.am_failure;
udata.au_aupinfo.ap_termid.machine =
- tp->p_au->ai_termid.machine;
+ my_cred->cr_au.ai_termid.machine;
udata.au_aupinfo.ap_termid.port =
- tp->p_au->ai_termid.port;
- udata.au_aupinfo.ap_asid = tp->p_au->ai_asid;
+ my_cred->cr_au.ai_termid.port;
+ udata.au_aupinfo.ap_asid = my_cred->cr_au.ai_asid;
+
+ kauth_cred_unref(&my_cred);
+
+ proc_rele(tp);
+ tp = PROC_NULL;
+ lck_mtx_lock(audit_mtx);
break;
case A_SETPMASK:
- if (udata.au_aupinfo.ap_pid < 1)
- return (EINVAL);
- if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
- return (EINVAL);
-
- tp->p_au->ai_mask.am_success =
- udata.au_aupinfo.ap_mask.am_success;
- tp->p_au->ai_mask.am_failure =
- udata.au_aupinfo.ap_mask.am_failure;
+ if (udata.au_aupinfo.ap_pid < 1) {
+ ret = EINVAL;
+ break;
+ }
+ if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
+ ret = EINVAL;
+ break;
+ }
+
+ /*
+ * we are modifying the audit info in a credential so we need a new
+ * credential (or take another reference on an existing credential that
+ * matches our new one). We must do this because the audit info in the
+ * credential is used as part of our hash key. Get current credential
+ * in the target process and take a reference while we muck with it.
+ */
+ lck_mtx_unlock(audit_mtx);
+ for (;;) {
+ kauth_cred_t my_new_cred;
+ struct auditinfo temp_auditinfo;
+
+ my_cred = kauth_cred_proc_ref(tp);
+ /*
+ * Set the credential with new info. If there is no
+ * change, we get back the same credential we passed
+ * in; if there is a change, we drop the reference on
+ * the credential we passed in. The subsequent
+ * compare is safe, because it is a pointer compare
+ * rather than a contents compare.
+ */
+ temp_auditinfo = my_cred->cr_au;
+ temp_auditinfo.ai_mask.am_success =
+ udata.au_aupinfo.ap_mask.am_success;
+ temp_auditinfo.ai_mask.am_failure =
+ udata.au_aupinfo.ap_mask.am_failure;
+ my_new_cred = kauth_cred_setauditinfo(my_cred, &temp_auditinfo);
+
+ if (my_cred != my_new_cred) {
+ proc_lock(tp);
+ /* need to protect for a race where another thread also changed
+ * the credential after we took our reference. If p_ucred has
+ * changed then we should restart this again with the new cred.
+ */
+ if (tp->p_ucred != my_cred) {
+ proc_unlock(tp);
+ kauth_cred_unref(&my_new_cred);
+ /* try again */
+ continue;
+ }
+ tp->p_ucred = my_new_cred;
+ proc_unlock(tp);
+ }
+ /* drop old proc reference or our extra reference */
+ kauth_cred_unref(&my_cred);
+ break;
+ }
+ proc_rele(tp);
+ lck_mtx_lock(audit_mtx);
break;
case A_SETFSIZE:
if ((udata.au_fstat.af_filesz != 0) &&
- (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
- return (EINVAL);
+ (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) {
+ ret = EINVAL;
+ break;
+ }
audit_fstat.af_filesz = udata.au_fstat.af_filesz;
break;
case A_GETFSIZE:
udata.au_fstat.af_currsz = audit_fstat.af_currsz;
break;
case A_GETPINFO_ADDR:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_GETKAUDIT:
- return (ENOSYS);
+ ret = ENOSYS;
break;
case A_SETKAUDIT:
- return (ENOSYS);
+ ret = ENOSYS;
break;
}
/* Copy data back to userspace for the GET comands */
- switch (uap->cmd) {
- case A_GETPOLICY:
- case A_GETKMASK:
- case A_GETQCTRL:
- case A_GETCWD:
- case A_GETCAR:
- case A_GETSTAT:
- case A_GETCOND:
- case A_GETCLASS:
- case A_GETPINFO:
- case A_GETFSIZE:
- case A_GETPINFO_ADDR:
- case A_GETKAUDIT:
- ret = copyout((void *)&udata, uap->data, uap->length);
- if (ret)
- return (ret);
- break;
+ if (ret == 0) {
+ switch (uap->cmd) {
+ case A_GETPOLICY:
+ case A_GETKMASK:
+ case A_GETQCTRL:
+ case A_GETCWD:
+ case A_GETCAR:
+ case A_GETSTAT:
+ case A_GETCOND:
+ case A_GETCLASS:
+ case A_GETPINFO:
+ case A_GETFSIZE:
+ case A_GETPINFO_ADDR:
+ case A_GETKAUDIT:
+ ret = copyout((void *)&udata, uap->data, uap->length);
+ break;
+ }
}
- return (0);
+ lck_mtx_unlock(audit_mtx);
+ return (ret);
}
/*
* System calls to manage the user audit information.
- * XXXAUDIT May need to lock the proc structure.
*/
-struct getauid_args {
- au_id_t *auid;
-};
/* ARGSUSED */
int
-getauid(struct proc *p, struct getauid_args *uap, register_t *retval)
+getauid(__unused proc_t p, struct getauid_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
int error;
- error = suser(pc->pc_ucred, &p->p_acflag);
+#if CONFIG_MACF
+ error = mac_proc_check_getauid(p);
if (error)
return (error);
+#endif
- error = copyout((void *)&p->p_au->ai_auid, (void *)uap->auid,
- sizeof(*uap->auid));
+ error = copyout((void *)&kauth_cred_get()->cr_au.ai_auid,
+ uap->auid, sizeof(au_id_t));
if (error)
return (error);
return (0);
}
-struct setauid_args {
- au_id_t *auid;
-};
/* ARGSUSED */
int
-setauid(struct proc *p, struct setauid_args *uap, register_t *retval)
+setauid(proc_t p, struct setauid_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
int error;
+ au_id_t temp_au_id;
- error = suser(pc->pc_ucred, &p->p_acflag);
+ error = suser(kauth_cred_get(), &p->p_acflag);
if (error)
return (error);
- error = copyin((void *)uap->auid, (void *)&p->p_au->ai_auid,
- sizeof(p->p_au->ai_auid));
+ error = copyin(uap->auid,
+ (void *)&temp_au_id,
+ sizeof(au_id_t));
if (error)
return (error);
+#if CONFIG_MACF
+ error = mac_proc_check_setauid(p, temp_au_id);
+ if (error)
+ return (error);
+#endif
+
+ /*
+ * we are modifying the audit info in a credential so we need a new
+ * credential (or take another reference on an existing credential that
+ * matches our new one). We must do this because the audit info in the
+ * credential is used as part of our hash key. Get current credential
+ * in the target process and take a reference while we muck with it.
+ */
+ for (;;) {
+ kauth_cred_t my_cred, my_new_cred;
+ struct auditinfo temp_auditinfo;
+
+ my_cred = kauth_cred_proc_ref(p);
+ /*
+ * Set the credential with new info. If there is no change,
+ * we get back the same credential we passed in; if there is
+ * a change, we drop the reference on the credential we
+ * passed in. The subsequent compare is safe, because it is
+ * a pointer compare rather than a contents compare.
+ */
+ temp_auditinfo = my_cred->cr_au;
+ temp_auditinfo.ai_auid = temp_au_id;
+ my_new_cred = kauth_cred_setauditinfo(my_cred, &temp_auditinfo);
+
+ if (my_cred != my_new_cred) {
+ proc_lock(p);
+ /* need to protect for a race where another thread also changed
+ * the credential after we took our reference. If p_ucred has
+ * changed then we should restart this again with the new cred.
+ */
+ if (p->p_ucred != my_cred) {
+ proc_unlock(p);
+ kauth_cred_unref(&my_new_cred);
+ /* try again */
+ continue;
+ }
+ p->p_ucred = my_new_cred;
+ proc_unlock(p);
+ }
+ /* drop old proc reference or our extra reference */
+ kauth_cred_unref(&my_cred);
+ break;
+ }
/* propagate the change from the process to Mach task */
set_security_token(p);
- audit_arg_auid(p->p_au->ai_auid);
+ audit_arg_auid(kauth_cred_get()->cr_au.ai_auid);
return (0);
}
/*
* System calls to get and set process audit information.
+ * If the caller is privileged, they get the whole set of
+ * audit information. Otherwise, the real audit mask is
+ * filtered out - but the rest of the information is
+ * returned.
*/
-struct getaudit_args {
- struct auditinfo *auditinfo;
-};
/* ARGSUSED */
int
-getaudit(struct proc *p, struct getaudit_args *uap, register_t *retval)
+getaudit(proc_t p, struct getaudit_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
+ struct auditinfo ai;
int error;
- error = suser(pc->pc_ucred, &p->p_acflag);
+#if CONFIG_MACF
+ error = mac_proc_check_getaudit(p);
if (error)
return (error);
- error = copyout((void *)p->p_au, (void *)uap->auditinfo,
- sizeof(*uap->auditinfo));
+#endif
+
+ ai = kauth_cred_get()->cr_au;
+
+ /* only superuser gets to see the real mask */
+ error = suser(kauth_cred_get(), &p->p_acflag);
+ if (error) {
+ ai.ai_mask.am_success = ~0;
+ ai.ai_mask.am_failure = ~0;
+ }
+
+ error = copyout(&ai, uap->auditinfo, sizeof(ai));
if (error)
return (error);
return (0);
}
-struct setaudit_args {
- struct auditinfo *auditinfo;
-};
/* ARGSUSED */
int
-setaudit(struct proc *p, struct setaudit_args *uap, register_t *retval)
+setaudit(proc_t p, struct setaudit_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
int error;
+ struct auditinfo temp_auditinfo;
+ kauth_cred_t safecred;
- error = suser(pc->pc_ucred, &p->p_acflag);
+ error = suser(kauth_cred_get(), &p->p_acflag);
if (error)
return (error);
- error = copyin((void *)uap->auditinfo, (void *)p->p_au,
- sizeof(*p->p_au));
+ error = copyin(uap->auditinfo,
+ (void *)&temp_auditinfo,
+ sizeof(temp_auditinfo));
if (error)
return (error);
+#if CONFIG_MACF
+ error = mac_proc_check_setaudit(p, &temp_auditinfo);
+ if (error)
+ return (error);
+
+#endif
+
+
+ /*
+ * we are modifying the audit info in a credential so we need a new
+ * credential (or take another reference on an existing credential that
+ * matches our new one). We must do this because the audit info in the
+ * credential is used as part of our hash key. Get current credential
+ * in the target process and take a reference while we muck with it.
+ */
+ for (;;) {
+ kauth_cred_t my_cred, my_new_cred;
+
+ my_cred = kauth_cred_proc_ref(p);
+ /*
+ * Set the credential with new info. If there is no change,
+ * we get back the same credential we passed in; if there is
+ * a change, we drop the reference on the credential we
+ * passed in. The subsequent compare is safe, because it is
+ * a pointer compare rather than a contents compare.
+ */
+ my_new_cred = kauth_cred_setauditinfo(my_cred, &temp_auditinfo);
+
+ if (my_cred != my_new_cred) {
+ proc_lock(p);
+ /* need to protect for a race where another thread also changed
+ * the credential after we took our reference. If p_ucred has
+ * changed then we should restart this again with the new cred.
+ */
+ if (p->p_ucred != my_cred) {
+ proc_unlock(p);
+ kauth_cred_unref(&my_new_cred);
+ /* try again */
+ continue;
+ }
+ p->p_ucred = my_new_cred;
+ proc_unlock(p);
+ }
+ /* drop old proc reference or our extra reference */
+ kauth_cred_unref(&my_cred);
+ break;
+ }
/* propagate the change from the process to Mach task */
set_security_token(p);
- audit_arg_auditinfo(p->p_au);
+ safecred = kauth_cred_proc_ref(p);
+ audit_arg_auditinfo(&safecred->cr_au);
+ kauth_cred_unref(&safecred);
return (0);
}
-struct getaudit_addr_args {
- struct auditinfo_addr *auditinfo_addr;
- int length;
-};
/* ARGSUSED */
int
-getaudit_addr(struct proc *p, struct getaudit_addr_args *uap, register_t *retval)
+getaudit_addr(__unused proc_t p, __unused struct getaudit_addr_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
- int error;
-
- error = suser(pc->pc_ucred, &p->p_acflag);
- if (error)
- return (error);
return (ENOSYS);
}
-struct setaudit_addr_args {
- struct auditinfo_addr *auditinfo_addr;
- int length;
-};
/* ARGSUSED */
int
-setaudit_addr(struct proc *p, struct setaudit_addr_args *uap, register_t *retval)
+setaudit_addr(proc_t p, __unused struct setaudit_addr_args *uap, __unused register_t *retval)
{
- register struct pcred *pc = p->p_cred;
int error;
- error = suser(pc->pc_ucred, &p->p_acflag);
+ error = suser(kauth_cred_get(), &p->p_acflag);
if (error)
return (error);
return (ENOSYS);
* Syscall to manage audit files.
*
*/
-struct auditctl_args {
- char *path;
-};
/* ARGSUSED */
int
-auditctl(struct proc *p, struct auditctl_args *uap)
+auditctl(proc_t p, struct auditctl_args *uap, __unused register_t *retval)
{
- struct kaudit_record *ar;
struct nameidata nd;
- struct ucred *cred;
+ kauth_cred_t cred;
struct vnode *vp;
- int error, flags, ret;
+ int error;
- error = suser(p->p_ucred, &p->p_acflag);
+ error = suser(kauth_cred_get(), &p->p_acflag);
if (error)
return (error);
* validity checks, and grab another reference to the current
* credential.
*/
- if (uap->path != NULL) {
+ if (uap->path != USER_ADDR_NULL) {
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
- UIO_USERSPACE, uap->path, p);
- flags = audit_open_flags;
- error = vn_open(&nd, flags, 0);
+ (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
+ uap->path, vfs_context_current());
+ error = vn_open(&nd, audit_open_flags, 0);
if (error)
goto out;
- VOP_UNLOCK(nd.ni_vp, 0, p);
vp = nd.ni_vp;
+
if (vp->v_type != VREG) {
- vn_close(vp, audit_close_flags, p->p_ucred, p);
+ vn_close(vp, audit_close_flags, vfs_context_current());
+ vnode_put(vp);
error = EINVAL;
goto out;
}
- cred = p->p_ucred;
- crhold(cred);
+#if CONFIG_MACF
+ /*
+ * Accessibility of the vnode was determined in
+ * vn_open; the mac_system_check_auditctl should only
+ * determine whether that vnode is appropriate for
+ * storing audit data, or that the caller was
+ * permitted to control the auditing system at all.
+ * For example, a confidentiality policy may want to
+ * ensure that audit files are always high
+ * sensitivity.
+ */
+
+ error = mac_system_check_auditctl(kauth_cred_get(), vp);
+ if (error) {
+ vn_close(vp, audit_close_flags, vfs_context_current());
+ vnode_put(vp);
+ goto out;
+ }
+#endif
+ cred = kauth_cred_get_with_ref();
+ lck_mtx_lock(audit_mtx);
audit_suspended = 0;
+ lck_mtx_unlock(audit_mtx);
}
-
+#if CONFIG_MACF
+ else {
+ error = mac_system_check_auditctl(kauth_cred_get(), NULL);
+ if (error)
+ return (error);
+ }
+#endif
+
+ /*
+ * a vp and cred of NULL is valid at this point
+ * and indicates we're to turn off auditing...
+ */
audit_rotate_vnode(cred, vp);
+ if (vp)
+ vnode_put(vp);
out:
return (error);
}
* MPSAFE
*/
struct kaudit_record *
-audit_new(int event, struct proc *p, struct uthread *uthread)
+audit_new(int event, proc_t p, __unused struct uthread *uthread)
{
struct kaudit_record *ar;
int no_record;
+ kauth_cred_t safecred;
/*
* Eventually, there may be certain classes of events that
#if 0
if (event != AUDIT_EVENT_FILESTOP && event != AUDIT_EVENT_FILESTART) {
#endif
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
no_record = (audit_suspended || !audit_enabled);
- mutex_unlock(audit_mtx);
+ lck_mtx_unlock(audit_mtx);
if (no_record)
return (NULL);
#if 0
if (ar == NULL)
return NULL;
- mutex_lock(audit_mtx);
- audit_pre_q_len++;
- mutex_unlock(audit_mtx);
-
bzero(ar, sizeof(*ar));
ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC;
ar->k_ar.ar_event = event;
nanotime(&ar->k_ar.ar_starttime);
+ safecred = kauth_cred_proc_ref(p);
/* Export the subject credential. */
- cru2x(p->p_ucred, &ar->k_ar.ar_subj_cred);
- ar->k_ar.ar_subj_ruid = p->p_cred->p_ruid;
- ar->k_ar.ar_subj_rgid = p->p_cred->p_rgid;
- ar->k_ar.ar_subj_egid = p->p_ucred->cr_groups[0];
- ar->k_ar.ar_subj_auid = p->p_au->ai_auid;
- ar->k_ar.ar_subj_asid = p->p_au->ai_asid;
+ cru2x(safecred, &ar->k_ar.ar_subj_cred);
+
+ ar->k_ar.ar_subj_ruid = safecred->cr_ruid;
+ ar->k_ar.ar_subj_rgid = safecred->cr_rgid;
+ ar->k_ar.ar_subj_egid = safecred->cr_groups[0];
+ ar->k_ar.ar_subj_auid = safecred->cr_au.ai_auid;
+ ar->k_ar.ar_subj_asid = safecred->cr_au.ai_asid;
+ ar->k_ar.ar_subj_amask = safecred->cr_au.ai_mask;
+ ar->k_ar.ar_subj_term = safecred->cr_au.ai_termid;
+ kauth_cred_unref(&safecred);
+
ar->k_ar.ar_subj_pid = p->p_pid;
- ar->k_ar.ar_subj_amask = p->p_au->ai_mask;
- ar->k_ar.ar_subj_term = p->p_au->ai_termid;
bcopy(p->p_comm, ar->k_ar.ar_subj_comm, MAXCOMLEN);
+#if CONFIG_MACF
+ do {
+ struct mac mac;
+
+ /* Retrieve the MAC labels for the process. */
+ ar->k_ar.ar_cred_mac_labels =
+ (char *)zalloc(audit_mac_label_zone);
+ if (ar->k_ar.ar_cred_mac_labels == NULL) {
+ zfree(audit_zone, ar);
+ return (NULL);
+ }
+ mac.m_buflen = MAC_AUDIT_LABEL_LEN;
+ mac.m_string = ar->k_ar.ar_cred_mac_labels;
+ mac_cred_label_externalize_audit(p, &mac);
+
+ /*
+ * grab space for the reconds.
+ */
+ ar->k_ar.ar_mac_records = (struct mac_audit_record_list_t *)
+ kalloc(sizeof(*ar->k_ar.ar_mac_records));
+ if (ar->k_ar.ar_mac_records == NULL) {
+ zfree(audit_mac_label_zone,
+ ar->k_ar.ar_cred_mac_labels);
+ zfree(audit_zone, ar);
+ return (NULL);
+ }
+
+ LIST_INIT(ar->k_ar.ar_mac_records);
+
+ ar->k_ar.ar_forced_by_mac = 0;
+
+ } while (0);
+#endif
+
+ lck_mtx_lock(audit_mtx);
+ audit_pre_q_len++;
+ lck_mtx_unlock(audit_mtx);
+
return (ar);
}
void
audit_abort(struct kaudit_record *ar)
{
-
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
audit_pre_q_len--;
- mutex_unlock(audit_mtx);
+ lck_mtx_unlock(audit_mtx);
audit_free(ar);
}
if (au_preselect(ar->k_ar.ar_event, aumask, sorf) != 0)
ar->k_ar_commit |= AR_COMMIT_KERNEL;
- if (ar->k_ar_commit & (AR_COMMIT_USER | AR_COMMIT_KERNEL) == 0) {
- mutex_lock(audit_mtx);
+ if ((ar->k_ar_commit & (AR_COMMIT_USER | AR_COMMIT_KERNEL)) == 0) {
+ lck_mtx_lock(audit_mtx);
audit_pre_q_len--;
- mutex_unlock(audit_mtx);
+ lck_mtx_unlock(audit_mtx);
audit_free(ar);
return;
}
*/
nanotime(&ar->k_ar.ar_endtime);
- mutex_lock(audit_mtx);
-
+ lck_mtx_lock(audit_mtx);
/*
* Note: it could be that some records initiated while audit was
* enabled should still be committed?
*/
if (audit_suspended || !audit_enabled) {
audit_pre_q_len--;
- mutex_unlock(audit_mtx);
+ lck_mtx_unlock(audit_mtx);
audit_free(ar);
return;
}
-
+
/*
* Constrain the number of committed audit records based on
* the configurable parameter.
ret = wait_queue_assert_wait(audit_wait_queue,
AUDIT_COMMIT_EVENT,
- THREAD_UNINT);
- mutex_unlock(audit_mtx);
+ THREAD_UNINT,
+ 0);
+ lck_mtx_unlock(audit_mtx);
assert(ret == THREAD_WAITING);
ret = thread_block(THREAD_CONTINUE_NULL);
assert(ret == THREAD_AWAKENED);
- mutex_lock(audit_mtx);
+ lck_mtx_lock(audit_mtx);
}
TAILQ_INSERT_TAIL(&audit_q, ar, k_q);
audit_q_len++;
audit_pre_q_len--;
wait_queue_wakeup_one(audit_wait_queue, AUDIT_WORKER_EVENT, THREAD_AWAKENED);
- mutex_unlock(audit_mtx);
+ lck_mtx_unlock(audit_mtx);
+}
+
+/*
+ * If we're out of space and need to suspend unprivileged
+ * processes, do that here rather than trying to allocate
+ * another audit record.
+ */
+static void
+audit_new_wait(int audit_event, proc_t proc, struct uthread *uthread)
+{
+ int ret;
+
+ if (audit_in_failure &&
+ suser(kauth_cred_get(), &proc->p_acflag) != 0) {
+ ret = wait_queue_assert_wait(audit_wait_queue,
+ AUDIT_FAILURE_EVENT, THREAD_UNINT, 0);
+ assert(ret == THREAD_WAITING);
+ (void)thread_block(THREAD_CONTINUE_NULL);
+ panic("audit_failing_stop: thread continued");
+ }
+ uthread->uu_ar = audit_new(audit_event, proc, uthread);
}
/*
* each system call.
*/
void
-audit_syscall_enter(unsigned short code, struct proc *proc,
+audit_syscall_enter(unsigned short code, proc_t proc,
struct uthread *uthread)
{
int audit_event;
struct au_mask *aumask;
+ kauth_cred_t my_cred;
audit_event = sys_au_event[code];
if (audit_event == AUE_NULL)
/* Check which audit mask to use; either the kernel non-attributable
* event mask or the process audit mask.
*/
- if (proc->p_au->ai_auid == AU_DEFAUDITID)
+ my_cred = kauth_cred_proc_ref(proc);
+
+ if (my_cred->cr_au.ai_auid == AU_DEFAUDITID)
aumask = &audit_nae_mask;
else
- aumask = &proc->p_au->ai_mask;
-
+ aumask = &my_cred->cr_au.ai_mask;
+
/*
* Allocate an audit record, if preselection allows it, and store
* in the BSD thread for later use.
*/
- if (au_preselect(audit_event, aumask,
- AU_PRS_FAILURE | AU_PRS_SUCCESS)) {
- /*
- * If we're out of space and need to suspend unprivileged
- * processes, do that here rather than trying to allocate
- * another audit record.
- */
- if (audit_in_failure &&
- suser(proc->p_ucred, &proc->p_acflag) != 0) {
- int ret;
- ret = wait_queue_assert_wait(audit_wait_queue,
- AUDIT_FAILURE_EVENT, THREAD_UNINT);
- assert(ret == THREAD_WAITING);
- (void)thread_block(THREAD_CONTINUE_NULL);
- panic("audit_failing_stop: thread continued");
+#if CONFIG_MACF
+ do {
+ int error;
+
+ error = mac_audit_check_preselect(my_cred, code,
+ (void *) uthread->uu_arg);
+
+ if (error == MAC_AUDIT_YES) {
+ uthread->uu_ar = audit_new(audit_event, proc, uthread);
+ uthread->uu_ar->k_ar.ar_forced_by_mac = 1;
+ au_to_text("Forced by a MAC policy");
+ }
+ else if (error == MAC_AUDIT_NO) {
+ uthread->uu_ar = NULL;
}
- uthread->uu_ar = audit_new(audit_event, proc, uthread);
- } else
+ else if (error == MAC_AUDIT_DEFAULT &&
+ au_preselect(audit_event, &my_cred->cr_au.ai_mask,
+ AU_PRS_FAILURE | AU_PRS_SUCCESS))
+ audit_new_wait(audit_event, proc, uthread);
+ } while (0);
+#else
+ if (au_preselect(audit_event, &my_cred->cr_au.ai_mask,
+ AU_PRS_FAILURE | AU_PRS_SUCCESS)) {
+ audit_new_wait(audit_event, proc, uthread);
+ } else {
uthread->uu_ar = NULL;
+ }
+#endif
+ kauth_cred_unref(&my_cred);
}
+/*
+ * Note: The audit_syscall_exit() parameter list was modified to support
+ * mac_audit_check_postselect(), which requires the Darwin syscall number.
+ */
+#if CONFIG_MACF
void
-audit_syscall_exit(int error, struct proc *proc, struct uthread *uthread)
+audit_syscall_exit(unsigned short code, int error, AUDIT_PRINTF_ONLY proc_t proc, struct uthread *uthread)
+#else
+void
+audit_syscall_exit(int error, AUDIT_PRINTF_ONLY proc_t proc, struct uthread *uthread)
+#endif
{
int retval;
else
retval = uthread->uu_rval[0];
+#if CONFIG_MACF
+ do {
+ int mac_error;
+
+ if (uthread->uu_ar == NULL) /* syscall wasn't audited */
+ goto out;
+
+ /*
+ * Note, no other postselect mechanism exists. If
+ * mac_audit_check_postselect returns MAC_AUDIT_NO, the
+ * record will be suppressed. Other values at this
+ * point result in the audit record being committed.
+ * This suppression behavior will probably go away in
+ * the port to 10.3.4.
+ */
+ mac_error = mac_audit_check_postselect(kauth_cred_get(), code,
+ (void *) uthread->uu_arg, error, retval,
+ uthread->uu_ar->k_ar.ar_forced_by_mac);
+
+ if (mac_error == MAC_AUDIT_YES)
+ uthread->uu_ar->k_ar_commit |= AR_COMMIT_KERNEL;
+ else if (mac_error == MAC_AUDIT_NO) {
+ audit_free(uthread->uu_ar);
+ goto out;
+ }
+
+ } while (0);
+
+#endif
audit_commit(uthread->uu_ar, error, retval);
- if (uthread->uu_ar != NULL)
+ if (uthread->uu_ar != NULL) {
AUDIT_PRINTF(("audit record committed by pid %d\n", proc->p_pid));
+ }
+
+#if CONFIG_MACF
+out:
+#endif
uthread->uu_ar = NULL;
}
audit_mach_syscall_enter(unsigned short audit_event)
{
struct uthread *uthread;
- struct proc *proc;
+ proc_t proc;
struct au_mask *aumask;
+ kauth_cred_t my_cred;
if (audit_event == AUE_NULL)
return;
assert(uthread->uu_ar == NULL);
+ my_cred = kauth_cred_proc_ref(proc);
+
/* Check which audit mask to use; either the kernel non-attributable
* event mask or the process audit mask.
*/
- if (proc->p_au->ai_auid == AU_DEFAUDITID)
+ if (my_cred->cr_au.ai_auid == AU_DEFAUDITID)
aumask = &audit_nae_mask;
else
- aumask = &proc->p_au->ai_mask;
+ aumask = &my_cred->cr_au.ai_mask;
+
+ kauth_cred_unref(&my_cred);
/*
* Allocate an audit record, if desired, and store in the BSD
* record for this event.
*/
void
-audit_arg_addr(void * addr)
+audit_arg_addr(user_addr_t addr)
{
struct kaudit_record *ar;
if (ar == NULL)
return;
- ar->k_ar.ar_arg_addr = addr;
+ ar->k_ar.ar_arg_addr = CAST_DOWN(void *, addr); /* XXX */
ar->k_ar.ar_valid_arg |= ARG_ADDR;
}
void
-audit_arg_len(int len)
+audit_arg_len(user_size_t len)
{
struct kaudit_record *ar;
if (ar == NULL)
return;
- ar->k_ar.ar_arg_len = len;
+ ar->k_ar.ar_arg_len = CAST_DOWN(int, len); /* XXX */
ar->k_ar.ar_valid_arg |= ARG_LEN;
}
}
void
-audit_arg_groupset(gid_t *gidset, u_int gidset_size)
+audit_arg_groupset(const gid_t *gidset, u_int gidset_size)
{
- int i;
+ uint i;
struct kaudit_record *ar;
ar = currecord();
}
void
-audit_arg_login(char *login)
+audit_arg_login(const char *login)
{
struct kaudit_record *ar;
if (ar == NULL)
return;
-#if 0
- /*
- * XXX: Add strlcpy() to Darwin for improved safety.
- */
strlcpy(ar->k_ar.ar_arg_login, login, MAXLOGNAME);
-#else
- strcpy(ar->k_ar.ar_arg_login, login);
-#endif
ar->k_ar.ar_valid_arg |= ARG_LOGIN;
}
void
-audit_arg_ctlname(int *name, int namelen)
+audit_arg_ctlname(const int *name, int namelen)
{
struct kaudit_record *ar;
audit_arg_pid(pid_t pid)
{
struct kaudit_record *ar;
- struct proc *p;
ar = currecord();
if (ar == NULL)
ar->k_ar.ar_arg_pid = pid;
ar->k_ar.ar_valid_arg |= ARG_PID;
-
}
void
-audit_arg_process(struct proc *p)
+audit_arg_process(proc_t p)
{
struct kaudit_record *ar;
+ kauth_cred_t my_cred;
ar = currecord();
if ((ar == NULL) || (p == NULL))
return;
- /* XXX May need to lock the credentials structures */
- ar->k_ar.ar_arg_auid = p->p_au->ai_auid;
- ar->k_ar.ar_arg_euid = p->p_ucred->cr_uid;
- ar->k_ar.ar_arg_egid = p->p_ucred->cr_groups[0];
- ar->k_ar.ar_arg_ruid = p->p_cred->p_ruid;
- ar->k_ar.ar_arg_rgid = p->p_cred->p_rgid;
- ar->k_ar.ar_arg_asid = p->p_au->ai_asid;
-
- ar->k_ar.ar_arg_termid = p->p_au->ai_termid;
+ my_cred = kauth_cred_proc_ref(p);
+ ar->k_ar.ar_arg_auid = my_cred->cr_au.ai_auid;
+ ar->k_ar.ar_arg_euid = my_cred->cr_uid;
+ ar->k_ar.ar_arg_egid = my_cred->cr_groups[0];
+ ar->k_ar.ar_arg_ruid = my_cred->cr_ruid;
+ ar->k_ar.ar_arg_rgid = my_cred->cr_rgid;
+ ar->k_ar.ar_arg_asid = my_cred->cr_au.ai_asid;
+ ar->k_ar.ar_arg_termid = my_cred->cr_au.ai_termid;
+ kauth_cred_unref(&my_cred);
ar->k_ar.ar_valid_arg |= ARG_AUID | ARG_EUID | ARG_EGID | ARG_RUID |
ARG_RGID | ARG_ASID | ARG_TERMID | ARG_PROCESS;
ar->k_ar.ar_valid_arg |= ARG_SOCKINFO;
}
+/*
+ * Note that the current working directory vp must be supplied at the audit
+ * call site to permit per thread current working directories, and that it
+ * must take a upath starting with '/' into account for chroot if the path
+ * is absolute. This results in the real (non-chroot) path being recorded
+ * in the audit record.
+ */
void
-audit_arg_sockaddr(struct proc *p, struct sockaddr *so)
+audit_arg_sockaddr(struct vnode *cwd_vp, struct sockaddr *so)
{
struct kaudit_record *ar;
ar = currecord();
- if (ar == NULL || p == NULL || so == NULL)
+ if (ar == NULL || cwd_vp == NULL || so == NULL)
return;
bcopy(so, &ar->k_ar.ar_arg_sockaddr, sizeof(ar->k_ar.ar_arg_sockaddr));
ar->k_ar.ar_valid_arg |= ARG_SADDRINET6;
break;
case AF_UNIX:
- audit_arg_upath(p, ((struct sockaddr_un *)so)->sun_path,
+ audit_arg_upath(cwd_vp, ((struct sockaddr_un *)so)->sun_path,
ARG_UPATH1);
ar->k_ar.ar_valid_arg |= ARG_SADDRUNIX;
break;
}
void
-audit_arg_auditinfo(struct auditinfo *au_info)
+audit_arg_auditinfo(const struct auditinfo *au_info)
{
struct kaudit_record *ar;
}
void
-audit_arg_text(char *text)
+audit_arg_text(const char *text)
{
struct kaudit_record *ar;
return;
}
- strncpy(ar->k_ar.ar_arg_text, text, MAXPATHLEN);
+ strlcpy(ar->k_ar.ar_arg_text, text, MAXPATHLEN);
ar->k_ar.ar_valid_arg |= ARG_TEXT;
}
}
void
-audit_arg_svipc_perm(struct ipc_perm *perm)
+audit_arg_svipc_perm(const struct ipc_perm *perm)
{
struct kaudit_record *ar;
}
void
-audit_arg_svipc_addr(void * addr)
+audit_arg_svipc_addr(user_addr_t addr)
{
struct kaudit_record *ar;
}
void
-audit_arg_auditon(union auditon_udata *udata)
+audit_arg_auditon(const union auditon_udata *udata)
{
struct kaudit_record *ar;
if (ar == NULL)
return;
- bcopy((void *)udata, &ar->k_ar.ar_arg_auditon,
+ bcopy((const void *)udata, &ar->k_ar.ar_arg_auditon,
sizeof(ar->k_ar.ar_arg_auditon));
ar->k_ar.ar_valid_arg |= ARG_AUDITON;
}
-/*
+/*
* Audit information about a file, either the file's vnode info, or its
* socket address info.
*/
void
-audit_arg_file(struct proc *p, struct file *fp)
+audit_arg_file(__unused proc_t p, const struct fileproc *fp)
{
struct kaudit_record *ar;
struct socket *so;
struct inpcb *pcb;
- if (fp->f_type == DTYPE_VNODE) {
- audit_arg_vnpath((struct vnode *)fp->f_data, ARG_VNODE1);
+ if (fp->f_fglob->fg_type == DTYPE_VNODE) {
+ audit_arg_vnpath_withref((struct vnode *)fp->f_fglob->fg_data, ARG_VNODE1);
return;
}
- if (fp->f_type == DTYPE_SOCKET) {
+ if (fp->f_fglob->fg_type == DTYPE_SOCKET) {
ar = currecord();
if (ar == NULL)
return;
- so = (struct socket *)fp->f_data;
+ so = (struct socket *)fp->f_fglob->fg_data;
if (INP_CHECK_SOCKAF(so, PF_INET)) {
if (so->so_pcb == NULL)
return;
}
-/*
- * Initialize the audit information for the a process, presumably the first
- * process in the system.
- * XXX It is not clear what the initial values should be for session ID,
- * terminal ID etc.
- */
-void
-audit_proc_init(struct proc *p)
-{
- MALLOC_ZONE(p->p_au, struct auditinfo *, sizeof(*p->p_au),
- M_SUBPROC, M_WAITOK);
-
- bzero((void *)p->p_au, sizeof(*p->p_au));
-
- p->p_au->ai_auid = AU_DEFAUDITID;
-}
-
-/*
- * Copy the audit info from the parent process to the child process when
- * a fork takes place.
- * XXX Need to check for failure from the memory allocation, in here
- * as well as in any functions that use the process auditing info.
- */
-void
-audit_proc_fork(struct proc *parent, struct proc *child)
-{
- /* Always set up the audit information pointer as this function
- * should only be called when the proc is new. If proc structures
- * are ever cached and reused, then this behavior will leak memory.
- */
- MALLOC_ZONE(child->p_au, struct auditinfo *, sizeof(*child->p_au),
- M_SUBPROC, M_WAITOK);
-
- bcopy(parent->p_au, child->p_au, sizeof(*child->p_au));
-}
-
-/*
- * Free the auditing structure for the process.
- */
-void
-audit_proc_free(struct proc *p)
-{
- FREE_ZONE((void *)p->p_au, sizeof(*p->p_au), M_SUBPROC);
- p->p_au = NULL;
-}
/*
* Store a path as given by the user process for auditing into the audit
* record stored on the user thread. This function will allocate the memory to
* store the path info if not already available. This memory will be
- * freed when the audit record is freed.
+ * freed when the audit record is freed. Note that the current working
+ * directory vp must be supplied at the audit call site to permit per thread
+ * current working directories, and that it must take a upath starting with
+ * '/' into account for chroot if the path is absolute. This results in the
+ * real (non-chroot) path being recorded in the audit record.
*/
void
-audit_arg_upath(struct proc *p, char *upath, u_int64_t flags)
+audit_arg_upath(struct vnode *cwd_vp, char *upath, u_int64_t flags)
{
struct kaudit_record *ar;
char **pathp;
- if (p == NULL || upath == NULL)
+ if (cwd_vp == NULL || upath == NULL)
return; /* nothing to do! */
- if (flags & (ARG_UPATH1 | ARG_UPATH2) == 0)
+ if ((flags & (ARG_UPATH1 | ARG_UPATH2)) == 0)
return;
ar = currecord();
return;
}
- if (canon_path(p, upath, *pathp) == 0) {
+ if (canon_path(cwd_vp, upath, *pathp) == 0) {
if (flags & ARG_UPATH1)
ar->k_ar.ar_valid_arg |= ARG_UPATH1;
else
ar->k_ar.ar_valid_arg |= ARG_UPATH2;
- } else {
- kfree((vm_offset_t)*pathp, MAXPATHLEN);
- *pathp = NULL;
+ } else {
+ kfree(*pathp, MAXPATHLEN);
+ *pathp = NULL;
}
}
* record.
*
* It is assumed that the caller will hold any vnode locks necessary to
- * perform a VOP_GETATTR() on the passed vnode.
+ * perform a VNOP_GETATTR() on the passed vnode.
*
* XXX: The attr code is very similar to vfs_vnops.c:vn_stat(), but
* always provides access to the generation number as we need that
audit_arg_vnpath(struct vnode *vp, u_int64_t flags)
{
struct kaudit_record *ar;
- struct vattr vattr;
+ struct vnode_attr va;
int error;
int len;
char **pathp;
struct vnode_au_info *vnp;
- struct proc *p;
+ proc_t p;
+#if CONFIG_MACF
+ char **vnode_mac_labelp;
+ struct mac mac;
+#endif
if (vp == NULL)
return;
if (ar == NULL) /* This will be the case for unaudited system calls */
return;
- if (flags & (ARG_VNODE1 | ARG_VNODE2) == 0)
+ if ((flags & (ARG_VNODE1 | ARG_VNODE2)) == 0)
return;
p = current_proc();
ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE1);
pathp = &ar->k_ar.ar_arg_kpath1;
vnp = &ar->k_ar.ar_arg_vnode1;
+#if CONFIG_MACF
+ vnode_mac_labelp = &ar->k_ar.ar_vnode1_mac_labels;
+#endif
}
else {
ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_KPATH2);
ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE2);
pathp = &ar->k_ar.ar_arg_kpath2;
vnp = &ar->k_ar.ar_arg_vnode2;
+#if CONFIG_MACF
+ vnode_mac_labelp = &ar->k_ar.ar_vnode2_mac_labels;
+#endif
}
if (*pathp == NULL) {
*/
len = MAXPATHLEN;
if (vn_getpath(vp, *pathp, &len) == 0) {
- if (flags & ARG_VNODE1)
- ar->k_ar.ar_valid_arg |= ARG_KPATH1;
- else
- ar->k_ar.ar_valid_arg |= ARG_KPATH2;
+ if (flags & ARG_VNODE1)
+ ar->k_ar.ar_valid_arg |= ARG_KPATH1;
+ else
+ ar->k_ar.ar_valid_arg |= ARG_KPATH2;
} else {
- kfree((vm_offset_t)*pathp, MAXPATHLEN);
+ kfree(*pathp, MAXPATHLEN);
*pathp = NULL;
}
- /*
- * XXX: We'd assert the vnode lock here, only Darwin doesn't
- * appear to have vnode locking assertions.
- */
- error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
+ VATTR_INIT(&va);
+ VATTR_WANTED(&va, va_mode);
+ VATTR_WANTED(&va, va_uid);
+ VATTR_WANTED(&va, va_gid);
+ VATTR_WANTED(&va, va_rdev);
+ VATTR_WANTED(&va, va_fsid);
+ VATTR_WANTED(&va, va_fileid);
+ VATTR_WANTED(&va, va_gen);
+ error = vnode_getattr(vp, &va, vfs_context_current());
if (error) {
/* XXX: How to handle this case? */
return;
}
- vnp->vn_mode = vattr.va_mode;
- vnp->vn_uid = vattr.va_uid;
- vnp->vn_gid = vattr.va_gid;
- vnp->vn_dev = vattr.va_rdev;
- vnp->vn_fsid = vattr.va_fsid;
- vnp->vn_fileid = vattr.va_fileid;
- vnp->vn_gen = vattr.va_gen;
+#if CONFIG_MACF
+ if (*vnode_mac_labelp == NULL) {
+ *vnode_mac_labelp = (char *)zalloc(audit_mac_label_zone);
+ if (*vnode_mac_labelp != NULL) {
+ mac.m_buflen = MAC_AUDIT_LABEL_LEN;
+ mac.m_string = *vnode_mac_labelp;
+ mac_vnode_label_externalize_audit(vp, &mac);
+ }
+
+
+
+ }
+#endif
+
+ /* XXX do we want to fall back here when these aren't supported? */
+ vnp->vn_mode = va.va_mode;
+ vnp->vn_uid = va.va_uid;
+ vnp->vn_gid = va.va_gid;
+ vnp->vn_dev = va.va_rdev;
+ vnp->vn_fsid = va.va_fsid;
+ vnp->vn_fileid = (u_long)va.va_fileid;
+ vnp->vn_gen = va.va_gen;
if (flags & ARG_VNODE1)
ar->k_ar.ar_valid_arg |= ARG_VNODE1;
else
}
void
-audit_arg_mach_port1(mach_port_t port)
+audit_arg_vnpath_withref(struct vnode *vp, u_int64_t flags)
+{
+ if (vp == NULL || vnode_getwithref(vp))
+ return;
+ audit_arg_vnpath(vp, flags);
+ (void)vnode_put(vp);
+}
+
+void
+audit_arg_mach_port1(mach_port_name_t port)
{
struct kaudit_record *ar;
}
void
-audit_arg_mach_port2(mach_port_t port)
+audit_arg_mach_port2(mach_port_name_t port)
{
struct kaudit_record *ar;
* within the system call itself.
*/
void
-audit_sysclose(struct proc *p, int fd)
+audit_sysclose(proc_t p, int fd)
{
- struct file *fp;
+ struct fileproc *fp;
+ struct vnode *vp;
audit_arg_fd(fd);
- if (getvnode(p, fd, &fp) != 0)
+ if (fp_getfvp(p, fd, &fp, &vp) != 0)
return;
- audit_arg_vnpath((struct vnode *)fp->f_data, ARG_VNODE1);
-
+ audit_arg_vnpath_withref((struct vnode *)fp->f_fglob->fg_data, ARG_VNODE1);
+ file_drop(fd);
}
+#if CONFIG_MACF
+/*
+ * This function is called by the MAC Framework to add audit data
+ * from a policy to the current audit record.
+ */
+int
+audit_mac_data(int type, int len, u_char *data) {
+ struct kaudit_record *cur;
+ struct mac_audit_record *record;
+ int ret = 0;
+
+ if (audit_enabled == 0) {
+ ret = ENOTSUP;
+ goto out_fail;
+ }
+
+ cur = currecord();
+ if (cur == NULL) {
+ ret = ENOTSUP;
+ goto out_fail;
+ }
+
+ /*
+ * XXX: Note that we silently drop the audit data if this
+ * allocation fails - this is consistent with the rest of the
+ * audit implementation.
+ */
+ record = (struct mac_audit_record *)kalloc(sizeof(*record));
+ if (record == NULL)
+ goto out_fail;
+
+ record->type = type;
+ record->length = len;
+ record->data = data;
+ LIST_INSERT_HEAD(cur->k_ar.ar_mac_records, record, records);
+
+ return (0);
+
+out_fail:
+ kfree(data, len);
+ return (ret);
+}
+
+void
+audit_arg_mac_string(const char *string)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ if (ar->k_ar.ar_arg_mac_string == NULL) {
+ ar->k_ar.ar_arg_mac_string =
+ (char *)kalloc(MAC_MAX_LABEL_BUF_LEN + MAC_ARG_PREFIX_LEN);
+ /* This should be a rare event. If kalloc() returns NULL, the
+ * system is low on kernel virtual memory. To be consistent with the
+ * rest of audit, just return (may need to panic if required to for audit6).
+ */
+ if (ar->k_ar.ar_arg_mac_string == NULL)
+ return;
+ }
+ strncpy(ar->k_ar.ar_arg_mac_string, MAC_ARG_PREFIX, MAC_ARG_PREFIX_LEN);
+ strncpy(ar->k_ar.ar_arg_mac_string + MAC_ARG_PREFIX_LEN, string, MAC_MAX_LABEL_BUF_LEN);
+ ar->k_ar.ar_valid_arg |= ARG_MAC_STRING;
+
+}
+#endif /* MAC */
+
+/*
+ * kau_will_audit can be used by a security policy to determine
+ * if an audit record will be stored, reducing wasted memory allocation
+ * and string handling.
+ */
+
+int
+kau_will_audit(void)
+{
+
+ return (audit_enabled && currecord() != NULL);
+}
+
#else /* !AUDIT */
void
}
int
-audit(struct proc *p, struct audit_args *uap, register_t *retval)
+audit(proc_t p, struct audit_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-auditon(struct proc *p, struct auditon_args *uap, register_t *retval)
+auditon(proc_t p, struct auditon_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-getauid(struct proc *p, struct getauid_args *uap, register_t *retval)
+getauid(proc_t p, struct getauid_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-setauid(struct proc *p, struct setauid_args *uap, register_t *retval)
+setauid(proc_t p, struct setauid_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-getaudit(struct proc *p, struct getaudit_args *uap, register_t *retval)
+getaudit(proc_t p, struct getaudit_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-setaudit(struct proc *p, struct setaudit_args *uap, register_t *retval)
+setaudit(proc_t p, struct setaudit_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-getaudit_addr(struct proc *p, struct getaudit_addr_args *uap, register_t *retval)
+getaudit_addr(proc_t p, struct getaudit_addr_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-setaudit_addr(struct proc *p, struct setaudit_addr_args *uap, register_t *retval)
+setaudit_addr(proc_t p, struct setaudit_addr_args *uap, register_t *retval)
{
return (ENOSYS);
}
int
-auditctl(struct proc *p, struct auditctl_args *uap, register_t *retval)
+auditctl(proc_t p, struct auditctl_args *uap, register_t *retval)
{
return (ENOSYS);
}
+#if CONFIG_MACF
void
-audit_proc_init(struct proc *p)
+audit_mac_data(int type, int len, u_char *data)
{
-
-}
-
-void
-audit_proc_fork(struct proc *parent, struct proc *child)
-{
-
}
-void
-audit_proc_free(struct proc *p)
+int
+kau_will_audit()
{
-
+ return (0);
}
+#endif
#endif /* AUDIT */