/*-
- * Copyright (c) 2008-2009 Apple Inc.
+ * Copyright (c) 2008-2010 Apple Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <mach/host_priv.h>
#include <mach/host_special_ports.h>
#include <mach/audit_triggers_server.h>
+#include <mach/audit_triggers_types.h>
+
+#include <os/overflow.h>
+
+extern void ipc_port_release_send(ipc_port_t port);
#if CONFIG_AUDIT
struct mhdr {
- size_t mh_size;
- au_malloc_type_t *mh_type;
- u_long mh_magic;
- char mh_data[0];
+ size_t mh_size;
+ au_malloc_type_t *mh_type;
+ u_long mh_magic;
+ char mh_data[0];
};
-#define AUDIT_MHMAGIC 0x4D656C53
+/*
+ * The lock group for the audit subsystem.
+ */
+static LCK_GRP_DECLARE(audit_lck_grp, "Audit");
+
+#define AUDIT_MHMAGIC 0x4D656C53
#if AUDIT_MALLOC_DEBUG
-#define AU_MAX_SHORTDESC 20
-#define AU_MAX_LASTCALLER 20
+#define AU_MAX_SHORTDESC 20
+#define AU_MAX_LASTCALLER 20
struct au_malloc_debug_info {
- SInt64 md_size;
- SInt64 md_maxsize;
- SInt32 md_inuse;
- SInt32 md_maxused;
- unsigned md_type;
- unsigned md_magic;
- char md_shortdesc[AU_MAX_SHORTDESC];
- char md_lastcaller[AU_MAX_LASTCALLER];
+ SInt64 md_size;
+ SInt64 md_maxsize;
+ SInt32 md_inuse;
+ SInt32 md_maxused;
+ unsigned md_type;
+ unsigned md_magic;
+ char md_shortdesc[AU_MAX_SHORTDESC];
+ char md_lastcaller[AU_MAX_LASTCALLER];
};
typedef struct au_malloc_debug_info au_malloc_debug_info_t;
-au_malloc_type_t *audit_malloc_types[NUM_MALLOC_TYPES];
+au_malloc_type_t *audit_malloc_types[NUM_MALLOC_TYPES];
static int audit_sysctl_malloc_debug(struct sysctl_oid *oidp, void *arg1,
int arg2, struct sysctl_req *req);
audit_sysctl_malloc_debug, "S,audit_malloc_debug",
"Current malloc debug info for auditing.");
-#define AU_MALLOC_DBINFO_SZ \
+#define AU_MALLOC_DBINFO_SZ \
(NUM_MALLOC_TYPES * sizeof(au_malloc_debug_info_t))
/*
- * Copy out the malloc debug info via the sysctl interface. The userland code
+ * Copy out the malloc debug info via the sysctl interface. The userland code
* is something like the following:
*
* error = sysctlbyname("kern.audit_malloc_debug", buffer_ptr, &buffer_len,
/*
* This provides a read-only node.
*/
- if (req->newptr != USER_ADDR_NULL)
- return (EPERM);
+ if (req->newptr != USER_ADDR_NULL) {
+ return EPERM;
+ }
/*
- * If just querying then return the space required.
+ * If just querying then return the space required.
*/
if (req->oldptr == USER_ADDR_NULL) {
- req->oldidx = AU_MALLOC_DBINFO_SZ;
- return (0);
+ req->oldidx = AU_MALLOC_DBINFO_SZ;
+ return 0;
}
/*
* Alloc a temporary buffer.
*/
- if (req->oldlen < AU_MALLOC_DBINFO_SZ)
- return (ENOMEM);
- amdi_ptr = (au_malloc_debug_info_t *)kalloc(AU_MALLOC_DBINFO_SZ);
- if (amdi_ptr == NULL)
- return (ENOMEM);
- bzero(amdi_ptr, AU_MALLOC_DBINFO_SZ);
+ if (req->oldlen < AU_MALLOC_DBINFO_SZ) {
+ return ENOMEM;
+ }
+ amdi_ptr = kheap_alloc(KHEAP_TEMP, AU_MALLOC_DBINFO_SZ, Z_WAITOK | Z_ZERO);
+ if (amdi_ptr == NULL) {
+ return ENOMEM;
+ }
/*
- * Build the record array.
+ * Build the record array.
*/
sz = 0;
nxt_ptr = amdi_ptr;
- for(i = 0; i < NUM_MALLOC_TYPES; i++) {
- if (audit_malloc_types[i] == NULL)
+ for (i = 0; i < NUM_MALLOC_TYPES; i++) {
+ if (audit_malloc_types[i] == NULL) {
continue;
+ }
if (audit_malloc_types[i]->mt_magic != M_MAGIC) {
nxt_ptr->md_magic = audit_malloc_types[i]->mt_magic;
continue;
strlcpy(nxt_ptr->md_shortdesc,
audit_malloc_types[i]->mt_shortdesc, AU_MAX_SHORTDESC - 1);
strlcpy(nxt_ptr->md_lastcaller,
- audit_malloc_types[i]->mt_lastcaller, AU_MAX_LASTCALLER-1);
+ audit_malloc_types[i]->mt_lastcaller, AU_MAX_LASTCALLER - 1);
sz += sizeof(au_malloc_debug_info_t);
nxt_ptr++;
}
req->oldlen = sz;
err = SYSCTL_OUT(req, amdi_ptr, sz);
- kfree(amdi_ptr, AU_MALLOC_DBINFO_SZ);
+ kheap_free(KHEAP_TEMP, amdi_ptr, AU_MALLOC_DBINFO_SZ);
- return (err);
+ return err;
}
#endif /* AUDIT_MALLOC_DEBUG */
-
+
/*
* BSD malloc()
- *
+ *
* If the M_NOWAIT flag is set then it may not block and return NULL.
* If the M_ZERO flag is set then zero out the buffer.
*/
#if AUDIT_MALLOC_DEBUG
_audit_malloc(size_t size, au_malloc_type_t *type, int flags, const char *fn)
#else
-_audit_malloc(size_t size, au_malloc_type_t *type, int flags)
+_audit_malloc(size_t size, au_malloc_type_t * type, int flags)
#endif
{
- union {
- struct mhdr hdr;
- char mem[size + sizeof (struct mhdr)];
- } *mem;
- size_t memsize = sizeof (*mem);
-
- if (size == 0)
- return (NULL);
- if (flags & M_NOWAIT) {
- mem = (void *)kalloc_noblock(memsize);
- } else {
- mem = (void *)kalloc(memsize);
- if (mem == NULL)
- panic("_audit_malloc: kernel memory exhausted");
- }
- if (mem == NULL)
- return (NULL);
- mem->hdr.mh_size = memsize;
- mem->hdr.mh_type = type;
- mem->hdr.mh_magic = AUDIT_MHMAGIC;
- if (flags & M_ZERO)
- memset(mem->hdr.mh_data, 0, size);
+ struct mhdr *hdr;
+ size_t memsize;
+ if (os_add_overflow(sizeof(*hdr), size, &memsize)) {
+ return NULL;
+ }
+
+ if (size == 0) {
+ return NULL;
+ }
+ hdr = kheap_alloc(KHEAP_AUDIT, memsize, flags);
+ if (hdr == NULL) {
+ return NULL;
+ }
+ hdr->mh_size = memsize;
+ hdr->mh_type = type;
+ hdr->mh_magic = AUDIT_MHMAGIC;
#if AUDIT_MALLOC_DEBUG
if (type != NULL && type->mt_type < NUM_MALLOC_TYPES) {
OSAddAtomic64(memsize, &type->mt_size);
audit_malloc_types[type->mt_type] = type;
}
#endif /* AUDIT_MALLOC_DEBUG */
- return (mem->hdr.mh_data);
+ return hdr->mh_data;
}
/*
#endif
{
struct mhdr *hdr;
-
- if (addr == NULL)
+
+ if (addr == NULL) {
return;
+ }
hdr = addr; hdr--;
- KASSERT(hdr->mh_magic == AUDIT_MHMAGIC,
- ("_audit_free(): hdr->mh_magic != AUDIT_MHMAGIC"));
+ if (hdr->mh_magic != AUDIT_MHMAGIC) {
+ panic("_audit_free(): hdr->mh_magic (%lx) != AUDIT_MHMAGIC", hdr->mh_magic);
+ }
#if AUDIT_MALLOC_DEBUG
if (type != NULL) {
OSAddAtomic(-1, &type->mt_inuse);
}
#endif /* AUDIT_MALLOC_DEBUG */
- kfree(hdr, hdr->mh_size);
+ kheap_free(KHEAP_AUDIT, hdr, hdr->mh_size);
}
/*
void
_audit_cv_init(struct cv *cvp, const char *desc)
{
-
- if (desc == NULL)
+ if (desc == NULL) {
cvp->cv_description = "UNKNOWN";
- else
+ } else {
cvp->cv_description = desc;
+ }
cvp->cv_waiters = 0;
}
void
_audit_cv_destroy(struct cv *cvp)
{
-
cvp->cv_description = NULL;
cvp->cv_waiters = 0;
}
void
_audit_cv_signal(struct cv *cvp)
{
-
if (cvp->cv_waiters > 0) {
wakeup_one((caddr_t)cvp);
cvp->cv_waiters--;
void
_audit_cv_broadcast(struct cv *cvp)
{
-
if (cvp->cv_waiters > 0) {
wakeup((caddr_t)cvp);
cvp->cv_waiters = 0;
void
_audit_cv_wait(struct cv *cvp, lck_mtx_t *mp, const char *desc)
{
-
cvp->cv_waiters++;
(void) msleep(cvp, mp, PZERO, desc, 0);
}
int
_audit_cv_wait_sig(struct cv *cvp, lck_mtx_t *mp, const char *desc)
{
-
cvp->cv_waiters++;
- return (msleep(cvp, mp, PSOCK | PCATCH, desc, 0));
+ return msleep(cvp, mp, PSOCK | PCATCH, desc, 0);
}
/*
- * Simple recursive lock.
+ * BSD Mutexes.
*/
void
-_audit_rlck_init(struct rlck *lp, const char *grpname)
+#if DIAGNOSTIC
+_audit_mtx_init(struct mtx *mp, const char *lckname)
+#else
+_audit_mtx_init(struct mtx *mp, __unused const char *lckname)
+#endif
+{
+ mp->mtx_lock = lck_mtx_alloc_init(&audit_lck_grp, LCK_ATTR_NULL);
+ KASSERT(mp->mtx_lock != NULL,
+ ("_audit_mtx_init: Could not allocate a mutex."));
+#if DIAGNOSTIC
+ strlcpy(mp->mtx_name, lckname, AU_MAX_LCK_NAME);
+#endif
+}
+
+void
+_audit_mtx_destroy(struct mtx *mp)
+{
+ if (mp->mtx_lock) {
+ lck_mtx_free(mp->mtx_lock, &audit_lck_grp);
+ mp->mtx_lock = NULL;
+ }
+}
+
+/*
+ * BSD rw locks.
+ */
+void
+#if DIAGNOSTIC
+_audit_rw_init(struct rwlock *lp, const char *lckname)
+#else
+_audit_rw_init(struct rwlock *lp, __unused const char *lckname)
+#endif
+{
+ lp->rw_lock = lck_rw_alloc_init(&audit_lck_grp, LCK_ATTR_NULL);
+ KASSERT(lp->rw_lock != NULL,
+ ("_audit_rw_init: Could not allocate a rw lock."));
+#if DIAGNOSTIC
+ strlcpy(lp->rw_name, lckname, AU_MAX_LCK_NAME);
+#endif
+}
+
+void
+_audit_rw_destroy(struct rwlock *lp)
+{
+ if (lp->rw_lock) {
+ lck_rw_free(lp->rw_lock, &audit_lck_grp);
+ lp->rw_lock = NULL;
+ }
+}
+/*
+ * Wait on a condition variable in a continuation (i.e. yield kernel stack).
+ * A cv_signal or cv_broadcast on the same condition variable will cause
+ * the thread to be scheduled.
+ */
+int
+_audit_cv_wait_continuation(struct cv *cvp, lck_mtx_t *mp, thread_continue_t function)
{
+ int status = KERN_SUCCESS;
- lp->rl_grp = lck_grp_alloc_init(grpname, LCK_GRP_ATTR_NULL);
- lp->rl_mtx = lck_mtx_alloc_init(lp->rl_grp, LCK_ATTR_NULL);
+ cvp->cv_waiters++;
+ assert_wait(cvp, THREAD_UNINT);
+ lck_mtx_unlock(mp);
+ status = thread_block(function);
+
+ /* should not be reached, but just in case, re-lock */
+ lck_mtx_lock(mp);
+
+ return status;
+}
+
+/*
+ * Simple recursive lock.
+ */
+void
+#if DIAGNOSTIC
+_audit_rlck_init(struct rlck *lp, const char *lckname)
+#else
+_audit_rlck_init(struct rlck *lp, __unused const char *lckname)
+#endif
+{
+ lp->rl_mtx = lck_mtx_alloc_init(&audit_lck_grp, LCK_ATTR_NULL);
+ KASSERT(lp->rl_mtx != NULL,
+ ("_audit_rlck_init: Could not allocate a recursive lock."));
+#if DIAGNOSTIC
+ strlcpy(lp->rl_name, lckname, AU_MAX_LCK_NAME);
+#endif
lp->rl_thread = 0;
lp->rl_recurse = 0;
}
/*
* Recursive lock. Allow same thread to recursively lock the same lock.
- */
+ */
void
_audit_rlck_lock(struct rlck *lp)
{
-
if (lp->rl_thread == current_thread()) {
OSAddAtomic(1, &lp->rl_recurse);
KASSERT(lp->rl_recurse < 10000,
void
_audit_rlck_unlock(struct rlck *lp)
{
- KASSERT(lp->rl_thread == current_thread(),
+ KASSERT(lp->rl_thread == current_thread(),
("_audit_rlck_unlock(): Don't own lock."));
/* Note: OSAddAtomic returns old value. */
lck_mtx_unlock(lp->rl_mtx);
}
}
-
+
void
_audit_rlck_destroy(struct rlck *lp)
{
-
if (lp->rl_mtx) {
- lck_mtx_free(lp->rl_mtx, lp->rl_grp);
- lp->rl_mtx = 0;
- }
- if (lp->rl_grp) {
- lck_grp_free(lp->rl_grp);
- lp->rl_grp = 0;
+ lck_mtx_free(lp->rl_mtx, &audit_lck_grp);
+ lp->rl_mtx = NULL;
}
}
_audit_rlck_assert(struct rlck *lp, u_int assert)
{
thread_t cthd = current_thread();
-
- if (assert == LCK_MTX_ASSERT_OWNED && lp->rl_thread == cthd)
+
+ if (assert == LCK_MTX_ASSERT_OWNED && lp->rl_thread == cthd) {
panic("recursive lock (%p) not held by this thread (%p).",
lp, cthd);
- if (assert == LCK_MTX_ASSERT_NOTOWNED && lp->rl_thread != 0)
+ }
+ if (assert == LCK_MTX_ASSERT_NOTOWNED && lp->rl_thread != 0) {
panic("recursive lock (%p) held by thread (%p).",
lp, cthd);
+ }
}
/*
* Simple sleep lock.
*/
void
-_audit_slck_init(struct slck *lp, const char *grpname)
+#if DIAGNOSTIC
+_audit_slck_init(struct slck *lp, const char *lckname)
+#else
+_audit_slck_init(struct slck *lp, __unused const char *lckname)
+#endif
{
-
- lp->sl_grp = lck_grp_alloc_init(grpname, LCK_GRP_ATTR_NULL);
- lp->sl_mtx = lck_mtx_alloc_init(lp->sl_grp, LCK_ATTR_NULL);
-
+ lp->sl_mtx = lck_mtx_alloc_init(&audit_lck_grp, LCK_ATTR_NULL);
+ KASSERT(lp->sl_mtx != NULL,
+ ("_audit_slck_init: Could not allocate a sleep lock."));
+#if DIAGNOSTIC
+ strlcpy(lp->sl_name, lckname, AU_MAX_LCK_NAME);
+#endif
lp->sl_locked = 0;
lp->sl_waiting = 0;
}
/*
* Sleep lock lock. The 'intr' flag determines if the lock is interruptible.
- * If 'intr' is true then signals or other events can interrupt the sleep lock.
+ * If 'intr' is true then signals or other events can interrupt the sleep lock.
*/
wait_result_t
_audit_slck_lock(struct slck *lp, int intr)
while (lp->sl_locked && res == THREAD_AWAKENED) {
lp->sl_waiting = 1;
res = lck_mtx_sleep(lp->sl_mtx, LCK_SLEEP_DEFAULT,
- (event_t) lp, (intr) ? THREAD_INTERRUPTIBLE : THREAD_UNINT);
+ (event_t) lp, (intr) ? THREAD_INTERRUPTIBLE : THREAD_UNINT);
}
- if (res == THREAD_AWAKENED)
+ if (res == THREAD_AWAKENED) {
lp->sl_locked = 1;
+ }
lck_mtx_unlock(lp->sl_mtx);
-
- return (res);
+
+ return res;
}
/*
void
_audit_slck_unlock(struct slck *lp)
{
-
lck_mtx_lock(lp->sl_mtx);
lp->sl_locked = 0;
if (lp->sl_waiting) {
lp->sl_waiting = 0;
/* Wake up *all* sleeping threads. */
- thread_wakeup_prim((event_t) lp, /*1 thr*/ 0, THREAD_AWAKENED);
+ wakeup((event_t) lp);
}
lck_mtx_unlock(lp->sl_mtx);
}
/*
- * Sleep lock try. Don't sleep if it doesn't get the lock.
+ * Sleep lock try. Don't sleep if it doesn't get the lock.
*/
int
_audit_slck_trylock(struct slck *lp)
lck_mtx_lock(lp->sl_mtx);
result = !lp->sl_locked;
- if (result)
+ if (result) {
lp->sl_locked = 1;
+ }
lck_mtx_unlock(lp->sl_mtx);
- return (result);
+ return result;
}
/*
void
_audit_slck_assert(struct slck *lp, u_int assert)
{
-
- if (assert == LCK_MTX_ASSERT_OWNED && lp->sl_locked == 0)
+ if (assert == LCK_MTX_ASSERT_OWNED && lp->sl_locked == 0) {
panic("sleep lock (%p) not held.", lp);
- if (assert == LCK_MTX_ASSERT_NOTOWNED && lp->sl_locked == 1)
+ }
+ if (assert == LCK_MTX_ASSERT_NOTOWNED && lp->sl_locked == 1) {
panic("sleep lock (%p) held.", lp);
+ }
}
void
_audit_slck_destroy(struct slck *lp)
{
-
if (lp->sl_mtx) {
- lck_mtx_free(lp->sl_mtx, lp->sl_grp);
- lp->sl_mtx = 0;
- }
- if (lp->sl_grp) {
- lck_grp_free(lp->sl_grp);
- lp->sl_grp = 0;
+ lck_mtx_free(lp->sl_mtx, &audit_lck_grp);
+ lp->sl_mtx = NULL;
}
}
*/
#ifndef timersub
#define timersub(tvp, uvp, vvp) \
- do { \
- (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
- (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
- if ((vvp)->tv_usec < 0) { \
- (vvp)->tv_sec--; \
- (vvp)->tv_usec += 1000000; \
- } \
- } while (0)
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
#endif
/*
*lasttime = tv;
*curpps = 0;
rv = 1;
- } else if (maxpps < 0)
+ } else if (maxpps < 0) {
rv = 1;
- else if (*curpps < maxpps)
+ } else if (*curpps < maxpps) {
rv = 1;
- else
+ } else {
rv = 0;
- if (*curpps + 1 > 0)
+ }
+ if (*curpps + 1 > 0) {
*curpps = *curpps + 1;
+ }
- return (rv);
+ return rv;
}
int
error = host_get_audit_control_port(host_priv_self(), &audit_port);
if (error == KERN_SUCCESS && audit_port != MACH_PORT_NULL) {
- audit_triggers(audit_port, trigger);
- return (0);
+ (void)audit_triggers(audit_port, trigger);
+ ipc_port_release_send(audit_port);
+ return 0;
} else {
printf("Cannot get audit control port\n");
- return (error);
+ return error;
}
}
+
+int
+audit_send_analytics(char* signing_id, char* process_name)
+{
+ mach_port_t audit_port;
+ int error;
+
+ error = host_get_audit_control_port(host_priv_self(), &audit_port);
+ if (error == KERN_SUCCESS && audit_port != MACH_PORT_NULL) {
+ (void)audit_analytics(audit_port, signing_id, process_name);
+ ipc_port_release_send(audit_port);
+ return 0;
+ } else {
+ printf("Cannot get audit control port for analytics \n");
+ return error;
+ }
+}
+
#endif /* CONFIG_AUDIT */