xref: /freebsd-src/sys/security/mac/mac_internal.h (revision db33c6f3ae9d1231087710068ee4ea5398aacca7)
17bc82500SRobert Watson /*-
25c95417dSRobert Watson  * Copyright (c) 1999-2002, 2006, 2009, 2019 Robert N. M. Watson
37bc82500SRobert Watson  * Copyright (c) 2001 Ilmar S. Habibulin
4c66b4d8dSRobert Watson  * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
5800c9408SRobert Watson  * Copyright (c) 2006 nCircle Network Security, Inc.
630d239bcSRobert Watson  * Copyright (c) 2006 SPARTA, Inc.
79162f64bSRobert Watson  * Copyright (c) 2009 Apple, Inc.
87bc82500SRobert Watson  * All rights reserved.
97bc82500SRobert Watson  *
107bc82500SRobert Watson  * This software was developed by Robert Watson and Ilmar Habibulin for the
117bc82500SRobert Watson  * TrustedBSD Project.
127bc82500SRobert Watson  *
136201265bSRobert Watson  * This software was developed for the FreeBSD Project in part by Network
146201265bSRobert Watson  * Associates Laboratories, the Security Research Division of Network
156201265bSRobert Watson  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
166201265bSRobert Watson  * as part of the DARPA CHATS research program.
177bc82500SRobert Watson  *
18800c9408SRobert Watson  * This software was developed by Robert N. M. Watson for the TrustedBSD
19800c9408SRobert Watson  * Project under contract to nCircle Network Security, Inc.
20800c9408SRobert Watson  *
2130d239bcSRobert Watson  * This software was enhanced by SPARTA ISSO under SPAWAR contract
2230d239bcSRobert Watson  * N66001-04-C-6019 ("SEFOS").
2330d239bcSRobert Watson  *
242087a58cSRobert Watson  * This software was developed at the University of Cambridge Computer
252087a58cSRobert Watson  * Laboratory with support from a grant from Google, Inc.
262087a58cSRobert Watson  *
277bc82500SRobert Watson  * Redistribution and use in source and binary forms, with or without
287bc82500SRobert Watson  * modification, are permitted provided that the following conditions
297bc82500SRobert Watson  * are met:
307bc82500SRobert Watson  * 1. Redistributions of source code must retain the above copyright
317bc82500SRobert Watson  *    notice, this list of conditions and the following disclaimer.
327bc82500SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
337bc82500SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
347bc82500SRobert Watson  *    documentation and/or other materials provided with the distribution.
357bc82500SRobert Watson  *
367bc82500SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
377bc82500SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
387bc82500SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
397bc82500SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
407bc82500SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
417bc82500SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
427bc82500SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
437bc82500SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
447bc82500SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
457bc82500SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
467bc82500SRobert Watson  * SUCH DAMAGE.
477bc82500SRobert Watson  */
48677b542eSDavid E. O'Brien 
49646a9f80SRobert Watson #ifndef _SECURITY_MAC_MAC_INTERNAL_H_
50646a9f80SRobert Watson #define	_SECURITY_MAC_MAC_INTERNAL_H_
51d02188c1SRobert Watson 
52c96ae196SRobert Watson #ifndef _KERNEL
53c96ae196SRobert Watson #error "no user-serviceable parts inside"
54c96ae196SRobert Watson #endif
55c96ae196SRobert Watson 
5681fee06fSRobert Watson #include <sys/lock.h>
5781fee06fSRobert Watson #include <sys/rmlock.h>
5881fee06fSRobert Watson 
597bc82500SRobert Watson /*
602087a58cSRobert Watson  * MAC Framework SDT DTrace probe namespace, macros for declaring entry
612087a58cSRobert Watson  * point probes, macros for invoking them.
622087a58cSRobert Watson  */
632087a58cSRobert Watson #ifdef SDT_PROVIDER_DECLARE
642087a58cSRobert Watson SDT_PROVIDER_DECLARE(mac);		/* MAC Framework-level events. */
652087a58cSRobert Watson SDT_PROVIDER_DECLARE(mac_framework);	/* Entry points to MAC. */
662087a58cSRobert Watson 
672087a58cSRobert Watson #define	MAC_CHECK_PROBE_DEFINE4(name, arg0, arg1, arg2, arg3)		\
6836160958SMark Johnston 	SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__err,	\
69d9fae5abSAndriy Gapon 	    "int", arg0, arg1, arg2, arg3);				\
7036160958SMark Johnston 	SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__ok,	\
71d9fae5abSAndriy Gapon 	    "int", arg0, arg1, arg2, arg3);
722087a58cSRobert Watson 
732087a58cSRobert Watson #define	MAC_CHECK_PROBE_DEFINE3(name, arg0, arg1, arg2)			\
7436160958SMark Johnston 	SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__err,	\
75d9fae5abSAndriy Gapon 	    "int", arg0, arg1, arg2);					\
7636160958SMark Johnston 	SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__ok,	\
77d9fae5abSAndriy Gapon 	    "int", arg0, arg1, arg2);
782087a58cSRobert Watson 
792087a58cSRobert Watson #define	MAC_CHECK_PROBE_DEFINE2(name, arg0, arg1)			\
8036160958SMark Johnston 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__err,	\
81d9fae5abSAndriy Gapon 	    "int", arg0, arg1);						\
8236160958SMark Johnston 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__ok,	\
83d9fae5abSAndriy Gapon 	    "int", arg0, arg1);
842087a58cSRobert Watson 
852087a58cSRobert Watson #define	MAC_CHECK_PROBE_DEFINE1(name, arg0)				\
8636160958SMark Johnston 	SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__err,	\
87d9fae5abSAndriy Gapon 	    "int", arg0);						\
8836160958SMark Johnston 	SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__ok,	\
89d9fae5abSAndriy Gapon 	    "int", arg0);
902087a58cSRobert Watson 
912087a58cSRobert Watson #define	MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, arg3)	do {	\
926dcf45feSMateusz Guzik 	if (SDT_PROBES_ENABLED()) {					\
932087a58cSRobert Watson 		if (error) {						\
9436160958SMark Johnston 			SDT_PROBE5(mac_framework, , name, mac__check__err,\
952087a58cSRobert Watson 			    error, arg0, arg1, arg2, arg3);		\
962087a58cSRobert Watson 		} else {						\
9736160958SMark Johnston 			SDT_PROBE5(mac_framework, , name, mac__check__ok,\
982087a58cSRobert Watson 			    0, arg0, arg1, arg2, arg3);			\
992087a58cSRobert Watson 		}							\
1006dcf45feSMateusz Guzik 	}								\
1012087a58cSRobert Watson } while (0)
1022087a58cSRobert Watson 
1032087a58cSRobert Watson #define	MAC_CHECK_PROBE3(name, error, arg0, arg1, arg2)			\
1042087a58cSRobert Watson 	MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, 0)
1052087a58cSRobert Watson #define	MAC_CHECK_PROBE2(name, error, arg0, arg1)			\
1062087a58cSRobert Watson 	MAC_CHECK_PROBE3(name, error, arg0, arg1, 0)
1072087a58cSRobert Watson #define	MAC_CHECK_PROBE1(name, error, arg0)				\
1082087a58cSRobert Watson 	MAC_CHECK_PROBE2(name, error, arg0, 0)
1092087a58cSRobert Watson #endif
1102087a58cSRobert Watson 
1112087a58cSRobert Watson #define	MAC_GRANT_PROBE_DEFINE2(name, arg0, arg1)			\
11236160958SMark Johnston 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__err,	\
113d9fae5abSAndriy Gapon 	    "int", arg0, arg1);						\
11436160958SMark Johnston 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__ok,	\
115d9fae5abSAndriy Gapon 	    "int", arg0, arg1);
1162087a58cSRobert Watson 
1172087a58cSRobert Watson #define	MAC_GRANT_PROBE2(name, error, arg0, arg1)	do {		\
1186dcf45feSMateusz Guzik 	if (SDT_PROBES_ENABLED()) {					\
1192087a58cSRobert Watson 		if (error) {						\
12036160958SMark Johnston 			SDT_PROBE3(mac_framework, , name, mac__grant__err,\
12136160958SMark Johnston 			    error, arg0, arg1);				\
1222087a58cSRobert Watson 		} else {						\
12336160958SMark Johnston 			SDT_PROBE3(mac_framework, , name, mac__grant__ok,\
12436160958SMark Johnston 			    error, arg0, arg1);				\
1252087a58cSRobert Watson 		}							\
1266dcf45feSMateusz Guzik 	}								\
1272087a58cSRobert Watson } while (0)
1282087a58cSRobert Watson 
1292087a58cSRobert Watson /*
13086ea834cSRobert Watson  * MAC Framework global types and typedefs.
13186ea834cSRobert Watson  */
13286ea834cSRobert Watson LIST_HEAD(mac_policy_list_head, mac_policy_conf);
13357f253a4SBruce Evans #ifdef MALLOC_DECLARE
134138f64b6SRobert Watson MALLOC_DECLARE(M_MACTEMP);
13557f253a4SBruce Evans #endif
1366be0c25eSRobert Watson 
13786ea834cSRobert Watson /*
1380142affcSRobert Watson  * MAC labels -- in-kernel storage format.
1390142affcSRobert Watson  *
1400142affcSRobert Watson  * In general, struct label pointers are embedded in kernel data structures
1410142affcSRobert Watson  * representing objects that may be labeled (and protected).  Struct label is
1420142affcSRobert Watson  * opaque to both kernel services that invoke the MAC Framework and MAC
1430142affcSRobert Watson  * policy modules.  In particular, we do not wish to encode the layout of the
1440142affcSRobert Watson  * label structure into any ABIs.  Historically, the slot array contained
1450142affcSRobert Watson  * unions of {long, void} but now contains uintptr_t.
1460142affcSRobert Watson  */
1470142affcSRobert Watson #define	MAC_MAX_SLOTS	4
1480142affcSRobert Watson #define	MAC_FLAG_INITIALIZED	0x0000001	/* Is initialized for use. */
1490142affcSRobert Watson struct label {
1500142affcSRobert Watson 	int		l_flags;
1510142affcSRobert Watson 	intptr_t	l_perpolicy[MAC_MAX_SLOTS];
1520142affcSRobert Watson };
1530142affcSRobert Watson 
1549162f64bSRobert Watson /*
1559162f64bSRobert Watson  * Flags for mac_labeled, a bitmask of object types need across the union of
1569162f64bSRobert Watson  * all policies currently registered with the MAC Framework, used to key
1579162f64bSRobert Watson  * whether or not labels are allocated and constructors for the type are
1589162f64bSRobert Watson  * invoked.
1599162f64bSRobert Watson  */
1609162f64bSRobert Watson #define	MPC_OBJECT_CRED			0x0000000000000001
1619162f64bSRobert Watson #define	MPC_OBJECT_PROC			0x0000000000000002
1629162f64bSRobert Watson #define	MPC_OBJECT_VNODE		0x0000000000000004
1639162f64bSRobert Watson #define	MPC_OBJECT_INPCB		0x0000000000000008
1649162f64bSRobert Watson #define	MPC_OBJECT_SOCKET		0x0000000000000010
1659162f64bSRobert Watson #define	MPC_OBJECT_DEVFS		0x0000000000000020
1669162f64bSRobert Watson #define	MPC_OBJECT_MBUF			0x0000000000000040
1679162f64bSRobert Watson #define	MPC_OBJECT_IPQ			0x0000000000000080
1689162f64bSRobert Watson #define	MPC_OBJECT_IFNET		0x0000000000000100
1699162f64bSRobert Watson #define	MPC_OBJECT_BPFDESC		0x0000000000000200
1709162f64bSRobert Watson #define	MPC_OBJECT_PIPE			0x0000000000000400
1719162f64bSRobert Watson #define	MPC_OBJECT_MOUNT		0x0000000000000800
1729162f64bSRobert Watson #define	MPC_OBJECT_POSIXSEM		0x0000000000001000
1739162f64bSRobert Watson #define	MPC_OBJECT_POSIXSHM		0x0000000000002000
1749162f64bSRobert Watson #define	MPC_OBJECT_SYSVMSG		0x0000000000004000
1759162f64bSRobert Watson #define	MPC_OBJECT_SYSVMSQ		0x0000000000008000
1769162f64bSRobert Watson #define	MPC_OBJECT_SYSVSEM		0x0000000000010000
1779162f64bSRobert Watson #define	MPC_OBJECT_SYSVSHM		0x0000000000020000
1789162f64bSRobert Watson #define	MPC_OBJECT_SYNCACHE		0x0000000000040000
1799162f64bSRobert Watson #define	MPC_OBJECT_IP6Q			0x0000000000080000
1809162f64bSRobert Watson 
1810142affcSRobert Watson /*
18286ea834cSRobert Watson  * MAC Framework global variables.
18386ea834cSRobert Watson  */
18486ea834cSRobert Watson extern struct mac_policy_list_head	mac_policy_list;
18586ea834cSRobert Watson extern struct mac_policy_list_head	mac_static_policy_list;
186f93bfb23SRobert Watson extern u_int				mac_policy_count;
1876356dba0SRobert Watson extern uint64_t				mac_labeled;
188b9b0dac3SRobert Watson extern struct mtx			mac_ifnet_mtx;
189b2f0927aSRobert Watson 
19086ea834cSRobert Watson /*
19186ea834cSRobert Watson  * MAC Framework infrastructure functions.
19295fab37eSRobert Watson  */
19386ea834cSRobert Watson int	mac_error_select(int error1, int error2);
19486ea834cSRobert Watson 
19581fee06fSRobert Watson void	mac_policy_slock_nosleep(struct rm_priotracker *tracker);
19640202729SRobert Watson void	mac_policy_slock_sleep(void);
19781fee06fSRobert Watson void	mac_policy_sunlock_nosleep(struct rm_priotracker *tracker);
19840202729SRobert Watson void	mac_policy_sunlock_sleep(void);
19986ea834cSRobert Watson 
200eca8a663SRobert Watson struct label	*mac_labelzone_alloc(int flags);
201eca8a663SRobert Watson void		 mac_labelzone_free(struct label *label);
202eca8a663SRobert Watson void		 mac_labelzone_init(void);
203eca8a663SRobert Watson 
20486ea834cSRobert Watson void	mac_init_label(struct label *label);
20586ea834cSRobert Watson void	mac_destroy_label(struct label *label);
206f64a688dSBrooks Davis int	mac_check_structmac_consistent(const struct mac *mac);
20786ea834cSRobert Watson int	mac_allocate_slot(void);
208a96acd1aSRobert Watson 
2095c95417dSRobert Watson /*
2105c95417dSRobert Watson  * Lock ifnets to protect labels only if ifnet labels are in use.
2115c95417dSRobert Watson  */
2125c95417dSRobert Watson #define MAC_IFNET_LOCK(ifp, locked)	do {				\
2135c95417dSRobert Watson 	if (mac_labeled & MPC_OBJECT_IFNET) {				\
2145c95417dSRobert Watson 		mtx_lock(&mac_ifnet_mtx);				\
2155c95417dSRobert Watson 		locked = 1;						\
2165c95417dSRobert Watson 	} else {							\
2175c95417dSRobert Watson 		locked = 0;						\
2185c95417dSRobert Watson 	}								\
2195c95417dSRobert Watson } while (0)
2205c95417dSRobert Watson 
2215c95417dSRobert Watson #define MAC_IFNET_UNLOCK(ifp, locked)	do {				\
2225c95417dSRobert Watson 	if (locked) {							\
2235c95417dSRobert Watson 		mtx_unlock(&mac_ifnet_mtx);				\
2245c95417dSRobert Watson 		locked = 0;						\
2255c95417dSRobert Watson 	}								\
2265c95417dSRobert Watson } while (0)
227b9b0dac3SRobert Watson 
228a96acd1aSRobert Watson /*
2295c5a9819SRobert Watson  * MAC Framework per-object type functions.  It's not yet clear how the
2305c5a9819SRobert Watson  * namespaces, etc, should work for these, so for now, sort by object type.
231a96acd1aSRobert Watson  */
2326356dba0SRobert Watson struct label	*mac_cred_label_alloc(void);
2336356dba0SRobert Watson void		 mac_cred_label_free(struct label *label);
234eca8a663SRobert Watson struct label	*mac_pipe_label_alloc(void);
235eca8a663SRobert Watson void		 mac_pipe_label_free(struct label *label);
236b0323ea3SRobert Watson struct label	*mac_socket_label_alloc(int flag);
237b0323ea3SRobert Watson void		 mac_socket_label_free(struct label *label);
238*2fb778faSMichael Tuexen void		 mac_socketpeer_label_free(struct label *label);
2396356dba0SRobert Watson struct label	*mac_vnode_label_alloc(void);
2406356dba0SRobert Watson void		 mac_vnode_label_free(struct label *label);
241eca8a663SRobert Watson 
24230d239bcSRobert Watson int	mac_cred_check_relabel(struct ucred *cred, struct label *newlabel);
24330d239bcSRobert Watson int	mac_cred_externalize_label(struct label *label, char *elements,
24483b7b0edSRobert Watson 	    char *outbuf, size_t outbuflen);
24530d239bcSRobert Watson int	mac_cred_internalize_label(struct label *label, char *string);
24630d239bcSRobert Watson void	mac_cred_relabel(struct ucred *cred, struct label *newlabel);
24795fab37eSRobert Watson 
248c66b4d8dSRobert Watson struct label	*mac_mbuf_to_label(struct mbuf *m);
249c66b4d8dSRobert Watson 
25030d239bcSRobert Watson void	mac_pipe_copy_label(struct label *src, struct label *dest);
25130d239bcSRobert Watson int	mac_pipe_externalize_label(struct label *label, char *elements,
25283b7b0edSRobert Watson 	    char *outbuf, size_t outbuflen);
25330d239bcSRobert Watson int	mac_pipe_internalize_label(struct label *label, char *string);
25495fab37eSRobert Watson 
255c9ea2dcfSRobert Watson int	mac_socket_label_set(struct ucred *cred, struct socket *so,
256c9ea2dcfSRobert Watson 	    struct label *label);
25730d239bcSRobert Watson void	mac_socket_copy_label(struct label *src, struct label *dest);
25830d239bcSRobert Watson int	mac_socket_externalize_label(struct label *label, char *elements,
259b0323ea3SRobert Watson 	    char *outbuf, size_t outbuflen);
26030d239bcSRobert Watson int	mac_socket_internalize_label(struct label *label, char *string);
261c9ea2dcfSRobert Watson 
26230d239bcSRobert Watson int	mac_vnode_externalize_label(struct label *label, char *elements,
26383b7b0edSRobert Watson 	    char *outbuf, size_t outbuflen);
26430d239bcSRobert Watson int	mac_vnode_internalize_label(struct label *label, char *string);
26530d239bcSRobert Watson void	mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
26686ea834cSRobert Watson 	    int *prot);
26786ea834cSRobert Watson int	vn_setlabel(struct vnode *vp, struct label *intlabel,
26886ea834cSRobert Watson 	    struct ucred *cred);
26995fab37eSRobert Watson 
27095fab37eSRobert Watson /*
27140202729SRobert Watson  * MAC Framework composition macros invoke all registered MAC policies for a
27240202729SRobert Watson  * specific entry point.  They come in two forms: one which permits policies
27340202729SRobert Watson  * to sleep/block, and another that does not.
27440202729SRobert Watson  *
275fa765671SRobert Watson  * MAC_POLICY_CHECK performs the designated check by walking the policy
276fa765671SRobert Watson  * module list and checking with each as to how it feels about the request.
277fa765671SRobert Watson  * Note that it returns its value via 'error' in the scope of the caller.
27895fab37eSRobert Watson  */
279fa765671SRobert Watson #define	MAC_POLICY_CHECK(check, args...) do {				\
28095fab37eSRobert Watson 	struct mac_policy_conf *mpc;					\
28195fab37eSRobert Watson 									\
28295fab37eSRobert Watson 	error = 0;							\
28341a17fe3SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
28441a17fe3SRobert Watson 		if (mpc->mpc_ops->mpo_ ## check != NULL)		\
28586ea834cSRobert Watson 			error = mac_error_select(			\
28641a17fe3SRobert Watson 			    mpc->mpc_ops->mpo_ ## check (args),		\
28741a17fe3SRobert Watson 			    error);					\
28841a17fe3SRobert Watson 	}								\
28940202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {				\
29040202729SRobert Watson 		mac_policy_slock_sleep();				\
29195fab37eSRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
29295fab37eSRobert Watson 			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
29386ea834cSRobert Watson 				error = mac_error_select(		\
29495fab37eSRobert Watson 				    mpc->mpc_ops->mpo_ ## check (args),	\
29595fab37eSRobert Watson 				    error);				\
29695fab37eSRobert Watson 		}							\
29740202729SRobert Watson 		mac_policy_sunlock_sleep();				\
29840202729SRobert Watson 	}								\
29940202729SRobert Watson } while (0)
30040202729SRobert Watson 
301fa765671SRobert Watson #define	MAC_POLICY_CHECK_NOSLEEP(check, args...) do {			\
30240202729SRobert Watson 	struct mac_policy_conf *mpc;					\
30340202729SRobert Watson 									\
30440202729SRobert Watson 	error = 0;							\
30540202729SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
30640202729SRobert Watson 		if (mpc->mpc_ops->mpo_ ## check != NULL)		\
30740202729SRobert Watson 			error = mac_error_select(			\
30840202729SRobert Watson 			    mpc->mpc_ops->mpo_ ## check (args),		\
30940202729SRobert Watson 			    error);					\
31040202729SRobert Watson 	}								\
31140202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {				\
31281fee06fSRobert Watson 		struct rm_priotracker tracker;				\
31381fee06fSRobert Watson 									\
31481fee06fSRobert Watson 		mac_policy_slock_nosleep(&tracker);			\
31540202729SRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
31640202729SRobert Watson 			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
31740202729SRobert Watson 				error = mac_error_select(		\
31840202729SRobert Watson 				    mpc->mpc_ops->mpo_ ## check (args),	\
31940202729SRobert Watson 				    error);				\
32040202729SRobert Watson 		}							\
32181fee06fSRobert Watson 		mac_policy_sunlock_nosleep(&tracker);			\
32241a17fe3SRobert Watson 	}								\
32395fab37eSRobert Watson } while (0)
32495fab37eSRobert Watson 
32595fab37eSRobert Watson /*
326fa765671SRobert Watson  * MAC_POLICY_GRANT performs the designated check by walking the policy
327fa765671SRobert Watson  * module list and checking with each as to how it feels about the request.
328fa765671SRobert Watson  * Unlike MAC_POLICY_CHECK, it grants if any policies return '0', and
329fa765671SRobert Watson  * otherwise returns EPERM.  Note that it returns its value via 'error' in
330fa765671SRobert Watson  * the scope of the caller.
331800c9408SRobert Watson  */
332fa765671SRobert Watson #define	MAC_POLICY_GRANT_NOSLEEP(check, args...) do {			\
333800c9408SRobert Watson 	struct mac_policy_conf *mpc;					\
334800c9408SRobert Watson 									\
335800c9408SRobert Watson 	error = EPERM;							\
336800c9408SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
337800c9408SRobert Watson 		if (mpc->mpc_ops->mpo_ ## check != NULL) {		\
338800c9408SRobert Watson 			if (mpc->mpc_ops->mpo_ ## check(args) == 0)	\
339800c9408SRobert Watson 				error = 0;				\
340800c9408SRobert Watson 		}							\
341800c9408SRobert Watson 	}								\
34240202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {				\
34381fee06fSRobert Watson 		struct rm_priotracker tracker;				\
34481fee06fSRobert Watson 									\
34581fee06fSRobert Watson 		mac_policy_slock_nosleep(&tracker);			\
346800c9408SRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
347800c9408SRobert Watson 			if (mpc->mpc_ops->mpo_ ## check != NULL) {	\
348800c9408SRobert Watson 				if (mpc->mpc_ops->mpo_ ## check (args)	\
349800c9408SRobert Watson 				    == 0)				\
350800c9408SRobert Watson 					error = 0;			\
351800c9408SRobert Watson 			}						\
352800c9408SRobert Watson 		}							\
35381fee06fSRobert Watson 		mac_policy_sunlock_nosleep(&tracker);			\
354800c9408SRobert Watson 	}								\
355800c9408SRobert Watson } while (0)
356800c9408SRobert Watson 
357800c9408SRobert Watson /*
358fa765671SRobert Watson  * MAC_POLICY_BOOLEAN performs the designated boolean composition by walking
359fa765671SRobert Watson  * the module list, invoking each instance of the operation, and combining
360fa765671SRobert Watson  * the results using the passed C operator.  Note that it returns its value
361fa765671SRobert Watson  * via 'result' in the scope of the caller, which should be initialized by
362fa765671SRobert Watson  * the caller in a meaningful way to get a meaningful result.
36395fab37eSRobert Watson  */
364fa765671SRobert Watson #define	MAC_POLICY_BOOLEAN(operation, composition, args...) do {	\
36595fab37eSRobert Watson 	struct mac_policy_conf *mpc;					\
36695fab37eSRobert Watson 									\
36741a17fe3SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
36895fab37eSRobert Watson 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
36995fab37eSRobert Watson 			result = result composition			\
37095fab37eSRobert Watson 			    mpc->mpc_ops->mpo_ ## operation (args);	\
37195fab37eSRobert Watson 	}								\
37240202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {				\
37340202729SRobert Watson 		mac_policy_slock_sleep();				\
37441a17fe3SRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
37541a17fe3SRobert Watson 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
37641a17fe3SRobert Watson 				result = result composition		\
37741a17fe3SRobert Watson 				    mpc->mpc_ops->mpo_ ## operation	\
37841a17fe3SRobert Watson 				    (args);				\
37941a17fe3SRobert Watson 		}							\
38040202729SRobert Watson 		mac_policy_sunlock_sleep();				\
38140202729SRobert Watson 	}								\
38240202729SRobert Watson } while (0)
38340202729SRobert Watson 
384fa765671SRobert Watson #define	MAC_POLICY_BOOLEAN_NOSLEEP(operation, composition, args...) do {\
38540202729SRobert Watson 	struct mac_policy_conf *mpc;					\
38640202729SRobert Watson 									\
38740202729SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
38840202729SRobert Watson 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
38940202729SRobert Watson 			result = result composition			\
39040202729SRobert Watson 			    mpc->mpc_ops->mpo_ ## operation (args);	\
39140202729SRobert Watson 	}								\
39240202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {				\
39381fee06fSRobert Watson 		struct rm_priotracker tracker;				\
39481fee06fSRobert Watson 									\
39581fee06fSRobert Watson 		mac_policy_slock_nosleep(&tracker);			\
39640202729SRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
39740202729SRobert Watson 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
39840202729SRobert Watson 				result = result composition		\
39940202729SRobert Watson 				    mpc->mpc_ops->mpo_ ## operation	\
40040202729SRobert Watson 				    (args);				\
40140202729SRobert Watson 		}							\
40281fee06fSRobert Watson 		mac_policy_sunlock_nosleep(&tracker);			\
40341a17fe3SRobert Watson 	}								\
40495fab37eSRobert Watson } while (0)
40595fab37eSRobert Watson 
4065c5a9819SRobert Watson /*
407fa765671SRobert Watson  * MAC_POLICY_EXTERNALIZE queries each policy to see if it can generate an
4085c5a9819SRobert Watson  * externalized version of a label element by name.  Policies declare whether
4095c5a9819SRobert Watson  * they have matched a particular element name, parsed from the string by
410fa765671SRobert Watson  * MAC_POLICY_EXTERNALIZE, and an error is returned if any element is matched
411fa765671SRobert Watson  * by no policy.
4125c5a9819SRobert Watson  */
413fa765671SRobert Watson #define	MAC_POLICY_EXTERNALIZE(type, label, elementlist, outbuf, 	\
414f7b951a8SRobert Watson     outbuflen) do {							\
415f51e5803SRobert Watson 	int claimed, first, ignorenotfound, savedlen;			\
416f51e5803SRobert Watson 	char *element_name, *element_temp;				\
417f51e5803SRobert Watson 	struct sbuf sb;							\
418f7b951a8SRobert Watson 									\
419f7b951a8SRobert Watson 	error = 0;							\
420f7b951a8SRobert Watson 	first = 1;							\
421f51e5803SRobert Watson 	sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN);		\
422f51e5803SRobert Watson 	element_temp = elementlist;					\
423f7b951a8SRobert Watson 	while ((element_name = strsep(&element_temp, ",")) != NULL) {	\
424f7b951a8SRobert Watson 		if (element_name[0] == '?') {				\
425f7b951a8SRobert Watson 			element_name++;					\
426f7b951a8SRobert Watson 			ignorenotfound = 1;				\
427f7b951a8SRobert Watson 		 } else							\
428f7b951a8SRobert Watson 			ignorenotfound = 0;				\
429f51e5803SRobert Watson 		savedlen = sbuf_len(&sb);				\
43086ea834cSRobert Watson 		if (first)						\
431f51e5803SRobert Watson 			error = sbuf_printf(&sb, "%s/", element_name);	\
43286ea834cSRobert Watson 		else							\
433f51e5803SRobert Watson 			error = sbuf_printf(&sb, ",%s/", element_name);	\
434f51e5803SRobert Watson 		if (error == -1) {					\
435f51e5803SRobert Watson 			error = EINVAL;	/* XXX: E2BIG? */		\
436f7b951a8SRobert Watson 			break;						\
437f7b951a8SRobert Watson 		}							\
438f51e5803SRobert Watson 		claimed = 0;						\
439fa765671SRobert Watson 		MAC_POLICY_CHECK(type ## _externalize_label, label,	\
440da77b2faSRobert Watson 		    element_name, &sb, &claimed);			\
441f7b951a8SRobert Watson 		if (error)						\
442f7b951a8SRobert Watson 			break;						\
443f51e5803SRobert Watson 		if (claimed == 0 && ignorenotfound) {			\
444f51e5803SRobert Watson 			/* Revert last label name. */			\
445f51e5803SRobert Watson 			sbuf_setpos(&sb, savedlen);			\
446f51e5803SRobert Watson 		} else if (claimed != 1) {				\
447f51e5803SRobert Watson 			error = EINVAL;	/* XXX: ENOLABEL? */		\
448f7b951a8SRobert Watson 			break;						\
44986ea834cSRobert Watson 		} else {						\
45086ea834cSRobert Watson 			first = 0;					\
451f7b951a8SRobert Watson 		}							\
452f7b951a8SRobert Watson 	}								\
453f51e5803SRobert Watson 	sbuf_finish(&sb);						\
454f7b951a8SRobert Watson } while (0)
455f7b951a8SRobert Watson 
4565c5a9819SRobert Watson /*
457fa765671SRobert Watson  * MAC_POLICY_INTERNALIZE presents parsed element names and data to each
458fa765671SRobert Watson  * policy to see if any is willing to claim it and internalize the label
459fa765671SRobert Watson  * data.  If no policies match, an error is returned.
4605c5a9819SRobert Watson  */
461fa765671SRobert Watson #define	MAC_POLICY_INTERNALIZE(type, label, instring) do {		\
462f7b951a8SRobert Watson 	char *element, *element_name, *element_data;			\
463f7b951a8SRobert Watson 	int claimed;							\
464f7b951a8SRobert Watson 									\
465f7b951a8SRobert Watson 	error = 0;							\
466f7b951a8SRobert Watson 	element = instring;						\
467f7b951a8SRobert Watson 	while ((element_name = strsep(&element, ",")) != NULL) {	\
468f7b951a8SRobert Watson 		element_data = element_name;				\
469f7b951a8SRobert Watson 		element_name = strsep(&element_data, "/");		\
470f7b951a8SRobert Watson 		if (element_data == NULL) {				\
471f7b951a8SRobert Watson 			error = EINVAL;					\
472f7b951a8SRobert Watson 			break;						\
473f7b951a8SRobert Watson 		}							\
474f7b951a8SRobert Watson 		claimed = 0;						\
475fa765671SRobert Watson 		MAC_POLICY_CHECK(type ## _internalize_label, label,	\
476da77b2faSRobert Watson 		    element_name, element_data, &claimed);		\
477f7b951a8SRobert Watson 		if (error)						\
478f7b951a8SRobert Watson 			break;						\
479f7b951a8SRobert Watson 		if (claimed != 1) {					\
480f7b951a8SRobert Watson 			/* XXXMAC: Another error here? */		\
481f7b951a8SRobert Watson 			error = EINVAL;					\
482f7b951a8SRobert Watson 			break;						\
483f7b951a8SRobert Watson 		}							\
484f7b951a8SRobert Watson 	}								\
485f7b951a8SRobert Watson } while (0)
486f7b951a8SRobert Watson 
48795fab37eSRobert Watson /*
488fa765671SRobert Watson  * MAC_POLICY_PERFORM performs the designated operation by walking the policy
489fa765671SRobert Watson  * module list and invoking that operation for each policy.
49095fab37eSRobert Watson  */
491fa765671SRobert Watson #define	MAC_POLICY_PERFORM(operation, args...) do {			\
49295fab37eSRobert Watson 	struct mac_policy_conf *mpc;					\
49395fab37eSRobert Watson 									\
49441a17fe3SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
49541a17fe3SRobert Watson 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
49641a17fe3SRobert Watson 			mpc->mpc_ops->mpo_ ## operation (args);		\
49741a17fe3SRobert Watson 	}								\
49840202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {				\
49940202729SRobert Watson 		mac_policy_slock_sleep();				\
50095fab37eSRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
50195fab37eSRobert Watson 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
50295fab37eSRobert Watson 				mpc->mpc_ops->mpo_ ## operation (args);	\
50395fab37eSRobert Watson 		}							\
50440202729SRobert Watson 		mac_policy_sunlock_sleep();				\
50540202729SRobert Watson 	}								\
50640202729SRobert Watson } while (0)
50740202729SRobert Watson 
508fa765671SRobert Watson #define	MAC_POLICY_PERFORM_NOSLEEP(operation, args...) do {		\
50940202729SRobert Watson 	struct mac_policy_conf *mpc;					\
51040202729SRobert Watson 									\
51140202729SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
51240202729SRobert Watson 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
51340202729SRobert Watson 			mpc->mpc_ops->mpo_ ## operation (args);		\
51440202729SRobert Watson 	}								\
51540202729SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {				\
51681fee06fSRobert Watson 		struct rm_priotracker tracker;				\
51781fee06fSRobert Watson 									\
51881fee06fSRobert Watson 		mac_policy_slock_nosleep(&tracker);			\
51940202729SRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
52040202729SRobert Watson 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
52140202729SRobert Watson 				mpc->mpc_ops->mpo_ ## operation (args);	\
52240202729SRobert Watson 		}							\
52381fee06fSRobert Watson 		mac_policy_sunlock_nosleep(&tracker);			\
52441a17fe3SRobert Watson 	}								\
52595fab37eSRobert Watson } while (0)
526d02188c1SRobert Watson 
527646a9f80SRobert Watson #endif /* !_SECURITY_MAC_MAC_INTERNAL_H_ */
528