diff options
-rw-r--r-- | sys/kern/kern_mac.c | 135 | ||||
-rw-r--r-- | sys/kern/subr_mbuf.c | 26 | ||||
-rw-r--r-- | sys/kern/uipc_mbuf.c | 23 | ||||
-rw-r--r-- | sys/kern/uipc_mbuf2.c | 23 | ||||
-rw-r--r-- | sys/net/if_loop.c | 8 | ||||
-rw-r--r-- | sys/security/mac/mac_framework.c | 135 | ||||
-rw-r--r-- | sys/security/mac/mac_framework.h | 7 | ||||
-rw-r--r-- | sys/security/mac/mac_internal.h | 135 | ||||
-rw-r--r-- | sys/security/mac/mac_net.c | 135 | ||||
-rw-r--r-- | sys/security/mac/mac_pipe.c | 135 | ||||
-rw-r--r-- | sys/security/mac/mac_policy.h | 3 | ||||
-rw-r--r-- | sys/security/mac/mac_process.c | 135 | ||||
-rw-r--r-- | sys/security/mac/mac_syscalls.c | 135 | ||||
-rw-r--r-- | sys/security/mac/mac_system.c | 135 | ||||
-rw-r--r-- | sys/security/mac/mac_vfs.c | 135 | ||||
-rw-r--r-- | sys/sys/mac.h | 7 | ||||
-rw-r--r-- | sys/sys/mac_policy.h | 3 | ||||
-rw-r--r-- | sys/sys/mbuf.h | 3 |
18 files changed, 1118 insertions, 200 deletions
diff --git a/sys/kern/kern_mac.c b/sys/kern/kern_mac.c index ff4ca4f..2650874 100644 --- a/sys/kern/kern_mac.c +++ b/sys/kern/kern_mac.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/kern/subr_mbuf.c b/sys/kern/subr_mbuf.c index 123553b..ff226e7 100644 --- a/sys/kern/subr_mbuf.c +++ b/sys/kern/subr_mbuf.c @@ -1305,9 +1305,9 @@ m_gethdr(int how, short type) if (mb != NULL) { _mbhdr_setup(mb, type); #ifdef MAC - if (mac_init_mbuf(mb, how) != 0) { + if (mac_init_mbuf(mb, MBTOM(how)) != 0) { m_free(mb); - return NULL; + return (NULL); } #endif } @@ -1354,9 +1354,9 @@ m_gethdr_clrd(int how, short type) if (mb != NULL) { _mbhdr_setup(mb, type); #ifdef MAC - if (mac_init_mbuf(mb, how) != 0) { + if (mac_init_mbuf(mb, MBTOM(how)) != 0) { m_free(mb); - return NULL; + return (NULL); } #endif bzero(mtod(mb, caddr_t), MHLEN); @@ -1382,11 +1382,6 @@ m_free(struct mbuf *mb) if ((mb->m_flags & M_PKTHDR) != 0) m_tag_delete_chain(mb, NULL); -#ifdef MAC - if ((mb->m_flags & M_PKTHDR) && - (mb->m_pkthdr.label.l_flags & MAC_FLAG_INITIALIZED)) - mac_destroy_mbuf(mb); -#endif nb = mb->m_next; if ((mb->m_flags & M_EXT) != 0) { MEXT_REM_REF(mb); @@ -1429,11 +1424,6 @@ m_freem(struct mbuf *mb) while (mb != NULL) { if ((mb->m_flags & M_PKTHDR) != 0) m_tag_delete_chain(mb, NULL); -#ifdef MAC - if ((mb->m_flags & M_PKTHDR) && - (mb->m_pkthdr.label.l_flags & MAC_FLAG_INITIALIZED)) - mac_destroy_mbuf(mb); -#endif persist = 0; m = mb; mb = mb->m_next; @@ -1501,9 +1491,11 @@ m_getcl(int how, short type, int flags) _mext_init_ref(mb, &cl_refcntmap[cl2ref(mb->m_ext.ext_buf)]); } #ifdef MAC - if ((flags & M_PKTHDR) && (mac_init_mbuf(mb, how) != 0)) { - m_free(mb); - return NULL; + if (flags & M_PKTHDR) { + if (mac_init_mbuf(mb, MBTOM(how)) != 0) { + m_free(mb); + return (NULL); + } } #endif return (mb); diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 55d828d..08a7246 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -88,21 +88,21 @@ m_move_pkthdr(struct mbuf *to, struct mbuf *from) #if 0 /* see below for why these are not enabled */ M_ASSERTPKTHDR(to); + /* Note: with MAC, this may not be a good assertion. */ KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags), ("m_move_pkthdr: to has tags")); #endif KASSERT((to->m_flags & M_EXT) == 0, ("m_move_pkthdr: to has cluster")); #ifdef MAC + /* + * XXXMAC: It could be this should also occur for non-MAC? + */ if (to->m_flags & M_PKTHDR) - mac_destroy_mbuf(to); + m_tag_delete_chain(to, NULL); #endif to->m_flags = from->m_flags & M_COPYFLAGS; to->m_data = to->m_pktdat; to->m_pkthdr = from->m_pkthdr; /* especially tags */ -#ifdef MAC - mac_init_mbuf(to, 1); /* XXXMAC no way to fail */ - mac_create_mbuf_from_mbuf(from, to); -#endif SLIST_INIT(&from->m_pkthdr.tags); /* purge tags from src */ from->m_flags &= ~M_PKTHDR; } @@ -125,20 +125,17 @@ m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int how) * assertions to trip. For now just disable them. */ M_ASSERTPKTHDR(to); + /* Note: with MAC, this may not be a good assertion. */ KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags), ("m_dup_pkthdr: to has tags")); #endif #ifdef MAC if (to->m_flags & M_PKTHDR) - mac_destroy_mbuf(to); + m_tag_delete_chain(to, NULL); #endif to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT); if ((to->m_flags & M_EXT) == 0) to->m_data = to->m_pktdat; to->m_pkthdr = from->m_pkthdr; -#ifdef MAC - mac_init_mbuf(to, 1); /* XXXMAC no way to fail */ - mac_create_mbuf_from_mbuf(from, to); -#endif SLIST_INIT(&to->m_pkthdr.tags); return (m_tag_copy_chain(to, from, MBTOM(how))); } @@ -158,12 +155,8 @@ m_prepend(struct mbuf *m, int len, int how) m_freem(m); return (NULL); } - if (m->m_flags & M_PKTHDR) { + if (m->m_flags & M_PKTHDR) M_MOVE_PKTHDR(mn, m); -#ifdef MAC - mac_destroy_mbuf(m); -#endif - } mn->m_next = m; m = mn; if (len < MHLEN) diff --git a/sys/kern/uipc_mbuf2.c b/sys/kern/uipc_mbuf2.c index 50b37f5..000bb24 100644 --- a/sys/kern/uipc_mbuf2.c +++ b/sys/kern/uipc_mbuf2.c @@ -68,10 +68,13 @@ /*#define PULLDOWN_DEBUG*/ +#include "opt_mac.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/mac.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/mutex.h> @@ -327,6 +330,10 @@ m_tag_alloc(u_int32_t cookie, int type, int len, int wait) void m_tag_free(struct m_tag *t) { +#ifdef MAC + if (t->m_tag_id == PACKET_TAG_MACLABEL) + mac_destroy_mbuf_tag(t); +#endif free(t, M_PACKET_TAGS); } @@ -402,7 +409,21 @@ m_tag_copy(struct m_tag *t, int how) p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how); if (p == NULL) return (NULL); - bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */ +#ifdef MAC + /* + * XXXMAC: we should probably pass off the initialization, and + * copying here? can we hide that PACKET_TAG_MACLABEL is + * special from the mbuf code? + */ + if (t->m_tag_id == PACKET_TAG_MACLABEL) { + if (mac_init_mbuf_tag(p, how) != 0) { + m_tag_free(p); + return (NULL); + } + mac_copy_mbuf_tag(t, p); + } else +#endif + bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */ return p; } diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 09ba6a3..b78b146 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -214,14 +214,6 @@ looutput(ifp, m, dst, rt) if (!n) goto contiguousfail; M_MOVE_PKTHDR(n, m); -#ifdef MAC - /* - * XXXMAC: Once we put labels in tags and proper - * primitives are used for relocating mbuf header - * data, this will no longer be required. - */ - m->m_pkthdr.label.l_flags &= ~MAC_FLAG_INITIALIZED; -#endif MCLGET(n, M_DONTWAIT); if (! (n->m_flags & M_EXT)) { m_freem(n); diff --git a/sys/security/mac/mac_framework.c b/sys/security/mac/mac_framework.c index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_framework.c +++ b/sys/security/mac/mac_framework.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h index 3cc856d..77c33c4 100644 --- a/sys/security/mac/mac_framework.h +++ b/sys/security/mac/mac_framework.h @@ -109,6 +109,7 @@ struct ifnet; struct ifreq; struct image_params; struct ipq; +struct m_tag; struct mbuf; struct mount; struct proc; @@ -136,11 +137,13 @@ void mac_init_ifnet(struct ifnet *); int mac_init_ipq(struct ipq *, int flag); int mac_init_socket(struct socket *, int flag); void mac_init_pipe(struct pipe *); -int mac_init_mbuf(struct mbuf *m, int flag); +int mac_init_mbuf(struct mbuf *mbuf, int flag); +int mac_init_mbuf_tag(struct m_tag *, int flag); void mac_init_mount(struct mount *); void mac_init_proc(struct proc *); void mac_init_vnode(struct vnode *); void mac_init_vnode_label(struct label *); +void mac_copy_mbuf_tag(struct m_tag *, struct m_tag *); void mac_copy_vnode_label(struct label *, struct label *label); void mac_destroy_bpfdesc(struct bpf_d *); void mac_destroy_cred(struct ucred *); @@ -150,7 +153,7 @@ void mac_destroy_ipq(struct ipq *); void mac_destroy_socket(struct socket *); void mac_destroy_pipe(struct pipe *); void mac_destroy_proc(struct proc *); -void mac_destroy_mbuf(struct mbuf *); +void mac_destroy_mbuf_tag(struct m_tag *); void mac_destroy_mount(struct mount *); void mac_destroy_vnode(struct vnode *); void mac_destroy_vnode_label(struct label *); diff --git a/sys/security/mac/mac_internal.h b/sys/security/mac/mac_internal.h index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_internal.h +++ b/sys/security/mac/mac_internal.h @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/security/mac/mac_net.c b/sys/security/mac/mac_net.c index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_net.c +++ b/sys/security/mac/mac_net.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/security/mac/mac_pipe.c b/sys/security/mac/mac_pipe.c index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_pipe.c +++ b/sys/security/mac/mac_pipe.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h index 4e00577..e3d649e 100644 --- a/sys/security/mac/mac_policy.h +++ b/sys/security/mac/mac_policy.h @@ -95,6 +95,8 @@ struct mac_policy_ops { void (*mpo_destroy_pipe_label)(struct label *label); void (*mpo_destroy_proc_label)(struct label *label); void (*mpo_destroy_vnode_label)(struct label *label); + void (*mpo_copy_mbuf_label)(struct label *src, + struct label *dest); void (*mpo_copy_pipe_label)(struct label *src, struct label *dest); void (*mpo_copy_vnode_label)(struct label *src, @@ -431,6 +433,7 @@ struct mac_policy_conf { /* Flags for the mpc_loadtime_flags field. */ #define MPC_LOADTIME_FLAG_NOTLATE 0x00000001 #define MPC_LOADTIME_FLAG_UNLOADOK 0x00000002 +#define MPC_LOADTIME_FLAG_LABELMBUFS 0x00000004 /* Flags for the mpc_runtime_flags field. */ #define MPC_RUNTIME_FLAG_REGISTERED 0x00000001 diff --git a/sys/security/mac/mac_process.c b/sys/security/mac/mac_process.c index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_process.c +++ b/sys/security/mac/mac_process.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/security/mac/mac_syscalls.c b/sys/security/mac/mac_syscalls.c index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_syscalls.c +++ b/sys/security/mac/mac_syscalls.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/security/mac/mac_system.c b/sys/security/mac/mac_system.c index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_system.c +++ b/sys/security/mac/mac_system.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/security/mac/mac_vfs.c b/sys/security/mac/mac_vfs.c index ff4ca4f..2650874 100644 --- a/sys/security/mac/mac_vfs.c +++ b/sys/security/mac/mac_vfs.c @@ -120,6 +120,21 @@ static int mac_late = 0; */ static int ea_warn_once = 0; +#ifndef MAC_ALWAYS_LABEL_MBUF +/* + * Flag to indicate whether or not we should allocate label storage for + * new mbufs. Since most dynamic policies we currently work with don't + * rely on mbuf labeling, try to avoid paying the cost of mtag allocation + * unless specifically notified of interest. One result of this is + * that if a dynamically loaded policy requests mbuf labels, it must + * be able to deal with a NULL label being returned on any mbufs that + * were already in flight when the policy was loaded. Since the policy + * already has to deal with uninitialized labels, this probably won't + * be a problem. Note: currently no locking. Will this be a problem? + */ +static int mac_labelmbufs = 0; +#endif + static int mac_enforce_fs = 1; SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW, &mac_enforce_fs, 0, "Enforce MAC policy on file system objects"); @@ -281,6 +296,12 @@ static int mac_policy_list_busy; &mac_policy_list_lock); \ } while (0) +#define MAC_POLICY_LIST_ASSERT_EXCLUSIVE() do { \ + mtx_assert(&mac_policy_list_lock, MA_OWNED); \ + KASSERT(mac_policy_list_busy == 0, \ + ("MAC_POLICY_LIST_ASSERT_EXCLUSIVE()")); \ +} while (0) + #define MAC_POLICY_LIST_BUSY() do { \ MAC_POLICY_LIST_LOCK(); \ mac_policy_list_busy++; \ @@ -464,6 +485,35 @@ mac_late_init(void) } /* + * After the policy list has changed, walk the list to update any global + * flags. + */ +static void +mac_policy_updateflags(void) +{ + struct mac_policy_conf *tmpc; +#ifndef MAC_ALWAYS_LABEL_MBUF + int labelmbufs; +#endif + + MAC_POLICY_LIST_ASSERT_EXCLUSIVE(); + +#ifndef MAC_ALWAYS_LABEL_MBUF + labelmbufs = 0; +#endif + LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { +#ifndef MAC_ALWAYS_LABEL_MBUF + if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) + labelmbufs++; +#endif + } + +#ifndef MAC_ALWAYS_LABEL_MBUF + mac_labelmbufs = (labelmbufs != 0); +#endif +} + +/* * Allow MAC policy modules to register during boot, etc. */ int @@ -530,6 +580,7 @@ mac_policy_register(struct mac_policy_conf *mpc) /* Per-policy initialization. */ if (mpc->mpc_ops->mpo_init != NULL) (*(mpc->mpc_ops->mpo_init))(mpc); + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, @@ -574,7 +625,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) LIST_REMOVE(mpc, mpc_list); mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; - + mac_policy_updateflags(); MAC_POLICY_LIST_UNLOCK(); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, @@ -623,9 +674,11 @@ error_select(int error1, int error2) static struct label * mbuf_to_label(struct mbuf *mbuf) { + struct m_tag *tag; struct label *label; - label = &mbuf->m_pkthdr.label; + tag = m_tag_find(mbuf, PACKET_TAG_MACLABEL, NULL); + label = (struct label *)(tag+1); return (label); } @@ -727,20 +780,20 @@ mac_init_ipq(struct ipq *ipq, int flag) } int -mac_init_mbuf(struct mbuf *m, int flag) +mac_init_mbuf_tag(struct m_tag *tag, int flag) { - int error; - - M_ASSERTPKTHDR(m); + struct label *label; + int error, trflag; - mac_init_label(&m->m_pkthdr.label); + label = (struct label *) (tag + 1); + mac_init_label(label); - MAC_CHECK(init_mbuf_label, &m->m_pkthdr.label, flag); + trflag = (flag == M_DONTWAIT ? M_NOWAIT : M_WAITOK); + MAC_CHECK(init_mbuf_label, label, trflag); if (error) { - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); } - #ifdef MAC_DEBUG if (error == 0) atomic_add_int(&nmacmbufs, 1); @@ -748,6 +801,37 @@ mac_init_mbuf(struct mbuf *m, int flag) return (error); } +int +mac_init_mbuf(struct mbuf *m, int flag) +{ + struct m_tag *tag; + int error; + + M_ASSERTPKTHDR(m); + +#ifndef MAC_ALWAYS_LABEL_MBUF + /* + * Don't reserve space for labels on mbufs unless we have a policy + * that uses the labels. + */ + if (mac_labelmbufs) { +#endif + tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label), + flag); + if (tag == NULL) + return (ENOMEM); + error = mac_init_mbuf_tag(tag, flag); + if (error) { + m_tag_free(tag); + return (error); + } + m_tag_prepend(m, tag); +#ifndef MAC_ALWAYS_LABEL_MBUF + } +#endif + return (0); +} + void mac_init_mount(struct mount *mp) { @@ -935,11 +1019,14 @@ mac_destroy_ipq(struct ipq *ipq) } void -mac_destroy_mbuf(struct mbuf *m) +mac_destroy_mbuf_tag(struct m_tag *tag) { + struct label *label; - MAC_PERFORM(destroy_mbuf_label, &m->m_pkthdr.label); - mac_destroy_label(&m->m_pkthdr.label); + label = (struct label *)(tag+1); + + MAC_PERFORM(destroy_mbuf_label, label); + mac_destroy_label(label); #ifdef MAC_DEBUG atomic_subtract_int(&nmacmbufs, 1); #endif @@ -1033,6 +1120,21 @@ mac_destroy_vnode(struct vnode *vp) mac_destroy_vnode_label(&vp->v_label); } +void +mac_copy_mbuf_tag(struct m_tag *src, struct m_tag *dest) +{ + struct label *src_label, *dest_label; + + src_label = (struct label *)(src+1); + dest_label = (struct label *)(dest+1); + + /* + * mac_init_mbuf_tag() is called on the target tag in + * m_tag_copy(), so we don't need to call it here. + */ + MAC_PERFORM(copy_mbuf_label, src_label, dest_label); +} + static void mac_copy_pipe_label(struct label *src, struct label *dest) { @@ -2318,13 +2420,12 @@ mac_check_ifnet_transmit(struct ifnet *ifnet, struct mbuf *mbuf) struct label *label; int error; + M_ASSERTPKTHDR(mbuf); + if (!mac_enforce_network) return (0); - M_ASSERTPKTHDR(mbuf); label = mbuf_to_label(mbuf); - if (!(label->l_flags & MAC_FLAG_INITIALIZED)) - if_printf(ifnet, "not initialized\n"); MAC_CHECK(check_ifnet_transmit, ifnet, &ifnet->if_label, mbuf, label); diff --git a/sys/sys/mac.h b/sys/sys/mac.h index 3cc856d..77c33c4 100644 --- a/sys/sys/mac.h +++ b/sys/sys/mac.h @@ -109,6 +109,7 @@ struct ifnet; struct ifreq; struct image_params; struct ipq; +struct m_tag; struct mbuf; struct mount; struct proc; @@ -136,11 +137,13 @@ void mac_init_ifnet(struct ifnet *); int mac_init_ipq(struct ipq *, int flag); int mac_init_socket(struct socket *, int flag); void mac_init_pipe(struct pipe *); -int mac_init_mbuf(struct mbuf *m, int flag); +int mac_init_mbuf(struct mbuf *mbuf, int flag); +int mac_init_mbuf_tag(struct m_tag *, int flag); void mac_init_mount(struct mount *); void mac_init_proc(struct proc *); void mac_init_vnode(struct vnode *); void mac_init_vnode_label(struct label *); +void mac_copy_mbuf_tag(struct m_tag *, struct m_tag *); void mac_copy_vnode_label(struct label *, struct label *label); void mac_destroy_bpfdesc(struct bpf_d *); void mac_destroy_cred(struct ucred *); @@ -150,7 +153,7 @@ void mac_destroy_ipq(struct ipq *); void mac_destroy_socket(struct socket *); void mac_destroy_pipe(struct pipe *); void mac_destroy_proc(struct proc *); -void mac_destroy_mbuf(struct mbuf *); +void mac_destroy_mbuf_tag(struct m_tag *); void mac_destroy_mount(struct mount *); void mac_destroy_vnode(struct vnode *); void mac_destroy_vnode_label(struct label *); diff --git a/sys/sys/mac_policy.h b/sys/sys/mac_policy.h index 4e00577..e3d649e 100644 --- a/sys/sys/mac_policy.h +++ b/sys/sys/mac_policy.h @@ -95,6 +95,8 @@ struct mac_policy_ops { void (*mpo_destroy_pipe_label)(struct label *label); void (*mpo_destroy_proc_label)(struct label *label); void (*mpo_destroy_vnode_label)(struct label *label); + void (*mpo_copy_mbuf_label)(struct label *src, + struct label *dest); void (*mpo_copy_pipe_label)(struct label *src, struct label *dest); void (*mpo_copy_vnode_label)(struct label *src, @@ -431,6 +433,7 @@ struct mac_policy_conf { /* Flags for the mpc_loadtime_flags field. */ #define MPC_LOADTIME_FLAG_NOTLATE 0x00000001 #define MPC_LOADTIME_FLAG_UNLOADOK 0x00000002 +#define MPC_LOADTIME_FLAG_LABELMBUFS 0x00000004 /* Flags for the mpc_runtime_flags field. */ #define MPC_RUNTIME_FLAG_REGISTERED 0x00000001 diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 2ebe84d..a00534a 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -37,7 +37,6 @@ #ifndef _SYS_MBUF_H_ #define _SYS_MBUF_H_ -#include <sys/_label.h> #include <sys/queue.h> /* @@ -98,7 +97,6 @@ struct pkthdr { int csum_flags; /* flags regarding checksum */ int csum_data; /* data field used by csum routines */ SLIST_HEAD(packet_tags, m_tag) tags; /* list of packet tags */ - struct label label; /* MAC label of data in packet */ }; /* @@ -535,6 +533,7 @@ struct mbuf *m_split(struct mbuf *, int, int); #define PACKET_TAG_IPFW 16 /* ipfw classification */ #define PACKET_TAG_DIVERT 17 /* divert info */ #define PACKET_TAG_IPFORWARD 18 /* ipforward info */ +#define PACKET_TAG_MACLABEL 19 /* MAC label */ /* Packet tag routines */ struct m_tag *m_tag_alloc(u_int32_t, int, int, int); |