svn commit: r316018 - head/sys/security/audit

Robert Watson rwatson at FreeBSD.org
Mon Mar 27 10:38:54 UTC 2017


Author: rwatson
Date: Mon Mar 27 10:38:53 2017
New Revision: 316018
URL: https://svnweb.freebsd.org/changeset/base/316018

Log:
  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

Modified:
  head/sys/security/audit/audit_bsm.c
  head/sys/security/audit/audit_bsm_klib.c
  head/sys/security/audit/audit_private.h
  head/sys/security/audit/audit_syscalls.c

Modified: head/sys/security/audit/audit_bsm.c
==============================================================================
--- head/sys/security/audit/audit_bsm.c	Mon Mar 27 09:45:27 2017	(r316017)
+++ head/sys/security/audit/audit_bsm.c	Mon Mar 27 10:38:53 2017	(r316018)
@@ -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();
 }
 
 /*

Modified: head/sys/security/audit/audit_bsm_klib.c
==============================================================================
--- head/sys/security/audit/audit_bsm_klib.c	Mon Mar 27 09:45:27 2017	(r316017)
+++ head/sys/security/audit/audit_bsm_klib.c	Mon Mar 27 10:38:53 2017	(r316018)
@@ -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[
 #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_
 }
 
 /*
+ * 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

Modified: head/sys/security/audit/audit_private.h
==============================================================================
--- head/sys/security/audit/audit_private.h	Mon Mar 27 09:45:27 2017	(r316017)
+++ head/sys/security/audit/audit_private.h	Mon Mar 27 10:38:53 2017	(r316018)
@@ -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_
 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);

Modified: head/sys/security/audit/audit_syscalls.c
==============================================================================
--- head/sys/security/audit/audit_syscalls.c	Mon Mar 27 09:45:27 2017	(r316017)
+++ head/sys/security/audit/audit_syscalls.c	Mon Mar 27 10:38:53 2017	(r316018)
@@ -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 au
 	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 au
 		    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 au
 		    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);


More information about the svn-src-head mailing list