aboutsummaryrefslogtreecommitdiff
path: root/sys/security
diff options
context:
space:
mode:
authorRobert Watson <rwatson@FreeBSD.org>2017-03-27 10:38:53 +0000
committerRobert Watson <rwatson@FreeBSD.org>2017-03-27 10:38:53 +0000
commit759c8caa5a6889ee891b1072f9dd4ada7cccf913 (patch)
treeb88313a0893a47d5a3c7ce4e522a1afded8305d8 /sys/security
parentd9da46bf1c036565b34651b2ff624404959323a5 (diff)
downloadsrc-759c8caa5a6889ee891b1072f9dd4ada7cccf913.tar.gz
src-759c8caa5a6889ee891b1072f9dd4ada7cccf913.zip
Introduce an audit event identifier -> audit event name mapping
database in the kernel audit implementation, similar the exist class mapping database. This will be used by the DTrace audit provider to map audit event identifiers originating in the system-call table back into strings for the purposes of setting probe names. The database is initialised and maintained by auditd(8), which reads values in from the audit_events configuration file, and then manages them using the A_GETEVENT and A_SETEVENT auditon(2) operations. Obtained from: TrustedBSD Project Sponsored by: DARPA, AFRL MFC after: 3 weeks
Notes
Notes: svn path=/head/; revision=316018
Diffstat (limited to 'sys/security')
-rw-r--r--sys/security/audit/audit_bsm.c7
-rw-r--r--sys/security/audit/audit_bsm_klib.c143
-rw-r--r--sys/security/audit/audit_private.h39
-rw-r--r--sys/security/audit/audit_syscalls.c28
4 files changed, 216 insertions, 1 deletions
diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c
index 62f4d8527b61..5920d1b19779 100644
--- a/sys/security/audit/audit_bsm.c
+++ b/sys/security/audit/audit_bsm.c
@@ -1,7 +1,13 @@
/*
* Copyright (c) 1999-2009 Apple Inc.
+ * Copyright (c) 2016-2017 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:
@@ -67,6 +73,7 @@ kau_init(void)
{
au_evclassmap_init();
+ au_evnamemap_init();
}
/*
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
diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h
index b5c373ae53ec..d4de263a625b 100644
--- a/sys/security/audit/audit_private.h
+++ b/sys/security/audit/audit_private.h
@@ -1,7 +1,13 @@
/*-
* Copyright (c) 1999-2009 Apple Inc.
+ * Copyright (c) 2016-2017 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:
@@ -151,6 +157,7 @@ union auditon_udata {
au_stat_t au_stat;
au_fstat_t au_fstat;
auditinfo_addr_t au_kau_info;
+ au_evname_map_t au_evname;
};
struct posix_ipc_perm {
@@ -368,6 +375,34 @@ extern int audit_in_failure;
#define AUDIT_OPEN_FLAGS (FWRITE | O_APPEND)
#define AUDIT_CLOSE_FLAGS (FWRITE | O_APPEND)
+/*
+ * Audit event-to-name mapping structure, maintained in audit_bsm_klib.c. It
+ * appears in this header so that the DTrace audit provider can dereference
+ * instances passed back in the au_evname_foreach() callbacks. Safe access to
+ * its fields rquires holding ene_lock (after it is visible in the global
+ * table).
+ *
+ * Locking:
+ * (c) - Constant after inserted in the global table
+ * (l) - Protected by ene_lock
+ * (m) - Protected by evnamemap_lock (audit_bsm_klib.c)
+ * (M) - Writes protected by evnamemap_lock; reads unprotected.
+ */
+struct evname_elem {
+ au_event_t ene_event; /* (c) */
+ char ene_name[EVNAMEMAP_NAME_SIZE]; /* (l) */
+ LIST_ENTRY(evname_elem) ene_entry; /* (m) */
+ struct mtx ene_lock;
+};
+
+#define EVNAME_LOCK(ene) mtx_lock(&(ene)->ene_lock)
+#define EVNAME_UNLOCK(ene) mtx_unlock(&(ene)->ene_lock)
+
+/*
+ * Callback function typedef for the same.
+ */
+typedef void (*au_evnamemap_callback_t)(struct evname_elem *ene);
+
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
@@ -387,6 +422,10 @@ int au_preselect(au_event_t event, au_class_t class,
void au_evclassmap_init(void);
void au_evclassmap_insert(au_event_t event, au_class_t class);
au_class_t au_event_class(au_event_t event);
+void au_evnamemap_init(void);
+void au_evnamemap_insert(au_event_t event, const char *name);
+void au_evnamemap_foreach(au_evnamemap_callback_t callback);
+int au_event_name(au_event_t event, char *name);
au_event_t audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg);
au_event_t audit_flags_and_error_to_openevent(int oflags, int error);
au_event_t audit_flags_and_error_to_openatevent(int oflags, int error);
diff --git a/sys/security/audit/audit_syscalls.c b/sys/security/audit/audit_syscalls.c
index b134b0a355f3..4c656c14a068 100644
--- a/sys/security/audit/audit_syscalls.c
+++ b/sys/security/audit/audit_syscalls.c
@@ -1,7 +1,13 @@
/*-
* Copyright (c) 1999-2009 Apple Inc.
+ * Copyright (c) 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:
@@ -195,10 +201,12 @@ sys_auditon(struct thread *td, struct auditon_args *uap)
case A_SETCOND:
case A_OLDSETCOND:
case A_SETCLASS:
+ case A_SETEVENT:
case A_SETPMASK:
case A_SETFSIZE:
case A_SETKAUDIT:
case A_GETCLASS:
+ case A_GETEVENT:
case A_GETPINFO:
case A_GETPINFO_ADDR:
case A_SENDTRIGGER:
@@ -404,6 +412,15 @@ sys_auditon(struct thread *td, struct auditon_args *uap)
udata.au_evclass.ec_number);
break;
+ case A_GETEVENT:
+ if (uap->length != sizeof(udata.au_evname))
+ return (EINVAL);
+ error = au_event_name(udata.au_evname.en_number,
+ udata.au_evname.en_name);
+ if (error != 0)
+ return (error);
+ break;
+
case A_SETCLASS:
if (uap->length != sizeof(udata.au_evclass))
return (EINVAL);
@@ -411,6 +428,17 @@ sys_auditon(struct thread *td, struct auditon_args *uap)
udata.au_evclass.ec_class);
break;
+ case A_SETEVENT:
+ if (uap->length != sizeof(udata.au_evname))
+ return (EINVAL);
+
+ /* Ensure nul termination from userspace. */
+ udata.au_evname.en_name[sizeof(udata.au_evname.en_name) - 1]
+ = 0;
+ au_evnamemap_insert(udata.au_evname.en_number,
+ udata.au_evname.en_name);
+ break;
+
case A_GETPINFO:
if (uap->length != sizeof(udata.au_aupinfo))
return (EINVAL);