From owner-svn-src-head@FreeBSD.ORG Sat Mar 14 16:06:07 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 42C201065670; Sat, 14 Mar 2009 16:06:07 +0000 (UTC) (envelope-from rwatson@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2F20D8FC18; Sat, 14 Mar 2009 16:06:07 +0000 (UTC) (envelope-from rwatson@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n2EG67pj098763; Sat, 14 Mar 2009 16:06:07 GMT (envelope-from rwatson@svn.freebsd.org) Received: (from rwatson@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n2EG66Ch098755; Sat, 14 Mar 2009 16:06:06 GMT (envelope-from rwatson@svn.freebsd.org) Message-Id: <200903141606.n2EG66Ch098755@svn.freebsd.org> From: Robert Watson Date: Sat, 14 Mar 2009 16:06:06 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r189797 - head/sys/security/mac X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 14 Mar 2009 16:06:07 -0000 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 #include #include -#include #include #include +#include #include +#include #include #include @@ -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 ***