xref: /f-stack/freebsd/security/mac/mac_internal.h (revision 22ce4aff)
1a9643ea8Slogwang /*-
2*22ce4affSfengbojiang  * Copyright (c) 1999-2002, 2006, 2009, 2019 Robert N. M. Watson
3a9643ea8Slogwang  * Copyright (c) 2001 Ilmar S. Habibulin
4a9643ea8Slogwang  * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
5a9643ea8Slogwang  * Copyright (c) 2006 nCircle Network Security, Inc.
6a9643ea8Slogwang  * Copyright (c) 2006 SPARTA, Inc.
7a9643ea8Slogwang  * Copyright (c) 2009 Apple, Inc.
8a9643ea8Slogwang  * All rights reserved.
9a9643ea8Slogwang  *
10a9643ea8Slogwang  * This software was developed by Robert Watson and Ilmar Habibulin for the
11a9643ea8Slogwang  * TrustedBSD Project.
12a9643ea8Slogwang  *
13a9643ea8Slogwang  * This software was developed for the FreeBSD Project in part by Network
14a9643ea8Slogwang  * Associates Laboratories, the Security Research Division of Network
15a9643ea8Slogwang  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
16a9643ea8Slogwang  * as part of the DARPA CHATS research program.
17a9643ea8Slogwang  *
18a9643ea8Slogwang  * This software was developed by Robert N. M. Watson for the TrustedBSD
19a9643ea8Slogwang  * Project under contract to nCircle Network Security, Inc.
20a9643ea8Slogwang  *
21a9643ea8Slogwang  * This software was enhanced by SPARTA ISSO under SPAWAR contract
22a9643ea8Slogwang  * N66001-04-C-6019 ("SEFOS").
23a9643ea8Slogwang  *
24a9643ea8Slogwang  * This software was developed at the University of Cambridge Computer
25a9643ea8Slogwang  * Laboratory with support from a grant from Google, Inc.
26a9643ea8Slogwang  *
27a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or without
28a9643ea8Slogwang  * modification, are permitted provided that the following conditions
29a9643ea8Slogwang  * are met:
30a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
31a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer.
32a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above copyright
33a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer in the
34a9643ea8Slogwang  *    documentation and/or other materials provided with the distribution.
35a9643ea8Slogwang  *
36a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
37a9643ea8Slogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38a9643ea8Slogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39a9643ea8Slogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
40a9643ea8Slogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41a9643ea8Slogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42a9643ea8Slogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43a9643ea8Slogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44a9643ea8Slogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45a9643ea8Slogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46a9643ea8Slogwang  * SUCH DAMAGE.
47a9643ea8Slogwang  *
48a9643ea8Slogwang  * $FreeBSD$
49a9643ea8Slogwang  */
50a9643ea8Slogwang 
51a9643ea8Slogwang #ifndef _SECURITY_MAC_MAC_INTERNAL_H_
52a9643ea8Slogwang #define	_SECURITY_MAC_MAC_INTERNAL_H_
53a9643ea8Slogwang 
54a9643ea8Slogwang #ifndef _KERNEL
55a9643ea8Slogwang #error "no user-serviceable parts inside"
56a9643ea8Slogwang #endif
57a9643ea8Slogwang 
58a9643ea8Slogwang #include <sys/lock.h>
59a9643ea8Slogwang #include <sys/rmlock.h>
60a9643ea8Slogwang 
61a9643ea8Slogwang /*
62a9643ea8Slogwang  * MAC Framework sysctl namespace.
63a9643ea8Slogwang  */
64a9643ea8Slogwang #ifdef SYSCTL_DECL
65a9643ea8Slogwang SYSCTL_DECL(_security_mac);
66a9643ea8Slogwang #endif /* SYSCTL_DECL */
67a9643ea8Slogwang 
68a9643ea8Slogwang /*
69a9643ea8Slogwang  * MAC Framework SDT DTrace probe namespace, macros for declaring entry
70a9643ea8Slogwang  * point probes, macros for invoking them.
71a9643ea8Slogwang  */
72a9643ea8Slogwang #ifdef SDT_PROVIDER_DECLARE
73a9643ea8Slogwang SDT_PROVIDER_DECLARE(mac);		/* MAC Framework-level events. */
74a9643ea8Slogwang SDT_PROVIDER_DECLARE(mac_framework);	/* Entry points to MAC. */
75a9643ea8Slogwang 
76a9643ea8Slogwang #define	MAC_CHECK_PROBE_DEFINE4(name, arg0, arg1, arg2, arg3)		\
77a9643ea8Slogwang 	SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__err,	\
78a9643ea8Slogwang 	    "int", arg0, arg1, arg2, arg3);				\
79a9643ea8Slogwang 	SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__ok,	\
80a9643ea8Slogwang 	    "int", arg0, arg1, arg2, arg3);
81a9643ea8Slogwang 
82a9643ea8Slogwang #define	MAC_CHECK_PROBE_DEFINE3(name, arg0, arg1, arg2)			\
83a9643ea8Slogwang 	SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__err,	\
84a9643ea8Slogwang 	    "int", arg0, arg1, arg2);					\
85a9643ea8Slogwang 	SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__ok,	\
86a9643ea8Slogwang 	    "int", arg0, arg1, arg2);
87a9643ea8Slogwang 
88a9643ea8Slogwang #define	MAC_CHECK_PROBE_DEFINE2(name, arg0, arg1)			\
89a9643ea8Slogwang 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__err,	\
90a9643ea8Slogwang 	    "int", arg0, arg1);						\
91a9643ea8Slogwang 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__ok,	\
92a9643ea8Slogwang 	    "int", arg0, arg1);
93a9643ea8Slogwang 
94a9643ea8Slogwang #define	MAC_CHECK_PROBE_DEFINE1(name, arg0)				\
95a9643ea8Slogwang 	SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__err,	\
96a9643ea8Slogwang 	    "int", arg0);						\
97a9643ea8Slogwang 	SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__ok,	\
98a9643ea8Slogwang 	    "int", arg0);
99a9643ea8Slogwang 
100a9643ea8Slogwang #define	MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, arg3)	do {	\
101*22ce4affSfengbojiang 	if (SDT_PROBES_ENABLED()) {					\
102a9643ea8Slogwang 		if (error) {						\
103a9643ea8Slogwang 			SDT_PROBE5(mac_framework, , name, mac__check__err,\
104a9643ea8Slogwang 			    error, arg0, arg1, arg2, arg3);		\
105a9643ea8Slogwang 		} else {						\
106a9643ea8Slogwang 			SDT_PROBE5(mac_framework, , name, mac__check__ok,\
107a9643ea8Slogwang 			    0, arg0, arg1, arg2, arg3);			\
108a9643ea8Slogwang 		}							\
109*22ce4affSfengbojiang 	}								\
110a9643ea8Slogwang } while (0)
111a9643ea8Slogwang 
112a9643ea8Slogwang #define	MAC_CHECK_PROBE3(name, error, arg0, arg1, arg2)			\
113a9643ea8Slogwang 	MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, 0)
114a9643ea8Slogwang #define	MAC_CHECK_PROBE2(name, error, arg0, arg1)			\
115a9643ea8Slogwang 	MAC_CHECK_PROBE3(name, error, arg0, arg1, 0)
116a9643ea8Slogwang #define	MAC_CHECK_PROBE1(name, error, arg0)				\
117a9643ea8Slogwang 	MAC_CHECK_PROBE2(name, error, arg0, 0)
118a9643ea8Slogwang #endif
119a9643ea8Slogwang 
120a9643ea8Slogwang #define	MAC_GRANT_PROBE_DEFINE2(name, arg0, arg1)			\
121a9643ea8Slogwang 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__err,	\
122a9643ea8Slogwang 	    "int", arg0, arg1);						\
123a9643ea8Slogwang 	SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__ok,	\
124a9643ea8Slogwang 	    "int", arg0, arg1);
125a9643ea8Slogwang 
126a9643ea8Slogwang #define	MAC_GRANT_PROBE2(name, error, arg0, arg1)	do {		\
127*22ce4affSfengbojiang 	if (SDT_PROBES_ENABLED()) {					\
128a9643ea8Slogwang 		if (error) {						\
129a9643ea8Slogwang 			SDT_PROBE3(mac_framework, , name, mac__grant__err,\
130a9643ea8Slogwang 			    error, arg0, arg1);				\
131a9643ea8Slogwang 		} else {						\
132a9643ea8Slogwang 			SDT_PROBE3(mac_framework, , name, mac__grant__ok,\
133a9643ea8Slogwang 			    error, arg0, arg1);				\
134a9643ea8Slogwang 		}							\
135*22ce4affSfengbojiang 	}								\
136a9643ea8Slogwang } while (0)
137a9643ea8Slogwang 
138a9643ea8Slogwang /*
139a9643ea8Slogwang  * MAC Framework global types and typedefs.
140a9643ea8Slogwang  */
141a9643ea8Slogwang LIST_HEAD(mac_policy_list_head, mac_policy_conf);
142a9643ea8Slogwang #ifdef MALLOC_DECLARE
143a9643ea8Slogwang MALLOC_DECLARE(M_MACTEMP);
144a9643ea8Slogwang #endif
145a9643ea8Slogwang 
146a9643ea8Slogwang /*
147a9643ea8Slogwang  * MAC labels -- in-kernel storage format.
148a9643ea8Slogwang  *
149a9643ea8Slogwang  * In general, struct label pointers are embedded in kernel data structures
150a9643ea8Slogwang  * representing objects that may be labeled (and protected).  Struct label is
151a9643ea8Slogwang  * opaque to both kernel services that invoke the MAC Framework and MAC
152a9643ea8Slogwang  * policy modules.  In particular, we do not wish to encode the layout of the
153a9643ea8Slogwang  * label structure into any ABIs.  Historically, the slot array contained
154a9643ea8Slogwang  * unions of {long, void} but now contains uintptr_t.
155a9643ea8Slogwang  */
156a9643ea8Slogwang #define	MAC_MAX_SLOTS	4
157a9643ea8Slogwang #define	MAC_FLAG_INITIALIZED	0x0000001	/* Is initialized for use. */
158a9643ea8Slogwang struct label {
159a9643ea8Slogwang 	int		l_flags;
160a9643ea8Slogwang 	intptr_t	l_perpolicy[MAC_MAX_SLOTS];
161a9643ea8Slogwang };
162a9643ea8Slogwang 
163a9643ea8Slogwang /*
164a9643ea8Slogwang  * Flags for mac_labeled, a bitmask of object types need across the union of
165a9643ea8Slogwang  * all policies currently registered with the MAC Framework, used to key
166a9643ea8Slogwang  * whether or not labels are allocated and constructors for the type are
167a9643ea8Slogwang  * invoked.
168a9643ea8Slogwang  */
169a9643ea8Slogwang #define	MPC_OBJECT_CRED			0x0000000000000001
170a9643ea8Slogwang #define	MPC_OBJECT_PROC			0x0000000000000002
171a9643ea8Slogwang #define	MPC_OBJECT_VNODE		0x0000000000000004
172a9643ea8Slogwang #define	MPC_OBJECT_INPCB		0x0000000000000008
173a9643ea8Slogwang #define	MPC_OBJECT_SOCKET		0x0000000000000010
174a9643ea8Slogwang #define	MPC_OBJECT_DEVFS		0x0000000000000020
175a9643ea8Slogwang #define	MPC_OBJECT_MBUF			0x0000000000000040
176a9643ea8Slogwang #define	MPC_OBJECT_IPQ			0x0000000000000080
177a9643ea8Slogwang #define	MPC_OBJECT_IFNET		0x0000000000000100
178a9643ea8Slogwang #define	MPC_OBJECT_BPFDESC		0x0000000000000200
179a9643ea8Slogwang #define	MPC_OBJECT_PIPE			0x0000000000000400
180a9643ea8Slogwang #define	MPC_OBJECT_MOUNT		0x0000000000000800
181a9643ea8Slogwang #define	MPC_OBJECT_POSIXSEM		0x0000000000001000
182a9643ea8Slogwang #define	MPC_OBJECT_POSIXSHM		0x0000000000002000
183a9643ea8Slogwang #define	MPC_OBJECT_SYSVMSG		0x0000000000004000
184a9643ea8Slogwang #define	MPC_OBJECT_SYSVMSQ		0x0000000000008000
185a9643ea8Slogwang #define	MPC_OBJECT_SYSVSEM		0x0000000000010000
186a9643ea8Slogwang #define	MPC_OBJECT_SYSVSHM		0x0000000000020000
187a9643ea8Slogwang #define	MPC_OBJECT_SYNCACHE		0x0000000000040000
188a9643ea8Slogwang #define	MPC_OBJECT_IP6Q			0x0000000000080000
189a9643ea8Slogwang 
190a9643ea8Slogwang /*
191a9643ea8Slogwang  * MAC Framework global variables.
192a9643ea8Slogwang  */
193a9643ea8Slogwang extern struct mac_policy_list_head	mac_policy_list;
194a9643ea8Slogwang extern struct mac_policy_list_head	mac_static_policy_list;
195a9643ea8Slogwang extern u_int				mac_policy_count;
196a9643ea8Slogwang extern uint64_t				mac_labeled;
197a9643ea8Slogwang extern struct mtx			mac_ifnet_mtx;
198a9643ea8Slogwang 
199a9643ea8Slogwang /*
200a9643ea8Slogwang  * MAC Framework infrastructure functions.
201a9643ea8Slogwang  */
202a9643ea8Slogwang int	mac_error_select(int error1, int error2);
203a9643ea8Slogwang 
204a9643ea8Slogwang void	mac_policy_slock_nosleep(struct rm_priotracker *tracker);
205a9643ea8Slogwang void	mac_policy_slock_sleep(void);
206a9643ea8Slogwang void	mac_policy_sunlock_nosleep(struct rm_priotracker *tracker);
207a9643ea8Slogwang void	mac_policy_sunlock_sleep(void);
208a9643ea8Slogwang 
209a9643ea8Slogwang struct label	*mac_labelzone_alloc(int flags);
210a9643ea8Slogwang void		 mac_labelzone_free(struct label *label);
211a9643ea8Slogwang void		 mac_labelzone_init(void);
212a9643ea8Slogwang 
213a9643ea8Slogwang void	mac_init_label(struct label *label);
214a9643ea8Slogwang void	mac_destroy_label(struct label *label);
215a9643ea8Slogwang int	mac_check_structmac_consistent(struct mac *mac);
216a9643ea8Slogwang int	mac_allocate_slot(void);
217a9643ea8Slogwang 
218*22ce4affSfengbojiang /*
219*22ce4affSfengbojiang  * Lock ifnets to protect labels only if ifnet labels are in use.
220*22ce4affSfengbojiang  */
221*22ce4affSfengbojiang #define MAC_IFNET_LOCK(ifp, locked)	do {				\
222*22ce4affSfengbojiang 	if (mac_labeled & MPC_OBJECT_IFNET) {				\
223*22ce4affSfengbojiang 		mtx_lock(&mac_ifnet_mtx);				\
224*22ce4affSfengbojiang 		locked = 1;						\
225*22ce4affSfengbojiang 	} else {							\
226*22ce4affSfengbojiang 		locked = 0;						\
227*22ce4affSfengbojiang 	}								\
228*22ce4affSfengbojiang } while (0)
229*22ce4affSfengbojiang 
230*22ce4affSfengbojiang #define MAC_IFNET_UNLOCK(ifp, locked)	do {				\
231*22ce4affSfengbojiang 	if (locked) {							\
232*22ce4affSfengbojiang 		mtx_unlock(&mac_ifnet_mtx);				\
233*22ce4affSfengbojiang 		locked = 0;						\
234*22ce4affSfengbojiang 	}								\
235*22ce4affSfengbojiang } while (0)
236a9643ea8Slogwang 
237a9643ea8Slogwang /*
238a9643ea8Slogwang  * MAC Framework per-object type functions.  It's not yet clear how the
239a9643ea8Slogwang  * namespaces, etc, should work for these, so for now, sort by object type.
240a9643ea8Slogwang  */
241a9643ea8Slogwang struct label	*mac_cred_label_alloc(void);
242a9643ea8Slogwang void		 mac_cred_label_free(struct label *label);
243a9643ea8Slogwang struct label	*mac_pipe_label_alloc(void);
244a9643ea8Slogwang void		 mac_pipe_label_free(struct label *label);
245a9643ea8Slogwang struct label	*mac_socket_label_alloc(int flag);
246a9643ea8Slogwang void		 mac_socket_label_free(struct label *label);
247a9643ea8Slogwang struct label	*mac_vnode_label_alloc(void);
248a9643ea8Slogwang void		 mac_vnode_label_free(struct label *label);
249a9643ea8Slogwang 
250a9643ea8Slogwang int	mac_cred_check_relabel(struct ucred *cred, struct label *newlabel);
251a9643ea8Slogwang int	mac_cred_externalize_label(struct label *label, char *elements,
252a9643ea8Slogwang 	    char *outbuf, size_t outbuflen);
253a9643ea8Slogwang int	mac_cred_internalize_label(struct label *label, char *string);
254a9643ea8Slogwang void	mac_cred_relabel(struct ucred *cred, struct label *newlabel);
255a9643ea8Slogwang 
256a9643ea8Slogwang struct label	*mac_mbuf_to_label(struct mbuf *m);
257a9643ea8Slogwang 
258a9643ea8Slogwang void	mac_pipe_copy_label(struct label *src, struct label *dest);
259a9643ea8Slogwang int	mac_pipe_externalize_label(struct label *label, char *elements,
260a9643ea8Slogwang 	    char *outbuf, size_t outbuflen);
261a9643ea8Slogwang int	mac_pipe_internalize_label(struct label *label, char *string);
262a9643ea8Slogwang 
263a9643ea8Slogwang int	mac_socket_label_set(struct ucred *cred, struct socket *so,
264a9643ea8Slogwang 	    struct label *label);
265a9643ea8Slogwang void	mac_socket_copy_label(struct label *src, struct label *dest);
266a9643ea8Slogwang int	mac_socket_externalize_label(struct label *label, char *elements,
267a9643ea8Slogwang 	    char *outbuf, size_t outbuflen);
268a9643ea8Slogwang int	mac_socket_internalize_label(struct label *label, char *string);
269a9643ea8Slogwang 
270a9643ea8Slogwang int	mac_vnode_externalize_label(struct label *label, char *elements,
271a9643ea8Slogwang 	    char *outbuf, size_t outbuflen);
272a9643ea8Slogwang int	mac_vnode_internalize_label(struct label *label, char *string);
273a9643ea8Slogwang void	mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
274a9643ea8Slogwang 	    int *prot);
275a9643ea8Slogwang int	vn_setlabel(struct vnode *vp, struct label *intlabel,
276a9643ea8Slogwang 	    struct ucred *cred);
277a9643ea8Slogwang 
278a9643ea8Slogwang /*
279a9643ea8Slogwang  * MAC Framework composition macros invoke all registered MAC policies for a
280a9643ea8Slogwang  * specific entry point.  They come in two forms: one which permits policies
281a9643ea8Slogwang  * to sleep/block, and another that does not.
282a9643ea8Slogwang  *
283a9643ea8Slogwang  * MAC_POLICY_CHECK performs the designated check by walking the policy
284a9643ea8Slogwang  * module list and checking with each as to how it feels about the request.
285a9643ea8Slogwang  * Note that it returns its value via 'error' in the scope of the caller.
286a9643ea8Slogwang  */
287a9643ea8Slogwang #define	MAC_POLICY_CHECK(check, args...) do {				\
288a9643ea8Slogwang 	struct mac_policy_conf *mpc;					\
289a9643ea8Slogwang 									\
290a9643ea8Slogwang 	error = 0;							\
291a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
292a9643ea8Slogwang 		if (mpc->mpc_ops->mpo_ ## check != NULL)		\
293a9643ea8Slogwang 			error = mac_error_select(			\
294a9643ea8Slogwang 			    mpc->mpc_ops->mpo_ ## check (args),		\
295a9643ea8Slogwang 			    error);					\
296a9643ea8Slogwang 	}								\
297a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {				\
298a9643ea8Slogwang 		mac_policy_slock_sleep();				\
299a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
300a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
301a9643ea8Slogwang 				error = mac_error_select(		\
302a9643ea8Slogwang 				    mpc->mpc_ops->mpo_ ## check (args),	\
303a9643ea8Slogwang 				    error);				\
304a9643ea8Slogwang 		}							\
305a9643ea8Slogwang 		mac_policy_sunlock_sleep();				\
306a9643ea8Slogwang 	}								\
307a9643ea8Slogwang } while (0)
308a9643ea8Slogwang 
309a9643ea8Slogwang #define	MAC_POLICY_CHECK_NOSLEEP(check, args...) do {			\
310a9643ea8Slogwang 	struct mac_policy_conf *mpc;					\
311a9643ea8Slogwang 									\
312a9643ea8Slogwang 	error = 0;							\
313a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
314a9643ea8Slogwang 		if (mpc->mpc_ops->mpo_ ## check != NULL)		\
315a9643ea8Slogwang 			error = mac_error_select(			\
316a9643ea8Slogwang 			    mpc->mpc_ops->mpo_ ## check (args),		\
317a9643ea8Slogwang 			    error);					\
318a9643ea8Slogwang 	}								\
319a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {				\
320a9643ea8Slogwang 		struct rm_priotracker tracker;				\
321a9643ea8Slogwang 									\
322a9643ea8Slogwang 		mac_policy_slock_nosleep(&tracker);			\
323a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
324a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
325a9643ea8Slogwang 				error = mac_error_select(		\
326a9643ea8Slogwang 				    mpc->mpc_ops->mpo_ ## check (args),	\
327a9643ea8Slogwang 				    error);				\
328a9643ea8Slogwang 		}							\
329a9643ea8Slogwang 		mac_policy_sunlock_nosleep(&tracker);			\
330a9643ea8Slogwang 	}								\
331a9643ea8Slogwang } while (0)
332a9643ea8Slogwang 
333a9643ea8Slogwang /*
334a9643ea8Slogwang  * MAC_POLICY_GRANT performs the designated check by walking the policy
335a9643ea8Slogwang  * module list and checking with each as to how it feels about the request.
336a9643ea8Slogwang  * Unlike MAC_POLICY_CHECK, it grants if any policies return '0', and
337a9643ea8Slogwang  * otherwise returns EPERM.  Note that it returns its value via 'error' in
338a9643ea8Slogwang  * the scope of the caller.
339a9643ea8Slogwang  */
340a9643ea8Slogwang #define	MAC_POLICY_GRANT_NOSLEEP(check, args...) do {			\
341a9643ea8Slogwang 	struct mac_policy_conf *mpc;					\
342a9643ea8Slogwang 									\
343a9643ea8Slogwang 	error = EPERM;							\
344a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
345a9643ea8Slogwang 		if (mpc->mpc_ops->mpo_ ## check != NULL) {		\
346a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## check(args) == 0)	\
347a9643ea8Slogwang 				error = 0;				\
348a9643ea8Slogwang 		}							\
349a9643ea8Slogwang 	}								\
350a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {				\
351a9643ea8Slogwang 		struct rm_priotracker tracker;				\
352a9643ea8Slogwang 									\
353a9643ea8Slogwang 		mac_policy_slock_nosleep(&tracker);			\
354a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
355a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## check != NULL) {	\
356a9643ea8Slogwang 				if (mpc->mpc_ops->mpo_ ## check (args)	\
357a9643ea8Slogwang 				    == 0)				\
358a9643ea8Slogwang 					error = 0;			\
359a9643ea8Slogwang 			}						\
360a9643ea8Slogwang 		}							\
361a9643ea8Slogwang 		mac_policy_sunlock_nosleep(&tracker);			\
362a9643ea8Slogwang 	}								\
363a9643ea8Slogwang } while (0)
364a9643ea8Slogwang 
365a9643ea8Slogwang /*
366a9643ea8Slogwang  * MAC_POLICY_BOOLEAN performs the designated boolean composition by walking
367a9643ea8Slogwang  * the module list, invoking each instance of the operation, and combining
368a9643ea8Slogwang  * the results using the passed C operator.  Note that it returns its value
369a9643ea8Slogwang  * via 'result' in the scope of the caller, which should be initialized by
370a9643ea8Slogwang  * the caller in a meaningful way to get a meaningful result.
371a9643ea8Slogwang  */
372a9643ea8Slogwang #define	MAC_POLICY_BOOLEAN(operation, composition, args...) do {	\
373a9643ea8Slogwang 	struct mac_policy_conf *mpc;					\
374a9643ea8Slogwang 									\
375a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
376a9643ea8Slogwang 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
377a9643ea8Slogwang 			result = result composition			\
378a9643ea8Slogwang 			    mpc->mpc_ops->mpo_ ## operation (args);	\
379a9643ea8Slogwang 	}								\
380a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {				\
381a9643ea8Slogwang 		mac_policy_slock_sleep();				\
382a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
383a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
384a9643ea8Slogwang 				result = result composition		\
385a9643ea8Slogwang 				    mpc->mpc_ops->mpo_ ## operation	\
386a9643ea8Slogwang 				    (args);				\
387a9643ea8Slogwang 		}							\
388a9643ea8Slogwang 		mac_policy_sunlock_sleep();				\
389a9643ea8Slogwang 	}								\
390a9643ea8Slogwang } while (0)
391a9643ea8Slogwang 
392a9643ea8Slogwang #define	MAC_POLICY_BOOLEAN_NOSLEEP(operation, composition, args...) do {\
393a9643ea8Slogwang 	struct mac_policy_conf *mpc;					\
394a9643ea8Slogwang 									\
395a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
396a9643ea8Slogwang 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
397a9643ea8Slogwang 			result = result composition			\
398a9643ea8Slogwang 			    mpc->mpc_ops->mpo_ ## operation (args);	\
399a9643ea8Slogwang 	}								\
400a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {				\
401a9643ea8Slogwang 		struct rm_priotracker tracker;				\
402a9643ea8Slogwang 									\
403a9643ea8Slogwang 		mac_policy_slock_nosleep(&tracker);			\
404a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
405a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
406a9643ea8Slogwang 				result = result composition		\
407a9643ea8Slogwang 				    mpc->mpc_ops->mpo_ ## operation	\
408a9643ea8Slogwang 				    (args);				\
409a9643ea8Slogwang 		}							\
410a9643ea8Slogwang 		mac_policy_sunlock_nosleep(&tracker);			\
411a9643ea8Slogwang 	}								\
412a9643ea8Slogwang } while (0)
413a9643ea8Slogwang 
414a9643ea8Slogwang /*
415a9643ea8Slogwang  * MAC_POLICY_EXTERNALIZE queries each policy to see if it can generate an
416a9643ea8Slogwang  * externalized version of a label element by name.  Policies declare whether
417a9643ea8Slogwang  * they have matched a particular element name, parsed from the string by
418a9643ea8Slogwang  * MAC_POLICY_EXTERNALIZE, and an error is returned if any element is matched
419a9643ea8Slogwang  * by no policy.
420a9643ea8Slogwang  */
421a9643ea8Slogwang #define	MAC_POLICY_EXTERNALIZE(type, label, elementlist, outbuf, 	\
422a9643ea8Slogwang     outbuflen) do {							\
423a9643ea8Slogwang 	int claimed, first, ignorenotfound, savedlen;			\
424a9643ea8Slogwang 	char *element_name, *element_temp;				\
425a9643ea8Slogwang 	struct sbuf sb;							\
426a9643ea8Slogwang 									\
427a9643ea8Slogwang 	error = 0;							\
428a9643ea8Slogwang 	first = 1;							\
429a9643ea8Slogwang 	sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN);		\
430a9643ea8Slogwang 	element_temp = elementlist;					\
431a9643ea8Slogwang 	while ((element_name = strsep(&element_temp, ",")) != NULL) {	\
432a9643ea8Slogwang 		if (element_name[0] == '?') {				\
433a9643ea8Slogwang 			element_name++;					\
434a9643ea8Slogwang 			ignorenotfound = 1;				\
435a9643ea8Slogwang 		 } else							\
436a9643ea8Slogwang 			ignorenotfound = 0;				\
437a9643ea8Slogwang 		savedlen = sbuf_len(&sb);				\
438a9643ea8Slogwang 		if (first)						\
439a9643ea8Slogwang 			error = sbuf_printf(&sb, "%s/", element_name);	\
440a9643ea8Slogwang 		else							\
441a9643ea8Slogwang 			error = sbuf_printf(&sb, ",%s/", element_name);	\
442a9643ea8Slogwang 		if (error == -1) {					\
443a9643ea8Slogwang 			error = EINVAL;	/* XXX: E2BIG? */		\
444a9643ea8Slogwang 			break;						\
445a9643ea8Slogwang 		}							\
446a9643ea8Slogwang 		claimed = 0;						\
447a9643ea8Slogwang 		MAC_POLICY_CHECK(type ## _externalize_label, label,	\
448a9643ea8Slogwang 		    element_name, &sb, &claimed);			\
449a9643ea8Slogwang 		if (error)						\
450a9643ea8Slogwang 			break;						\
451a9643ea8Slogwang 		if (claimed == 0 && ignorenotfound) {			\
452a9643ea8Slogwang 			/* Revert last label name. */			\
453a9643ea8Slogwang 			sbuf_setpos(&sb, savedlen);			\
454a9643ea8Slogwang 		} else if (claimed != 1) {				\
455a9643ea8Slogwang 			error = EINVAL;	/* XXX: ENOLABEL? */		\
456a9643ea8Slogwang 			break;						\
457a9643ea8Slogwang 		} else {						\
458a9643ea8Slogwang 			first = 0;					\
459a9643ea8Slogwang 		}							\
460a9643ea8Slogwang 	}								\
461a9643ea8Slogwang 	sbuf_finish(&sb);						\
462a9643ea8Slogwang } while (0)
463a9643ea8Slogwang 
464a9643ea8Slogwang /*
465a9643ea8Slogwang  * MAC_POLICY_INTERNALIZE presents parsed element names and data to each
466a9643ea8Slogwang  * policy to see if any is willing to claim it and internalize the label
467a9643ea8Slogwang  * data.  If no policies match, an error is returned.
468a9643ea8Slogwang  */
469a9643ea8Slogwang #define	MAC_POLICY_INTERNALIZE(type, label, instring) do {		\
470a9643ea8Slogwang 	char *element, *element_name, *element_data;			\
471a9643ea8Slogwang 	int claimed;							\
472a9643ea8Slogwang 									\
473a9643ea8Slogwang 	error = 0;							\
474a9643ea8Slogwang 	element = instring;						\
475a9643ea8Slogwang 	while ((element_name = strsep(&element, ",")) != NULL) {	\
476a9643ea8Slogwang 		element_data = element_name;				\
477a9643ea8Slogwang 		element_name = strsep(&element_data, "/");		\
478a9643ea8Slogwang 		if (element_data == NULL) {				\
479a9643ea8Slogwang 			error = EINVAL;					\
480a9643ea8Slogwang 			break;						\
481a9643ea8Slogwang 		}							\
482a9643ea8Slogwang 		claimed = 0;						\
483a9643ea8Slogwang 		MAC_POLICY_CHECK(type ## _internalize_label, label,	\
484a9643ea8Slogwang 		    element_name, element_data, &claimed);		\
485a9643ea8Slogwang 		if (error)						\
486a9643ea8Slogwang 			break;						\
487a9643ea8Slogwang 		if (claimed != 1) {					\
488a9643ea8Slogwang 			/* XXXMAC: Another error here? */		\
489a9643ea8Slogwang 			error = EINVAL;					\
490a9643ea8Slogwang 			break;						\
491a9643ea8Slogwang 		}							\
492a9643ea8Slogwang 	}								\
493a9643ea8Slogwang } while (0)
494a9643ea8Slogwang 
495a9643ea8Slogwang /*
496a9643ea8Slogwang  * MAC_POLICY_PERFORM performs the designated operation by walking the policy
497a9643ea8Slogwang  * module list and invoking that operation for each policy.
498a9643ea8Slogwang  */
499a9643ea8Slogwang #define	MAC_POLICY_PERFORM(operation, args...) do {			\
500a9643ea8Slogwang 	struct mac_policy_conf *mpc;					\
501a9643ea8Slogwang 									\
502a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
503a9643ea8Slogwang 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
504a9643ea8Slogwang 			mpc->mpc_ops->mpo_ ## operation (args);		\
505a9643ea8Slogwang 	}								\
506a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {				\
507a9643ea8Slogwang 		mac_policy_slock_sleep();				\
508a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
509a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
510a9643ea8Slogwang 				mpc->mpc_ops->mpo_ ## operation (args);	\
511a9643ea8Slogwang 		}							\
512a9643ea8Slogwang 		mac_policy_sunlock_sleep();				\
513a9643ea8Slogwang 	}								\
514a9643ea8Slogwang } while (0)
515a9643ea8Slogwang 
516a9643ea8Slogwang #define	MAC_POLICY_PERFORM_NOSLEEP(operation, args...) do {		\
517a9643ea8Slogwang 	struct mac_policy_conf *mpc;					\
518a9643ea8Slogwang 									\
519a9643ea8Slogwang 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
520a9643ea8Slogwang 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
521a9643ea8Slogwang 			mpc->mpc_ops->mpo_ ## operation (args);		\
522a9643ea8Slogwang 	}								\
523a9643ea8Slogwang 	if (!LIST_EMPTY(&mac_policy_list)) {				\
524a9643ea8Slogwang 		struct rm_priotracker tracker;				\
525a9643ea8Slogwang 									\
526a9643ea8Slogwang 		mac_policy_slock_nosleep(&tracker);			\
527a9643ea8Slogwang 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
528a9643ea8Slogwang 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
529a9643ea8Slogwang 				mpc->mpc_ops->mpo_ ## operation (args);	\
530a9643ea8Slogwang 		}							\
531a9643ea8Slogwang 		mac_policy_sunlock_nosleep(&tracker);			\
532a9643ea8Slogwang 	}								\
533a9643ea8Slogwang } while (0)
534a9643ea8Slogwang 
535a9643ea8Slogwang #endif /* !_SECURITY_MAC_MAC_INTERNAL_H_ */
536