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

Robert Watson rwatson at FreeBSD.org
Tue Oct 2 15:58:19 UTC 2018


Author: rwatson
Date: Tue Oct  2 15:58:17 2018
New Revision: 339085
URL: https://svnweb.freebsd.org/changeset/base/339085

Log:
  Rework the logic around quick checks for auditing that take place at
  system-call entry and whenever audit arguments or return values are
  captured:
  
  1. Expose a single global, audit_syscalls_enabled, which controls
     whether the audit framework is entered, rather than exposing
     components of the policy -- e.g., if the trail is enabled,
     suspended, etc.
  
  2. Introduce a new function audit_syscalls_enabled_update(), which is
     called to update audit_syscalls_enabled whenever an aspect of the
     policy changes, so that the value can be updated.
  
  3. Remove a check of trail enablement/suspension from audit_new() --
     at the point where this function has been entered, we believe that
     system-call auditing is already in force, or we wouldn't get here,
     so simply proceed to more expensive policy checks.
  
  4. Use an audit-provided global, audit_dtrace_enabled, rather than a
     dtaudit-provided global, to provide policy indicating whether
     dtaudit would like system calls to be audited.
  
  5. Do some minor cosmetic renaming to clarify what various variables
     are for.
  
  These changes collectively arrange it so that traditional audit
  (trail, pipes) or the DTrace audit provider can enable system-call
  probes without the other configured.  Otherwise, dtaudit cannot
  capture system-call data without auditd(8) started.
  
  Reviewed by:		gnn
  Sponsored by:		DARPA, AFRL
  Approved by:		re (gjb)
  Differential Revision:	https://reviews.freebsd.org/D17348

Modified:
  head/sys/security/audit/audit.c
  head/sys/security/audit/audit.h
  head/sys/security/audit/audit_dtrace.c
  head/sys/security/audit/audit_private.h
  head/sys/security/audit/audit_syscalls.c
  head/sys/security/audit/audit_worker.c

Modified: head/sys/security/audit/audit.c
==============================================================================
--- head/sys/security/audit/audit.c	Tue Oct  2 15:18:48 2018	(r339084)
+++ head/sys/security/audit/audit.c	Tue Oct  2 15:58:17 2018	(r339085)
@@ -2,7 +2,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1999-2005 Apple Inc.
- * Copyright (c) 2006-2007, 2016-2017 Robert N. M. Watson
+ * Copyright (c) 2006-2007, 2016-2018 Robert N. M. Watson
  * All rights reserved.
  *
  * Portions of this software were developed by BAE Systems, the University of
@@ -98,8 +98,12 @@ static SYSCTL_NODE(_security, OID_AUTO, audit, CTLFLAG
  *
  * Define the audit control flags.
  */
-int __read_frequently	audit_enabled;
-int			audit_suspended;
+int			audit_trail_enabled;
+int			audit_trail_suspended;
+#ifdef KDTRACE_HOOKS
+u_int			audit_dtrace_enabled;
+#endif
+int __read_frequently	audit_syscalls_enabled;
 
 /*
  * Flags controlling behavior in low storage situations.  Should we panic if
@@ -198,7 +202,34 @@ static struct rwlock		audit_kinfo_lock;
 #define	KINFO_RUNLOCK()		rw_runlock(&audit_kinfo_lock)
 #define	KINFO_WUNLOCK()		rw_wunlock(&audit_kinfo_lock)
 
+/*
+ * Check various policies to see if we should enable system-call audit hooks.
+ * Note that despite the mutex being held, we want to assign a value exactly
+ * once, as checks of the flag are performed lock-free for performance
+ * reasons.  The mutex is used to get a consistent snapshot of policy state --
+ * e.g., safely accessing the two audit_trail flags.
+ */
 void
+audit_syscalls_enabled_update(void)
+{
+
+	mtx_lock(&audit_mtx);
+#ifdef KDTRACE_HOOKS
+	if (audit_dtrace_enabled)
+		audit_syscalls_enabled = 1;
+	else {
+#endif
+		if (audit_trail_enabled && !audit_trail_suspended)
+			audit_syscalls_enabled = 1;
+		else
+			audit_syscalls_enabled = 0;
+#ifdef KDTRACE_HOOKS
+	}
+#endif
+	mtx_unlock(&audit_mtx);
+}
+
+void
 audit_set_kinfo(struct auditinfo_addr *ak)
 {
 
@@ -303,8 +334,9 @@ static void
 audit_init(void)
 {
 
-	audit_enabled = 0;
-	audit_suspended = 0;
+	audit_trail_enabled = 0;
+	audit_trail_suspended = 0;
+	audit_syscalls_enabled = 0;
 	audit_panic_on_write_fail = 0;
 	audit_fail_stop = 0;
 	audit_in_failure = 0;
@@ -337,6 +369,9 @@ audit_init(void)
 	    sizeof(struct kaudit_record), audit_record_ctor,
 	    audit_record_dtor, NULL, NULL, UMA_ALIGN_PTR, 0);
 
+	/* First initialisation of audit_syscalls_enabled. */
+	audit_syscalls_enabled_update();
+
 	/* Initialize the BSM audit subsystem. */
 	kau_init();
 
@@ -378,10 +413,6 @@ currecord(void)
 }
 
 /*
- * XXXAUDIT: There are a number of races present in the code below due to
- * release and re-grab of the mutex.  The code should be revised to become
- * slightly less racy.
- *
  * XXXAUDIT: Shouldn't there be logic here to sleep waiting on available
  * pre_q space, suspending the system call until there is room?
  */
@@ -389,14 +420,7 @@ struct kaudit_record *
 audit_new(int event, struct thread *td)
 {
 	struct kaudit_record *ar;
-	int no_record;
 
-	mtx_lock(&audit_mtx);
-	no_record = (audit_suspended || !audit_enabled);
-	mtx_unlock(&audit_mtx);
-	if (no_record)
-		return (NULL);
-
 	/*
 	 * Note: the number of outstanding uncommitted audit records is
 	 * limited to the number of concurrent threads servicing system calls
@@ -529,9 +553,13 @@ audit_commit(struct kaudit_record *ar, int error, int 
 	/*
 	 * Note: it could be that some records initiated while audit was
 	 * enabled should still be committed?
+	 *
+	 * NB: The check here is not for audit_syscalls because any
+	 * DTrace-related obligations have been fulfilled above -- we're just
+	 * down to the trail and pipes now.
 	 */
 	mtx_lock(&audit_mtx);
-	if (audit_suspended || !audit_enabled) {
+	if (audit_trail_suspended || !audit_trail_enabled) {
 		audit_pre_q_len--;
 		mtx_unlock(&audit_mtx);
 		audit_free(ar);
@@ -557,6 +585,10 @@ audit_commit(struct kaudit_record *ar, int error, int 
  * responsible for deciding whether or not to audit the call (preselection),
  * and if so, allocating a per-thread audit record.  audit_new() will fill in
  * basic thread/credential properties.
+ *
+ * This function will be entered only if audit_syscalls_enabled was set in the
+ * macro wrapper for this function.  It could be cleared by the time this
+ * function runs, but that is an acceptable race.
  */
 void
 audit_syscall_enter(unsigned short code, struct thread *td)

Modified: head/sys/security/audit/audit.h
==============================================================================
--- head/sys/security/audit/audit.h	Tue Oct  2 15:18:48 2018	(r339084)
+++ head/sys/security/audit/audit.h	Tue Oct  2 15:58:17 2018	(r339085)
@@ -2,7 +2,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1999-2005 Apple Inc.
- * Copyright (c) 2016-2017 Robert N. M. Watson
+ * Copyright (c) 2016-2018 Robert N. M. Watson
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -55,14 +55,23 @@
 #include <sys/sysctl.h>
 
 /*
- * Audit subsystem condition flags.  The audit_enabled flag is set and
+ * Audit subsystem condition flags.  The audit_trail_enabled flag is set and
  * removed automatically as a result of configuring log files, and can be
  * observed but should not be directly manipulated.  The audit suspension
  * flag permits audit to be temporarily disabled without reconfiguring the
  * audit target.
+ *
+ * As DTrace can also request system-call auditing, a further
+ * audit_syscalls_enabled flag tracks whether newly entering system calls
+ * should be considered for auditing or not.
+ *
+ * XXXRW: Move trail flags to audit_private.h, as they no longer need to be
+ * visible outside the audit code...?
  */
-extern int	audit_enabled;
-extern int	audit_suspended;
+extern u_int	audit_dtrace_enabled;
+extern int	audit_trail_enabled;
+extern int	audit_trail_suspended;
+extern int	audit_syscalls_enabled;
 
 void	 audit_syscall_enter(unsigned short code, struct thread *td);
 void	 audit_syscall_exit(int error, struct thread *td);
@@ -139,7 +148,7 @@ void	 audit_thread_free(struct thread *td);
 
 /*
  * Define macros to wrap the audit_arg_* calls by checking the global
- * audit_enabled flag before performing the actual call.
+ * audit_syscalls_enabled flag before performing the actual call.
  */
 #define	AUDITING_TD(td)		((td)->td_pflags & TDP_AUDITREC)
 
@@ -369,7 +378,7 @@ void	 audit_thread_free(struct thread *td);
 } while (0)
 
 #define	AUDIT_SYSCALL_ENTER(code, td)	do {				\
-	if (audit_enabled) {						\
+	if (audit_syscalls_enabled) {					\
 		audit_syscall_enter(code, td);				\
 	}								\
 } while (0)
@@ -377,7 +386,7 @@ void	 audit_thread_free(struct thread *td);
 /*
  * Wrap the audit_syscall_exit() function so that it is called only when
  * we have a audit record on the thread.  Audit records can persist after
- * auditing is disabled, so we don't just check audit_enabled here.
+ * auditing is disabled, so we don't just check audit_syscalls_enabled here.
  */
 #define	AUDIT_SYSCALL_EXIT(error, td)	do {				\
 	if (td->td_pflags & TDP_AUDITREC)				\

Modified: head/sys/security/audit/audit_dtrace.c
==============================================================================
--- head/sys/security/audit/audit_dtrace.c	Tue Oct  2 15:18:48 2018	(r339084)
+++ head/sys/security/audit/audit_dtrace.c	Tue Oct  2 15:58:17 2018	(r339085)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2016 Robert N. M. Watson
+ * Copyright (c) 2016, 2018 Robert N. M. Watson
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -147,8 +147,12 @@ static dtrace_provider_id_t	dtaudit_id;
  * maintain a global flag tracking whether any dtaudit probes are enabled.  If
  * not, don't bother doing all that work whenever potential queries about
  * events turn up during preselection or commit.
+ *
+ * NB: We used to maintain our own variable in dtaudit, but now use the
+ * centralized audit_dtrace_enabled variable imported from the audit code.
+ *
+ * static uint_t		dtaudit_probes_enabled;
  */
-static uint_t		dtaudit_probes_enabled;
 
 /*
  * Check dtaudit policy for the event to see whether this is an event we would
@@ -179,7 +183,7 @@ dtaudit_preselect(au_id_t auid, au_event_t event, au_c
 	 * NB: Lockless reads here may return a slightly stale value; this is
 	 * considered better than acquiring a lock, however.
 	 */
-	if (!dtaudit_probes_enabled)
+	if (!audit_dtrace_enabled)
 		return (NULL);
 	ene = au_evnamemap_lookup(event);
 	if (ene == NULL)
@@ -457,7 +461,8 @@ dtaudit_enable(void *arg, dtrace_id_t id, void *parg)
 		ene->ene_commit_probe_enabled = 1;
 	else
 		ene->ene_bsm_probe_enabled = 1;
-	refcount_acquire(&dtaudit_probes_enabled);
+	refcount_acquire(&audit_dtrace_enabled);
+	audit_syscalls_enabled_update();
 }
 
 static void
@@ -474,7 +479,8 @@ dtaudit_disable(void *arg, dtrace_id_t id, void *parg)
 		ene->ene_commit_probe_enabled = 0;
 	else
 		ene->ene_bsm_probe_enabled = 0;
-	(void)refcount_release(&dtaudit_probes_enabled);
+	(void)refcount_release(&audit_dtrace_enabled);
+	audit_syscalls_enabled_update();
 }
 
 static void

Modified: head/sys/security/audit/audit_private.h
==============================================================================
--- head/sys/security/audit/audit_private.h	Tue Oct  2 15:18:48 2018	(r339084)
+++ head/sys/security/audit/audit_private.h	Tue Oct  2 15:58:17 2018	(r339085)
@@ -2,7 +2,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1999-2009 Apple Inc.
- * Copyright (c) 2016-2017 Robert N. M. Watson
+ * Copyright (c) 2016, 2018 Robert N. M. Watson
  * All rights reserved.
  *
  * Portions of this software were developed by BAE Systems, the University of
@@ -342,6 +342,13 @@ void			 audit_abort(struct kaudit_record *ar);
 void			 audit_commit(struct kaudit_record *ar, int error,
 			    int retval);
 struct kaudit_record	*audit_new(int event, struct thread *td);
+
+/*
+ * Function to update the audit_syscalls_enabled flag, whose value is affected
+ * by configuration of the audit trail/pipe mechanism and DTrace.  Call this
+ * function when any of the inputs to that policy change.
+ */
+void	audit_syscalls_enabled_update(void);
 
 /*
  * Functions relating to the conversion of internal kernel audit records to

Modified: head/sys/security/audit/audit_syscalls.c
==============================================================================
--- head/sys/security/audit/audit_syscalls.c	Tue Oct  2 15:18:48 2018	(r339084)
+++ head/sys/security/audit/audit_syscalls.c	Tue Oct  2 15:58:17 2018	(r339085)
@@ -2,7 +2,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1999-2009 Apple Inc.
- * Copyright (c) 2016 Robert N. M. Watson
+ * Copyright (c) 2016, 2018 Robert N. M. Watson
  * All rights reserved.
  *
  * Portions of this software were developed by BAE Systems, the University of
@@ -368,7 +368,7 @@ sys_auditon(struct thread *td, struct auditon_args *ua
 	case A_OLDGETCOND:
 	case A_GETCOND:
 		if (uap->length == sizeof(udata.au_cond64)) {
-			if (audit_enabled && !audit_suspended)
+			if (audit_trail_enabled && !audit_trail_suspended)
 				udata.au_cond64 = AUC_AUDITING;
 			else
 				udata.au_cond64 = AUC_NOAUDIT;
@@ -376,7 +376,7 @@ sys_auditon(struct thread *td, struct auditon_args *ua
 		}
 		if (uap->length != sizeof(udata.au_cond))
 			return (EINVAL);
-		if (audit_enabled && !audit_suspended)
+		if (audit_trail_enabled && !audit_trail_suspended)
 			udata.au_cond = AUC_AUDITING;
 		else
 			udata.au_cond = AUC_NOAUDIT;
@@ -386,25 +386,27 @@ sys_auditon(struct thread *td, struct auditon_args *ua
 	case A_SETCOND:
 		if (uap->length == sizeof(udata.au_cond64)) {
 			if (udata.au_cond64 == AUC_NOAUDIT)
-				audit_suspended = 1;
+				audit_trail_suspended = 1;
 			if (udata.au_cond64 == AUC_AUDITING)
-				audit_suspended = 0;
+				audit_trail_suspended = 0;
 			if (udata.au_cond64 == AUC_DISABLED) {
-				audit_suspended = 1;
+				audit_trail_suspended = 1;
 				audit_shutdown(NULL, 0);
 			}
+			audit_syscalls_enabled_update();
 			break;
 		}
 		if (uap->length != sizeof(udata.au_cond))
 			return (EINVAL);
 		if (udata.au_cond == AUC_NOAUDIT)
-			audit_suspended = 1;
+			audit_trail_suspended = 1;
 		if (udata.au_cond == AUC_AUDITING)
-			audit_suspended = 0;
+			audit_trail_suspended = 0;
 		if (udata.au_cond == AUC_DISABLED) {
-			audit_suspended = 1;
+			audit_trail_suspended = 1;
 			audit_shutdown(NULL, 0);
 		}
+		audit_syscalls_enabled_update();
 		break;
 
 	case A_GETCLASS:
@@ -826,10 +828,11 @@ sys_auditctl(struct thread *td, struct auditctl_args *
 	crhold(cred);
 
 	/*
-	 * XXXAUDIT: Should audit_suspended actually be cleared by
+	 * XXXAUDIT: Should audit_trail_suspended actually be cleared by
 	 * audit_worker?
 	 */
-	audit_suspended = 0;
+	audit_trail_suspended = 0;
+	audit_syscalls_enabled_update();
 
 	audit_rotate_vnode(cred, vp);
 

Modified: head/sys/security/audit/audit_worker.c
==============================================================================
--- head/sys/security/audit/audit_worker.c	Tue Oct  2 15:18:48 2018	(r339084)
+++ head/sys/security/audit/audit_worker.c	Tue Oct  2 15:58:17 2018	(r339085)
@@ -2,7 +2,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1999-2008 Apple Inc.
- * Copyright (c) 2006-2008, 2016 Robert N. M. Watson
+ * Copyright (c) 2006-2008, 2016, 2018 Robert N. M. Watson
  * All rights reserved.
  *
  * Portions of this software were developed by BAE Systems, the University of
@@ -305,7 +305,8 @@ fail_enospc:
 		    "Audit log space exhausted and fail-stop set.");
 	}
 	(void)audit_send_trigger(AUDIT_TRIGGER_NO_SPACE);
-	audit_suspended = 1;
+	audit_trail_suspended = 1;
+	audit_syscalls_enabled_update();
 
 	/* FALLTHROUGH */
 fail:
@@ -518,7 +519,8 @@ audit_rotate_vnode(struct ucred *cred, struct vnode *v
 	audit_vp = vp;
 	audit_size = vattr.va_size;
 	audit_file_rotate_wait = 0;
-	audit_enabled = (audit_vp != NULL);
+	audit_trail_enabled = (audit_vp != NULL);
+	audit_syscalls_enabled_update();
 	AUDIT_WORKER_UNLOCK();
 
 	/*


More information about the svn-src-all mailing list