diff options
Diffstat (limited to 'sys/security/audit/audit_bsm_klib.c')
| -rw-r--r-- | sys/security/audit/audit_bsm_klib.c | 143 |
1 files changed, 142 insertions, 1 deletions
diff --git a/sys/security/audit/audit_bsm_klib.c b/sys/security/audit/audit_bsm_klib.c index f44fac9d26a1..915b60356750 100644 --- a/sys/security/audit/audit_bsm_klib.c +++ b/sys/security/audit/audit_bsm_klib.c @@ -1,8 +1,13 @@ /* * Copyright (c) 1999-2009 Apple Inc. - * Copyright (c) 2005 Robert N. M. Watson + * Copyright (c) 2005, 2016 Robert N. M. Watson * All rights reserved. * + * Portions of this software were developed by BAE Systems, the University of + * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL + * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent + * Computing (TC) research program. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/rwlock.h> #include <sys/sem.h> #include <sys/sbuf.h> +#include <sys/sx.h> #include <sys/syscall.h> #include <sys/sysctl.h> #include <sys/sysent.h> @@ -76,6 +82,30 @@ static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE]; #define EVCLASS_WLOCK() rw_wlock(&evclass_lock) #define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock) +/* + * Hash table maintaining a mapping from audit event numbers to audit event + * names. For now, used only by DTrace, but present always so that userspace + * tools can register and inspect fields consistently even if DTrace is not + * present. + * + * struct evname_elem is defined in audit_private.h so that audit_dtrace.c can + * use the definition. + */ +#define EVNAMEMAP_HASH_TABLE_SIZE 251 +struct evname_list { + LIST_HEAD(, evname_elem) enl_head; +}; + +static MALLOC_DEFINE(M_AUDITEVNAME, "audit_evname", "Audit event name"); +static struct sx evnamemap_lock; +static struct evname_list evnamemap_hash[EVNAMEMAP_HASH_TABLE_SIZE]; + +#define EVNAMEMAP_LOCK_INIT() sx_init(&evnamemap_lock, "evnamemap_lock"); +#define EVNAMEMAP_RLOCK() sx_slock(&evnamemap_lock) +#define EVNAMEMAP_RUNLOCK() sx_sunlock(&evnamemap_lock) +#define EVNAMEMAP_WLOCK() sx_xlock(&evnamemap_lock) +#define EVNAMEMAP_WUNLOCK() sx_xunlock(&evnamemap_lock) + struct aue_open_event { int aoe_flags; au_event_t aoe_event; @@ -222,6 +252,117 @@ au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf) } /* + * Look up the name for an audit event in the event-to-name mapping table. + */ +int +au_event_name(au_event_t event, char *name) +{ + struct evname_list *enl; + struct evname_elem *ene; + int error; + + error = ENOENT; + EVNAMEMAP_RLOCK(); + enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE]; + LIST_FOREACH(ene, &enl->enl_head, ene_entry) { + if (ene->ene_event == event) { + strlcpy(name, ene->ene_name, EVNAMEMAP_NAME_SIZE); + error = 0; + goto out; + } + } +out: + EVNAMEMAP_RUNLOCK(); + return (error); +} + +/* + * Insert a event-to-name mapping. If the event already exists in the + * mapping, then replace the mapping with the new one. + * + * XXX There is currently no constraints placed on the number of mappings. + * May want to either limit to a number, or in terms of memory usage. + * + * XXXRW: Accepts truncated name -- but perhaps should return failure instead? + * + * XXXRW: It could be we need a way to remove existing names...? + * + * XXXRW: We handle collisions between numbers, but I wonder if we also need a + * way to handle name collisions, for DTrace, where probe names must be + * unique? + */ +void +au_evnamemap_insert(au_event_t event, const char *name) +{ + struct evname_list *enl; + struct evname_elem *ene, *ene_new; + + /* + * Pessimistically, always allocate storage before acquiring lock. + * Free if there is already a mapping for this event. + */ + ene_new = malloc(sizeof(*ene_new), M_AUDITEVNAME, M_WAITOK | M_ZERO); + EVNAMEMAP_WLOCK(); + enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE]; + LIST_FOREACH(ene, &enl->enl_head, ene_entry) { + if (ene->ene_event == event) { + EVNAME_LOCK(ene); + (void)strlcpy(ene->ene_name, name, + sizeof(ene->ene_name)); + EVNAME_UNLOCK(ene); + EVNAMEMAP_WUNLOCK(); + free(ene_new, M_AUDITEVNAME); + return; + } + } + ene = ene_new; + mtx_init(&ene->ene_lock, "au_evnamemap", NULL, MTX_DEF); + ene->ene_event = event; + (void)strlcpy(ene->ene_name, name, sizeof(ene->ene_name)); + LIST_INSERT_HEAD(&enl->enl_head, ene, ene_entry); + EVNAMEMAP_WUNLOCK(); +} + +void +au_evnamemap_init(void) +{ + int i; + + EVNAMEMAP_LOCK_INIT(); + for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++) + LIST_INIT(&evnamemap_hash[i].enl_head); + + /* + * XXXRW: Unlike the event-to-class mapping, we don't attempt to + * pre-populate the list. Perhaps we should...? But not sure we + * really want to duplicate /etc/security/audit_event in the kernel + * -- and we'd need a way to remove names? + */ +} + +/* + * The DTrace audit provider occasionally needs to walk the entries in the + * event-to-name mapping table, and uses this public interface to do so. A + * write lock is acquired so that the provider can safely update its fields in + * table entries. + */ +void +au_evnamemap_foreach(au_evnamemap_callback_t callback) +{ + struct evname_list *enl; + struct evname_elem *ene; + int i; + + EVNAMEMAP_WLOCK(); + for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++) { + enl = &evnamemap_hash[i]; + LIST_FOREACH(ene, &enl->enl_head, ene_entry) + callback(ene); + } + EVNAMEMAP_WUNLOCK(); +} + +/* * Convert sysctl names and present arguments to events. */ au_event_t |
