Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 14 Mar 2009 16:06:06 +0000 (UTC)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r189797 - head/sys/security/mac
Message-ID:  <200903141606.n2EG66Ch098755@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rwatson
Date: Sat Mar 14 16:06:06 2009
New Revision: 189797
URL: http://svn.freebsd.org/changeset/base/189797

Log:
  Rework MAC Framework synchronization in a number of ways in order to
  improve performance:
  
  - Eliminate custom reference count and condition variable to monitor
    threads entering the framework, as this had both significant overhead
    and behaved badly in the face of contention.
  
  - Replace reference count with two locks: an rwlock and an sx lock,
    which will be read-acquired by threads entering the framework
    depending on whether a give policy entry point is permitted to sleep
    or not.
  
  - Replace previous mutex locking of the reference count for exclusive
    access with write acquiring of both the policy list sx and rw locks,
    which occurs only when policies are attached or detached.
  
  - Do a lockless read of the dynamic policy list head before acquiring
    any locks in order to reduce overhead when no dynamic policies are
    loaded; this a race we can afford to lose.
  
  - For every policy entry point invocation, decide whether sleeping is
    permitted, and if not, use a _NOSLEEP() variant of the composition
    macros, which will use the rwlock instead of the sxlock.  In some
    cases, we decide which to use based on allocation flags passed to the
    MAC Framework entry point.
  
  As with the move to rwlocks/rmlocks in pfil, this may trigger witness
  warnings, but these should (generally) be false positives as all
  acquisition of the locks is for read with two very narrow exceptions
  for policy load/unload, and those code blocks should never acquire
  other locks.
  
  Sponsored by:	Google, Inc.
  Obtained from:	TrustedBSD Project
  Discussed with:	csjp (idea, not specific patch)

Modified:
  head/sys/security/mac/mac_atalk.c
  head/sys/security/mac/mac_audit.c
  head/sys/security/mac/mac_cred.c
  head/sys/security/mac/mac_framework.c
  head/sys/security/mac/mac_inet.c
  head/sys/security/mac/mac_inet6.c
  head/sys/security/mac/mac_internal.h
  head/sys/security/mac/mac_net.c
  head/sys/security/mac/mac_pipe.c
  head/sys/security/mac/mac_posix_sem.c
  head/sys/security/mac/mac_posix_shm.c
  head/sys/security/mac/mac_priv.c
  head/sys/security/mac/mac_process.c
  head/sys/security/mac/mac_socket.c
  head/sys/security/mac/mac_syscalls.c
  head/sys/security/mac/mac_system.c
  head/sys/security/mac/mac_sysv_msg.c
  head/sys/security/mac/mac_sysv_sem.c
  head/sys/security/mac/mac_sysv_shm.c
  head/sys/security/mac/mac_vfs.c

Modified: head/sys/security/mac/mac_atalk.c
==============================================================================
--- head/sys/security/mac/mac_atalk.c	Sat Mar 14 15:53:06 2009	(r189796)
+++ head/sys/security/mac/mac_atalk.c	Sat Mar 14 16:06:06 2009	(r189797)
@@ -1,9 +1,12 @@
 /*-
- * Copyright (c) 2007 Robert N. M. Watson
+ * Copyright (c) 2007-2009 Robert N. M. Watson
  * All rights reserved.
  *
  * This software was developed by Robert Watson for the TrustedBSD Project.
  *
+ * This software was developed at the University of Cambridge Computer
+ * Laboratory with support from a grant from Google, Inc.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -61,6 +64,7 @@ mac_netatalk_aarp_send(struct ifnet *ifp
 	mlabel = mac_mbuf_to_label(m);
 
 	MAC_IFNET_LOCK(ifp);
-	MAC_PERFORM(netatalk_aarp_send, ifp, ifp->if_label, m, mlabel);
+	MAC_PERFORM_NOSLEEP(netatalk_aarp_send, ifp, ifp->if_label, m,
+	    mlabel);
 	MAC_IFNET_UNLOCK(ifp);
 }

Modified: head/sys/security/mac/mac_audit.c
==============================================================================
--- head/sys/security/mac/mac_audit.c	Sat Mar 14 15:53:06 2009	(r189796)
+++ head/sys/security/mac/mac_audit.c	Sat Mar 14 16:06:06 2009	(r189797)
@@ -66,7 +66,7 @@ mac_cred_check_setaudit(struct ucred *cr
 {
 	int error;
 
-	MAC_CHECK(cred_check_setaudit, cred, ai);
+	MAC_CHECK_NOSLEEP(cred_check_setaudit, cred, ai);
 	MAC_CHECK_PROBE2(cred_check_setaudit, error, cred, ai);
 
 	return (error);
@@ -80,7 +80,7 @@ mac_cred_check_setaudit_addr(struct ucre
 {
 	int error;
 
-	MAC_CHECK(cred_check_setaudit_addr, cred, aia);
+	MAC_CHECK_NOSLEEP(cred_check_setaudit_addr, cred, aia);
 	MAC_CHECK_PROBE2(cred_check_setaudit_addr, error, cred, aia);
 
 	return (error);
@@ -93,7 +93,7 @@ mac_cred_check_setauid(struct ucred *cre
 {
 	int error;
 
-	MAC_CHECK(cred_check_setauid, cred, auid);
+	MAC_CHECK_NOSLEEP(cred_check_setauid, cred, auid);
 	MAC_CHECK_PROBE2(cred_check_setauid, error, cred, auid);
 
 	return (error);
@@ -107,7 +107,7 @@ mac_system_check_audit(struct ucred *cre
 {
 	int error;
 
-	MAC_CHECK(system_check_audit, cred, record, length);
+	MAC_CHECK_NOSLEEP(system_check_audit, cred, record, length);
 	MAC_CHECK_PROBE3(system_check_audit, error, cred, record, length);
 
 	return (error);
@@ -138,7 +138,7 @@ mac_system_check_auditon(struct ucred *c
 {
 	int error;
 
-	MAC_CHECK(system_check_auditon, cred, cmd);
+	MAC_CHECK_NOSLEEP(system_check_auditon, cred, cmd);
 	MAC_CHECK_PROBE2(system_check_auditon, error, cred, cmd);
 
 	return (error);

Modified: head/sys/security/mac/mac_cred.c
==============================================================================
--- head/sys/security/mac/mac_cred.c	Sat Mar 14 15:53:06 2009	(r189796)
+++ head/sys/security/mac/mac_cred.c	Sat Mar 14 16:06:06 2009	(r189797)
@@ -100,7 +100,7 @@ void
 mac_cred_label_free(struct label *label)
 {
 
-	MAC_PERFORM(cred_destroy_label, label);
+	MAC_PERFORM_NOSLEEP(cred_destroy_label, label);
 	mac_labelzone_free(label);
 }
 
@@ -127,7 +127,7 @@ void
 mac_cred_associate_nfsd(struct ucred *cred)
 {
 
-	MAC_PERFORM(cred_associate_nfsd, cred);
+	MAC_PERFORM_NOSLEEP(cred_associate_nfsd, cred);
 }
 
 /*
@@ -138,7 +138,7 @@ void
 mac_cred_create_swapper(struct ucred *cred)
 {
 
-	MAC_PERFORM(cred_create_swapper, cred);
+	MAC_PERFORM_NOSLEEP(cred_create_swapper, cred);
 }
 
 /*
@@ -149,7 +149,7 @@ void
 mac_cred_create_init(struct ucred *cred)
 {
 
-	MAC_PERFORM(cred_create_init, cred);
+	MAC_PERFORM_NOSLEEP(cred_create_init, cred);
 }
 
 int
@@ -182,7 +182,7 @@ void
 mac_cred_copy(struct ucred *src, struct ucred *dest)
 {
 
-	MAC_PERFORM(cred_copy_label, src->cr_label, dest->cr_label);
+	MAC_PERFORM_NOSLEEP(cred_copy_label, src->cr_label, dest->cr_label);
 }
 
 /*
@@ -194,7 +194,7 @@ void
 mac_cred_relabel(struct ucred *cred, struct label *newlabel)
 {
 
-	MAC_PERFORM(cred_relabel, cred, newlabel);
+	MAC_PERFORM_NOSLEEP(cred_relabel, cred, newlabel);
 }
 
 MAC_CHECK_PROBE_DEFINE2(cred_check_relabel, "struct ucred *",
@@ -205,7 +205,7 @@ mac_cred_check_relabel(struct ucred *cre
 {
 	int error;
 
-	MAC_CHECK(cred_check_relabel, cred, newlabel);
+	MAC_CHECK_NOSLEEP(cred_check_relabel, cred, newlabel);
 	MAC_CHECK_PROBE2(cred_check_relabel, error, cred, newlabel);
 
 	return (error);
@@ -218,7 +218,7 @@ mac_cred_check_setuid(struct ucred *cred
 {
 	int error;
 
-	MAC_CHECK(cred_check_setuid, cred, uid);
+	MAC_CHECK_NOSLEEP(cred_check_setuid, cred, uid);
 	MAC_CHECK_PROBE2(cred_check_setuid, error, cred, uid);
 
 	return (error);
@@ -231,7 +231,7 @@ mac_cred_check_seteuid(struct ucred *cre
 {
 	int error;
 
-	MAC_CHECK(cred_check_seteuid, cred, euid);
+	MAC_CHECK_NOSLEEP(cred_check_seteuid, cred, euid);
 	MAC_CHECK_PROBE2(cred_check_seteuid, error, cred, euid);
 
 	return (error);
@@ -244,7 +244,7 @@ mac_cred_check_setgid(struct ucred *cred
 {
 	int error;
 
-	MAC_CHECK(cred_check_setgid, cred, gid);
+	MAC_CHECK_NOSLEEP(cred_check_setgid, cred, gid);
 	MAC_CHECK_PROBE2(cred_check_setgid, error, cred, gid);
 
 	return (error);
@@ -257,7 +257,7 @@ mac_cred_check_setegid(struct ucred *cre
 {
 	int error;
 
-	MAC_CHECK(cred_check_setegid, cred, egid);
+	MAC_CHECK_NOSLEEP(cred_check_setegid, cred, egid);
 	MAC_CHECK_PROBE2(cred_check_setegid, error, cred, egid);
 
 	return (error);
@@ -271,7 +271,7 @@ mac_cred_check_setgroups(struct ucred *c
 {
 	int error;
 
-	MAC_CHECK(cred_check_setgroups, cred, ngroups, gidset);
+	MAC_CHECK_NOSLEEP(cred_check_setgroups, cred, ngroups, gidset);
 	MAC_CHECK_PROBE3(cred_check_setgroups, error, cred, ngroups, gidset);
 
 	return (error);
@@ -285,7 +285,7 @@ mac_cred_check_setreuid(struct ucred *cr
 {
 	int error;
 
-	MAC_CHECK(cred_check_setreuid, cred, ruid, euid);
+	MAC_CHECK_NOSLEEP(cred_check_setreuid, cred, ruid, euid);
 	MAC_CHECK_PROBE3(cred_check_setreuid, error, cred, ruid, euid);
 
 	return (error);
@@ -299,7 +299,7 @@ mac_cred_check_setregid(struct ucred *cr
 {
 	int error;
 
-	MAC_CHECK(cred_check_setregid, cred, rgid, egid);
+	MAC_CHECK_NOSLEEP(cred_check_setregid, cred, rgid, egid);
 	MAC_CHECK_PROBE3(cred_check_setregid, error, cred, rgid, egid);
 
 	return (error);
@@ -314,7 +314,7 @@ mac_cred_check_setresuid(struct ucred *c
 {
 	int error;
 
-	MAC_CHECK(cred_check_setresuid, cred, ruid, euid, suid);
+	MAC_CHECK_NOSLEEP(cred_check_setresuid, cred, ruid, euid, suid);
 	MAC_CHECK_PROBE4(cred_check_setresuid, error, cred, ruid, euid,
 	    suid);
 
@@ -330,7 +330,7 @@ mac_cred_check_setresgid(struct ucred *c
 {
 	int error;
 
-	MAC_CHECK(cred_check_setresgid, cred, rgid, egid, sgid);
+	MAC_CHECK_NOSLEEP(cred_check_setresgid, cred, rgid, egid, sgid);
 	MAC_CHECK_PROBE4(cred_check_setresgid, error, cred, rgid, egid,
 	    sgid);
 
@@ -345,7 +345,7 @@ mac_cred_check_visible(struct ucred *cr1
 {
 	int error;
 
-	MAC_CHECK(cred_check_visible, cr1, cr2);
+	MAC_CHECK_NOSLEEP(cred_check_visible, cr1, cr2);
 	MAC_CHECK_PROBE2(cred_check_visible, error, cr1, cr2);
 
 	return (error);

Modified: head/sys/security/mac/mac_framework.c
==============================================================================
--- head/sys/security/mac/mac_framework.c	Sat Mar 14 15:53:06 2009	(r189796)
+++ head/sys/security/mac/mac_framework.c	Sat Mar 14 16:06:06 2009	(r189797)
@@ -76,10 +76,11 @@ __FBSDID("$FreeBSD$");
 #include <sys/condvar.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
-#include <sys/mutex.h>
 #include <sys/mac.h>
 #include <sys/module.h>
+#include <sys/rwlock.h>
 #include <sys/sdt.h>
+#include <sys/sx.h>
 #include <sys/systm.h>
 #include <sys/sysctl.h>
 
@@ -154,164 +155,125 @@ SYSCTL_QUAD(_security_mac, OID_AUTO, lab
 MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
 
 /*
- * mac_static_policy_list holds a list of policy modules that are not loaded
- * while the system is "live", and cannot be unloaded.  These policies can be
- * invoked without holding the busy count.
+ * MAC policy modules are placed in one of two lists: mac_static_policy_list,
+ * for policies that are loaded early and cannot be unloaded, and
+ * mac_policy_list, which holds policies either loaded later in the boot
+ * cycle or that may be unloaded.  The static policy list does not require
+ * locks to iterate over, but the dynamic list requires synchronization.
+ * Support for dynamic policy loading can be compiled out using the
+ * MAC_STATIC kernel option.
  *
- * mac_policy_list stores the list of dynamic policies.  A busy count is
- * maintained for the list, stored in mac_policy_busy.  The busy count is
- * protected by mac_policy_mtx; the list may be modified only while the busy
- * count is 0, requiring that the lock be held to prevent new references to
- * the list from being acquired.  For almost all operations, incrementing the
- * busy count is sufficient to guarantee consistency, as the list cannot be
- * modified while the busy count is elevated.  For a few special operations
- * involving a change to the list of active policies, the mtx itself must be
- * held.  A condition variable, mac_policy_cv, is used to signal potential
- * exclusive consumers that they should try to acquire the lock if a first
- * attempt at exclusive access fails.
- *
- * This design intentionally avoids fairness, and may starve attempts to
- * acquire an exclusive lock on a busy system.  This is required because we
- * do not ever want acquiring a read reference to perform an unbounded length
- * sleep.  Read references are acquired in ithreads, network isrs, etc, and
- * any unbounded blocking could lead quickly to deadlock.
- *
- * Another reason for never blocking on read references is that the MAC
- * Framework may recurse: if a policy calls a VOP, for example, this might
- * lead to vnode life cycle operations (such as init/destroy).
- *
- * If the kernel option MAC_STATIC has been compiled in, all locking becomes
- * a no-op, and the global list of policies is not allowed to change after
- * early boot.
- *
- * XXXRW: Currently, we signal mac_policy_cv every time the framework becomes
- * unbusy and there is a thread waiting to enter it exclusively.  Since it 
- * may take some time before the thread runs, we may issue a lot of signals.
- * We should instead keep track of the fact that we've signalled, taking into 
- * account that the framework may be busy again by the time the thread runs, 
- * requiring us to re-signal. 
+ * The dynamic policy list is protected by two locks: modifying the list
+ * requires both locks to be held exclusively.  One of the locks,
+ * mac_policy_rw, is acquired over policy entry points that will never sleep;
+ * the other, mac_policy_sx, is acquire over policy entry points that may
+ * sleep.  The former category will be used when kernel locks may be held
+ * over calls to the MAC Framework, during network processing in ithreads,
+ * etc.  The latter will tend to involve potentially blocking memory
+ * allocations, extended attribute I/O, etc.
  */
 #ifndef MAC_STATIC
-static struct mtx mac_policy_mtx;
-static struct cv mac_policy_cv;
-static int mac_policy_count;
-static int mac_policy_wait;
+static struct rwlock mac_policy_rw;	/* Non-sleeping entry points. */
+static struct sx mac_policy_sx;		/* Sleeping entry points. */
 #endif
+
 struct mac_policy_list_head mac_policy_list;
 struct mac_policy_list_head mac_static_policy_list;
 
-/*
- * We manually invoke WITNESS_WARN() to allow Witness to generate warnings
- * even if we don't end up ever triggering the wait at run-time.  The
- * consumer of the exclusive interface must not hold any locks (other than
- * potentially Giant) since we may sleep for long (potentially indefinite)
- * periods of time waiting for the framework to become quiescent so that a
- * policy list change may be made.
- */
+static void	mac_policy_xlock(void);
+static void	mac_policy_xlock_assert(void);
+static void	mac_policy_xunlock(void);
+
 void
-mac_policy_grab_exclusive(void)
+mac_policy_slock_nosleep(void)
 {
 
 #ifndef MAC_STATIC
 	if (!mac_late)
 		return;
 
-	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
- 	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
-	mtx_lock(&mac_policy_mtx);
-	while (mac_policy_count != 0) {
-		mac_policy_wait++;
-		cv_wait(&mac_policy_cv, &mac_policy_mtx);
-		mac_policy_wait--;
-	}
+	rw_rlock(&mac_policy_rw);
 #endif
 }
 
 void
-mac_policy_assert_exclusive(void)
+mac_policy_slock_sleep(void)
 {
 
+	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ 	    "mac_policy_slock_sleep");
+
 #ifndef MAC_STATIC
 	if (!mac_late)
 		return;
 
-	mtx_assert(&mac_policy_mtx, MA_OWNED);
-	KASSERT(mac_policy_count == 0,
-	    ("mac_policy_assert_exclusive(): not exclusive"));
+	sx_slock(&mac_policy_sx);
 #endif
 }
 
 void
-mac_policy_release_exclusive(void)
+mac_policy_sunlock_nosleep(void)
 {
-#ifndef MAC_STATIC
-	int dowakeup;
 
+#ifndef MAC_STATIC
 	if (!mac_late)
 		return;
 
-	KASSERT(mac_policy_count == 0,
-	    ("mac_policy_release_exclusive(): not exclusive"));
-	dowakeup = (mac_policy_wait != 0);
-	mtx_unlock(&mac_policy_mtx);
-	if (dowakeup)
-		cv_signal(&mac_policy_cv);
+	rw_runlock(&mac_policy_rw);
 #endif
 }
 
 void
-mac_policy_list_busy(void)
+mac_policy_sunlock_sleep(void)
 {
 
 #ifndef MAC_STATIC
 	if (!mac_late)
 		return;
 
-	mtx_lock(&mac_policy_mtx);
-	mac_policy_count++;
-	mtx_unlock(&mac_policy_mtx);
+	sx_sunlock(&mac_policy_sx);
 #endif
 }
 
-int
-mac_policy_list_conditional_busy(void)
+static void
+mac_policy_xlock(void)
 {
-#ifndef MAC_STATIC
-	int ret;
 
+	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ 	    "mac_policy_xlock()");
+
+#ifndef MAC_STATIC
 	if (!mac_late)
-		return (1);
+		return;
 
-	mtx_lock(&mac_policy_mtx);
-	if (!LIST_EMPTY(&mac_policy_list)) {
-		mac_policy_count++;
-		ret = 1;
-	} else
-		ret = 0;
-	mtx_unlock(&mac_policy_mtx);
-	return (ret);
-#else
-	return (1);
+	sx_xlock(&mac_policy_sx);
+	rw_wlock(&mac_policy_rw);
 #endif
 }
 
-void
-mac_policy_list_unbusy(void)
+static void
+mac_policy_xunlock(void)
 {
-#ifndef MAC_STATIC
-	int dowakeup;
 
+#ifndef MAC_STATIC
 	if (!mac_late)
 		return;
 
-	mtx_lock(&mac_policy_mtx);
-	mac_policy_count--;
-	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
-	dowakeup = (mac_policy_count == 0 && mac_policy_wait != 0);
-	mtx_unlock(&mac_policy_mtx);
+	rw_wunlock(&mac_policy_rw);
+	sx_xunlock(&mac_policy_sx);
+#endif
+}
 
-	if (dowakeup)
-		cv_signal(&mac_policy_cv);
+static void
+mac_policy_xlock_assert(void)
+{
+
+#ifndef MAC_STATIC
+	if (!mac_late)
+		return;
+
+	rw_assert(&mac_policy_rw, RA_WLOCKED);
+	sx_assert(&mac_policy_sx, SA_XLOCKED);
 #endif
 }
 
@@ -327,8 +289,8 @@ mac_init(void)
 	mac_labelzone_init();
 
 #ifndef MAC_STATIC
-	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
-	cv_init(&mac_policy_cv, "mac_policy_cv");
+	rw_init(&mac_policy_rw, "mac_policy_rw");
+	sx_init(&mac_policy_sx, "mac_policy_sx");
 #endif
 }
 
@@ -393,7 +355,7 @@ mac_policy_updateflags(void)
 {
 	struct mac_policy_conf *mpc;
 
-	mac_policy_assert_exclusive();
+	mac_policy_xlock_assert();
 
 	mac_labeled = 0;
 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list)
@@ -414,7 +376,7 @@ mac_policy_register(struct mac_policy_co
 	 * We don't technically need exclusive access while !mac_late, but
 	 * hold it for assertion consistency.
 	 */
-	mac_policy_grab_exclusive();
+	mac_policy_xlock();
 
 	/*
 	 * If the module can potentially be unloaded, or we're loading late,
@@ -479,7 +441,7 @@ mac_policy_register(struct mac_policy_co
 	    mpc->mpc_name);
 
 out:
-	mac_policy_release_exclusive();
+	mac_policy_xunlock();
 	return (error);
 }
 
@@ -491,9 +453,9 @@ mac_policy_unregister(struct mac_policy_
 	 * If we fail the load, we may get a request to unload.  Check to see
 	 * if we did the run-time registration, and if not, silently succeed.
 	 */
-	mac_policy_grab_exclusive();
+	mac_policy_xlock();
 	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
-		mac_policy_release_exclusive();
+		mac_policy_xunlock();
 		return (0);
 	}
 #if 0
@@ -501,7 +463,7 @@ mac_policy_unregister(struct mac_policy_
 	 * Don't allow unloading modules with private data.
 	 */
 	if (mpc->mpc_field_off != NULL) {
-		MAC_POLICY_LIST_UNLOCK();
+		mac_policy_xunlock();
 		return (EBUSY);
 	}
 #endif
@@ -510,7 +472,7 @@ mac_policy_unregister(struct mac_policy_
 	 * its own definition.
 	 */
 	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
-		mac_policy_release_exclusive();
+		mac_policy_xunlock();
 		return (EBUSY);
 	}
 	if (mpc->mpc_ops->mpo_destroy != NULL)
@@ -519,8 +481,7 @@ mac_policy_unregister(struct mac_policy_
 	LIST_REMOVE(mpc, mpc_list);
 	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
 	mac_policy_updateflags();
-
-	mac_policy_release_exclusive();
+	mac_policy_xunlock();
 
 	SDT_PROBE(mac, kernel, policy, unregister, mpc, 0, 0, 0, 0);
 	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,

Modified: head/sys/security/mac/mac_inet.c
==============================================================================
--- head/sys/security/mac/mac_inet.c	Sat Mar 14 15:53:06 2009	(r189796)
+++ head/sys/security/mac/mac_inet.c	Sat Mar 14 16:06:06 2009	(r189797)
@@ -84,9 +84,12 @@ mac_inpcb_label_alloc(int flag)
 	label = mac_labelzone_alloc(flag);
 	if (label == NULL)
 		return (NULL);
-	MAC_CHECK(inpcb_init_label, label, flag);
+	if (flag & M_WAITOK)
+		MAC_CHECK(inpcb_init_label, label, flag);
+	else
+		MAC_CHECK_NOSLEEP(inpcb_init_label, label, flag);
 	if (error) {
-		MAC_PERFORM(inpcb_destroy_label, label);
+		MAC_PERFORM_NOSLEEP(inpcb_destroy_label, label);
 		mac_labelzone_free(label);
 		return (NULL);
 	}
@@ -116,9 +119,12 @@ mac_ipq_label_alloc(int flag)
 	if (label == NULL)
 		return (NULL);
 
-	MAC_CHECK(ipq_init_label, label, flag);
+	if (flag & M_WAITOK)
+		MAC_CHECK(ipq_init_label, label, flag);
+	else
+		MAC_CHECK_NOSLEEP(ipq_init_label, label, flag);
 	if (error) {
-		MAC_PERFORM(ipq_destroy_label, label);
+		MAC_PERFORM_NOSLEEP(ipq_destroy_label, label);
 		mac_labelzone_free(label);
 		return (NULL);
 	}
@@ -142,7 +148,7 @@ static void
 mac_inpcb_label_free(struct label *label)
 {
 
-	MAC_PERFORM(inpcb_destroy_label, label);
+	MAC_PERFORM_NOSLEEP(inpcb_destroy_label, label);
 	mac_labelzone_free(label);
 }
 
@@ -160,7 +166,7 @@ static void
 mac_ipq_label_free(struct label *label)
 {
 
-	MAC_PERFORM(ipq_destroy_label, label);
+	MAC_PERFORM_NOSLEEP(ipq_destroy_label, label);
 	mac_labelzone_free(label);
 }
 
@@ -178,7 +184,8 @@ void
 mac_inpcb_create(struct socket *so, struct inpcb *inp)
 {
 
-	MAC_PERFORM(inpcb_create, so, so->so_label, inp, inp->inp_label);
+	MAC_PERFORM_NOSLEEP(inpcb_create, so, so->so_label, inp,
+	    inp->inp_label);
 }
 
 void
@@ -188,7 +195,7 @@ mac_ipq_reassemble(struct ipq *q, struct
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(ipq_reassemble, q, q->ipq_label, m, label);
+	MAC_PERFORM_NOSLEEP(ipq_reassemble, q, q->ipq_label, m, label);
 }
 
 void
@@ -199,7 +206,7 @@ mac_netinet_fragment(struct mbuf *m, str
 	mlabel = mac_mbuf_to_label(m);
 	fraglabel = mac_mbuf_to_label(frag);
 
-	MAC_PERFORM(netinet_fragment, m, mlabel, frag, fraglabel);
+	MAC_PERFORM_NOSLEEP(netinet_fragment, m, mlabel, frag, fraglabel);
 }
 
 void
@@ -209,7 +216,7 @@ mac_ipq_create(struct mbuf *m, struct ip
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(ipq_create, m, label, q, q->ipq_label);
+	MAC_PERFORM_NOSLEEP(ipq_create, m, label, q, q->ipq_label);
 }
 
 void
@@ -220,7 +227,8 @@ mac_inpcb_create_mbuf(struct inpcb *inp,
 	INP_LOCK_ASSERT(inp);
 	mlabel = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(inpcb_create_mbuf, inp, inp->inp_label, m, mlabel);
+	MAC_PERFORM_NOSLEEP(inpcb_create_mbuf, inp, inp->inp_label, m,
+	    mlabel);
 }
 
 int
@@ -232,7 +240,7 @@ mac_ipq_match(struct mbuf *m, struct ipq
 	label = mac_mbuf_to_label(m);
 
 	result = 1;
-	MAC_BOOLEAN(ipq_match, &&, m, label, q, q->ipq_label);
+	MAC_BOOLEAN_NOSLEEP(ipq_match, &&, m, label, q, q->ipq_label);
 
 	return (result);
 }
@@ -245,7 +253,7 @@ mac_netinet_arp_send(struct ifnet *ifp, 
 	mlabel = mac_mbuf_to_label(m);
 
 	MAC_IFNET_LOCK(ifp);
-	MAC_PERFORM(netinet_arp_send, ifp, ifp->if_label, m, mlabel);
+	MAC_PERFORM_NOSLEEP(netinet_arp_send, ifp, ifp->if_label, m, mlabel);
 	MAC_IFNET_UNLOCK(ifp);
 }
 
@@ -257,7 +265,7 @@ mac_netinet_icmp_reply(struct mbuf *mrec
 	mrecvlabel = mac_mbuf_to_label(mrecv);
 	msendlabel = mac_mbuf_to_label(msend);
 
-	MAC_PERFORM(netinet_icmp_reply, mrecv, mrecvlabel, msend,
+	MAC_PERFORM_NOSLEEP(netinet_icmp_reply, mrecv, mrecvlabel, msend,
 	    msendlabel);
 }
 
@@ -268,7 +276,7 @@ mac_netinet_icmp_replyinplace(struct mbu
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(netinet_icmp_replyinplace, m, label);
+	MAC_PERFORM_NOSLEEP(netinet_icmp_replyinplace, m, label);
 }
 
 void
@@ -279,7 +287,8 @@ mac_netinet_igmp_send(struct ifnet *ifp,
 	mlabel = mac_mbuf_to_label(m);
 
 	MAC_IFNET_LOCK(ifp);
-	MAC_PERFORM(netinet_igmp_send, ifp, ifp->if_label, m, mlabel);
+	MAC_PERFORM_NOSLEEP(netinet_igmp_send, ifp, ifp->if_label, m,
+	    mlabel);
 	MAC_IFNET_UNLOCK(ifp);
 }
 
@@ -290,7 +299,7 @@ mac_netinet_tcp_reply(struct mbuf *m)
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(netinet_tcp_reply, m, label);
+	MAC_PERFORM_NOSLEEP(netinet_tcp_reply, m, label);
 }
 
 void
@@ -300,7 +309,7 @@ mac_ipq_update(struct mbuf *m, struct ip
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(ipq_update, m, label, q, q->ipq_label);
+	MAC_PERFORM_NOSLEEP(ipq_update, m, label, q, q->ipq_label);
 }
 
 MAC_CHECK_PROBE_DEFINE2(inpcb_check_deliver, "struct inpcb *",
@@ -316,7 +325,8 @@ mac_inpcb_check_deliver(struct inpcb *in
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_CHECK(inpcb_check_deliver, inp, inp->inp_label, m, label);
+	MAC_CHECK_NOSLEEP(inpcb_check_deliver, inp, inp->inp_label, m,
+	    label);
 	MAC_CHECK_PROBE2(inpcb_check_deliver, error, inp, m);
 
 	return (error);
@@ -332,7 +342,7 @@ mac_inpcb_check_visible(struct ucred *cr
 
 	INP_LOCK_ASSERT(inp);
 
-	MAC_CHECK(inpcb_check_visible, cred, inp, inp->inp_label);
+	MAC_CHECK_NOSLEEP(inpcb_check_visible, cred, inp, inp->inp_label);
 	MAC_CHECK_PROBE2(inpcb_check_visible, error, cred, inp);
 
 	return (error);
@@ -344,7 +354,9 @@ mac_inpcb_sosetlabel(struct socket *so, 
 
 	INP_WLOCK_ASSERT(inp);
 	SOCK_LOCK_ASSERT(so);
-	MAC_PERFORM(inpcb_sosetlabel, so, so->so_label, inp, inp->inp_label);
+
+	MAC_PERFORM_NOSLEEP(inpcb_sosetlabel, so, so->so_label, inp,
+	    inp->inp_label);
 }
 
 void
@@ -358,7 +370,7 @@ mac_netinet_firewall_reply(struct mbuf *
 	mrecvlabel = mac_mbuf_to_label(mrecv);
 	msendlabel = mac_mbuf_to_label(msend);
 
-	MAC_PERFORM(netinet_firewall_reply, mrecv, mrecvlabel, msend,
+	MAC_PERFORM_NOSLEEP(netinet_firewall_reply, mrecv, mrecvlabel, msend,
 	    msendlabel);
 }
 
@@ -368,8 +380,10 @@ mac_netinet_firewall_send(struct mbuf *m
 	struct label *label;
 
 	M_ASSERTPKTHDR(m);
+
 	label = mac_mbuf_to_label(m);
-	MAC_PERFORM(netinet_firewall_send, m, label);
+
+	MAC_PERFORM_NOSLEEP(netinet_firewall_send, m, label);
 }
 
 /*
@@ -386,7 +400,7 @@ mac_syncache_destroy(struct label **labe
 {
 
 	if (*label != NULL) {
-		MAC_PERFORM(syncache_destroy_label, *label);
+		MAC_PERFORM_NOSLEEP(syncache_destroy_label, *label);
 		mac_labelzone_free(*label);
 		*label = NULL;
 	}
@@ -408,9 +422,9 @@ mac_syncache_init(struct label **label)
 		 * MAC_PERFORM so we can propagate allocation failures back
 		 * to the syncache code.
 		 */
-		MAC_CHECK(syncache_init_label, *label, M_NOWAIT);
+		MAC_CHECK_NOSLEEP(syncache_init_label, *label, M_NOWAIT);
 		if (error) {
-			MAC_PERFORM(syncache_destroy_label, *label);
+			MAC_PERFORM_NOSLEEP(syncache_destroy_label, *label);
 			mac_labelzone_free(*label);
 		}
 		return (error);
@@ -424,7 +438,8 @@ mac_syncache_create(struct label *label,
 {
 
 	INP_WLOCK_ASSERT(inp);
-	MAC_PERFORM(syncache_create, label, inp);
+
+	MAC_PERFORM_NOSLEEP(syncache_create, label, inp);
 }
 
 void
@@ -433,6 +448,8 @@ mac_syncache_create_mbuf(struct label *s
 	struct label *mlabel;
 
 	M_ASSERTPKTHDR(m);
+
 	mlabel = mac_mbuf_to_label(m);
-	MAC_PERFORM(syncache_create_mbuf, sc_label, m, mlabel);
+
+	MAC_PERFORM_NOSLEEP(syncache_create_mbuf, sc_label, m, mlabel);
 }

Modified: head/sys/security/mac/mac_inet6.c
==============================================================================
--- head/sys/security/mac/mac_inet6.c	Sat Mar 14 15:53:06 2009	(r189796)
+++ head/sys/security/mac/mac_inet6.c	Sat Mar 14 16:06:06 2009	(r189797)
@@ -1,9 +1,12 @@
 /*-
- * Copyright (c) 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2007-2009 Robert N. M. Watson
  * All rights reserved.
  *
  * This software was developed by Robert Watson for the TrustedBSD Project.
  *
+ * This software was developed at the University of Cambridge Computer
+ * Laboratory with support from a grant from Google, Inc.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -67,9 +70,12 @@ mac_ip6q_label_alloc(int flag)
 	if (label == NULL)
 		return (NULL);
 
-	MAC_CHECK(ip6q_init_label, label, flag);
+	if (flag & M_WAITOK)
+		MAC_CHECK(ip6q_init_label, label, flag);
+	else
+		MAC_CHECK_NOSLEEP(ip6q_init_label, label, flag);
 	if (error) {
-		MAC_PERFORM(ip6q_destroy_label, label);
+		MAC_PERFORM_NOSLEEP(ip6q_destroy_label, label);
 		mac_labelzone_free(label);
 		return (NULL);
 	}
@@ -93,7 +99,7 @@ static void
 mac_ip6q_label_free(struct label *label)
 {
 
-	MAC_PERFORM(ip6q_destroy_label, label);
+	MAC_PERFORM_NOSLEEP(ip6q_destroy_label, label);
 	mac_labelzone_free(label);
 }
 
@@ -114,7 +120,7 @@ mac_ip6q_reassemble(struct ip6q *q6, str
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(ip6q_reassemble, q6, q6->ip6q_label, m, label);
+	MAC_PERFORM_NOSLEEP(ip6q_reassemble, q6, q6->ip6q_label, m, label);
 }
 
 void
@@ -124,7 +130,7 @@ mac_ip6q_create(struct mbuf *m, struct i
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(ip6q_create, m, label, q6, q6->ip6q_label);
+	MAC_PERFORM_NOSLEEP(ip6q_create, m, label, q6, q6->ip6q_label);
 }
 
 int
@@ -136,7 +142,7 @@ mac_ip6q_match(struct mbuf *m, struct ip
 	label = mac_mbuf_to_label(m);
 
 	result = 1;
-	MAC_BOOLEAN(ip6q_match, &&, m, label, q6, q6->ip6q_label);
+	MAC_BOOLEAN_NOSLEEP(ip6q_match, &&, m, label, q6, q6->ip6q_label);
 
 	return (result);
 }
@@ -148,7 +154,7 @@ mac_ip6q_update(struct mbuf *m, struct i
 
 	label = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(ip6q_update, m, label, q6, q6->ip6q_label);
+	MAC_PERFORM_NOSLEEP(ip6q_update, m, label, q6, q6->ip6q_label);
 }
 
 void
@@ -158,5 +164,6 @@ mac_netinet6_nd6_send(struct ifnet *ifp,
 
 	mlabel = mac_mbuf_to_label(m);
 
-	MAC_PERFORM(netinet6_nd6_send, ifp, ifp->if_label, m, mlabel);
+	MAC_PERFORM_NOSLEEP(netinet6_nd6_send, ifp, ifp->if_label, m,
+	    mlabel);
 }

Modified: head/sys/security/mac/mac_internal.h
==============================================================================
--- head/sys/security/mac/mac_internal.h	Sat Mar 14 15:53:06 2009	(r189796)
+++ head/sys/security/mac/mac_internal.h	Sat Mar 14 16:06:06 2009	(r189797)
@@ -194,12 +194,10 @@ extern struct mtx			mac_ifnet_mtx;
  */
 int	mac_error_select(int error1, int error2);
 
-void	mac_policy_grab_exclusive(void);
-void	mac_policy_assert_exclusive(void);
-void	mac_policy_release_exclusive(void);
-void	mac_policy_list_busy(void);
-int	mac_policy_list_conditional_busy(void);
-void	mac_policy_list_unbusy(void);
+void	mac_policy_slock_nosleep(void);
+void	mac_policy_slock_sleep(void);
+void	mac_policy_sunlock_nosleep(void);
+void	mac_policy_sunlock_sleep(void);
 
 struct label	*mac_labelzone_alloc(int flags);
 void		 mac_labelzone_free(struct label *label);
@@ -255,13 +253,16 @@ int	vn_setlabel(struct vnode *vp, struct
 	    struct ucred *cred);
 
 /*
+ * MAC Framework composition macros invoke all registered MAC policies for a
+ * specific entry point.  They come in two forms: one which permits policies
+ * to sleep/block, and another that does not.
+ *
  * MAC_CHECK performs the designated check by walking the policy module list
  * and checking with each as to how it feels about the request.  Note that it
  * returns its value via 'error' in the scope of the caller.
  */
 #define	MAC_CHECK(check, args...) do {					\
 	struct mac_policy_conf *mpc;					\
-	int entrycount;							\
 									\
 	error = 0;							\
 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
@@ -270,14 +271,37 @@ int	vn_setlabel(struct vnode *vp, struct
 			    mpc->mpc_ops->mpo_ ## check (args),		\
 			    error);					\
 	}								\
-	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {	\
+	if (!LIST_EMPTY(&mac_policy_list)) {				\
+		mac_policy_slock_sleep();				\
 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
 			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
 				error = mac_error_select(		\
 				    mpc->mpc_ops->mpo_ ## check (args),	\
 				    error);				\
 		}							\
-		mac_policy_list_unbusy();				\
+		mac_policy_sunlock_sleep();				\
+	}								\
+} while (0)
+
+#define	MAC_CHECK_NOSLEEP(check, args...) do {				\
+	struct mac_policy_conf *mpc;					\
+									\
+	error = 0;							\
+	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
+		if (mpc->mpc_ops->mpo_ ## check != NULL)		\
+			error = mac_error_select(			\
+			    mpc->mpc_ops->mpo_ ## check (args),		\
+			    error);					\
+	}								\
+	if (!LIST_EMPTY(&mac_policy_list)) {				\
+		mac_policy_slock_nosleep();				\
+		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
+			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
+				error = mac_error_select(		\
+				    mpc->mpc_ops->mpo_ ## check (args),	\
+				    error);				\
+		}							\
+		mac_policy_sunlock_nosleep();				\
 	}								\
 } while (0)
 
@@ -288,9 +312,8 @@ int	vn_setlabel(struct vnode *vp, struct
  * EPERM.  Note that it returns its value via 'error' in the scope of the
  * caller.
  */
-#define	MAC_GRANT(check, args...) do {					\
+#define	MAC_GRANT_NOSLEEP(check, args...) do {				\
 	struct mac_policy_conf *mpc;					\
-	int entrycount;							\
 									\
 	error = EPERM;							\
 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
@@ -299,7 +322,8 @@ int	vn_setlabel(struct vnode *vp, struct
 				error = 0;				\
 		}							\
 	}								\
-	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {	\
+	if (!LIST_EMPTY(&mac_policy_list)) {				\
+		mac_policy_slock_nosleep();				\
 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
 			if (mpc->mpc_ops->mpo_ ## check != NULL) {	\
 				if (mpc->mpc_ops->mpo_ ## check (args)	\
@@ -307,7 +331,7 @@ int	vn_setlabel(struct vnode *vp, struct
 					error = 0;			\
 			}						\
 		}							\
-		mac_policy_list_unbusy();				\
+		mac_policy_sunlock_nosleep();				\
 	}								\
 } while (0)
 
@@ -320,21 +344,41 @@ int	vn_setlabel(struct vnode *vp, struct
  */
 #define	MAC_BOOLEAN(operation, composition, args...) do {		\
 	struct mac_policy_conf *mpc;					\
-	int entrycount;							\
 									\
 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
 			result = result composition			\
 			    mpc->mpc_ops->mpo_ ## operation (args);	\
 	}								\

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903141606.n2EG66Ch098755>