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