xref: /freebsd/sys/security/mac/mac_internal.h (revision f64a688d)
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 struct label	*mac_vnode_label_alloc(void);
246 void		 mac_vnode_label_free(struct label *label);
247 
248 int	mac_cred_check_relabel(struct ucred *cred, struct label *newlabel);
249 int	mac_cred_externalize_label(struct label *label, char *elements,
250 	    char *outbuf, size_t outbuflen);
251 int	mac_cred_internalize_label(struct label *label, char *string);
252 void	mac_cred_relabel(struct ucred *cred, struct label *newlabel);
253 
254 struct label	*mac_mbuf_to_label(struct mbuf *m);
255 
256 void	mac_pipe_copy_label(struct label *src, struct label *dest);
257 int	mac_pipe_externalize_label(struct label *label, char *elements,
258 	    char *outbuf, size_t outbuflen);
259 int	mac_pipe_internalize_label(struct label *label, char *string);
260 
261 int	mac_socket_label_set(struct ucred *cred, struct socket *so,
262 	    struct label *label);
263 void	mac_socket_copy_label(struct label *src, struct label *dest);
264 int	mac_socket_externalize_label(struct label *label, char *elements,
265 	    char *outbuf, size_t outbuflen);
266 int	mac_socket_internalize_label(struct label *label, char *string);
267 
268 int	mac_vnode_externalize_label(struct label *label, char *elements,
269 	    char *outbuf, size_t outbuflen);
270 int	mac_vnode_internalize_label(struct label *label, char *string);
271 void	mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
272 	    int *prot);
273 int	vn_setlabel(struct vnode *vp, struct label *intlabel,
274 	    struct ucred *cred);
275 
276 /*
277  * MAC Framework composition macros invoke all registered MAC policies for a
278  * specific entry point.  They come in two forms: one which permits policies
279  * to sleep/block, and another that does not.
280  *
281  * MAC_POLICY_CHECK performs the designated check by walking the policy
282  * module list and checking with each as to how it feels about the request.
283  * Note that it returns its value via 'error' in the scope of the caller.
284  */
285 #define	MAC_POLICY_CHECK(check, args...) do {				\
286 	struct mac_policy_conf *mpc;					\
287 									\
288 	error = 0;							\
289 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
290 		if (mpc->mpc_ops->mpo_ ## check != NULL)		\
291 			error = mac_error_select(			\
292 			    mpc->mpc_ops->mpo_ ## check (args),		\
293 			    error);					\
294 	}								\
295 	if (!LIST_EMPTY(&mac_policy_list)) {				\
296 		mac_policy_slock_sleep();				\
297 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
298 			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
299 				error = mac_error_select(		\
300 				    mpc->mpc_ops->mpo_ ## check (args),	\
301 				    error);				\
302 		}							\
303 		mac_policy_sunlock_sleep();				\
304 	}								\
305 } while (0)
306 
307 #define	MAC_POLICY_CHECK_NOSLEEP(check, args...) do {			\
308 	struct mac_policy_conf *mpc;					\
309 									\
310 	error = 0;							\
311 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
312 		if (mpc->mpc_ops->mpo_ ## check != NULL)		\
313 			error = mac_error_select(			\
314 			    mpc->mpc_ops->mpo_ ## check (args),		\
315 			    error);					\
316 	}								\
317 	if (!LIST_EMPTY(&mac_policy_list)) {				\
318 		struct rm_priotracker tracker;				\
319 									\
320 		mac_policy_slock_nosleep(&tracker);			\
321 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
322 			if (mpc->mpc_ops->mpo_ ## check != NULL)	\
323 				error = mac_error_select(		\
324 				    mpc->mpc_ops->mpo_ ## check (args),	\
325 				    error);				\
326 		}							\
327 		mac_policy_sunlock_nosleep(&tracker);			\
328 	}								\
329 } while (0)
330 
331 /*
332  * MAC_POLICY_GRANT performs the designated check by walking the policy
333  * module list and checking with each as to how it feels about the request.
334  * Unlike MAC_POLICY_CHECK, it grants if any policies return '0', and
335  * otherwise returns EPERM.  Note that it returns its value via 'error' in
336  * the scope of the caller.
337  */
338 #define	MAC_POLICY_GRANT_NOSLEEP(check, args...) do {			\
339 	struct mac_policy_conf *mpc;					\
340 									\
341 	error = EPERM;							\
342 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
343 		if (mpc->mpc_ops->mpo_ ## check != NULL) {		\
344 			if (mpc->mpc_ops->mpo_ ## check(args) == 0)	\
345 				error = 0;				\
346 		}							\
347 	}								\
348 	if (!LIST_EMPTY(&mac_policy_list)) {				\
349 		struct rm_priotracker tracker;				\
350 									\
351 		mac_policy_slock_nosleep(&tracker);			\
352 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
353 			if (mpc->mpc_ops->mpo_ ## check != NULL) {	\
354 				if (mpc->mpc_ops->mpo_ ## check (args)	\
355 				    == 0)				\
356 					error = 0;			\
357 			}						\
358 		}							\
359 		mac_policy_sunlock_nosleep(&tracker);			\
360 	}								\
361 } while (0)
362 
363 /*
364  * MAC_POLICY_BOOLEAN performs the designated boolean composition by walking
365  * the module list, invoking each instance of the operation, and combining
366  * the results using the passed C operator.  Note that it returns its value
367  * via 'result' in the scope of the caller, which should be initialized by
368  * the caller in a meaningful way to get a meaningful result.
369  */
370 #define	MAC_POLICY_BOOLEAN(operation, composition, args...) do {	\
371 	struct mac_policy_conf *mpc;					\
372 									\
373 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
374 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
375 			result = result composition			\
376 			    mpc->mpc_ops->mpo_ ## operation (args);	\
377 	}								\
378 	if (!LIST_EMPTY(&mac_policy_list)) {				\
379 		mac_policy_slock_sleep();				\
380 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
381 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
382 				result = result composition		\
383 				    mpc->mpc_ops->mpo_ ## operation	\
384 				    (args);				\
385 		}							\
386 		mac_policy_sunlock_sleep();				\
387 	}								\
388 } while (0)
389 
390 #define	MAC_POLICY_BOOLEAN_NOSLEEP(operation, composition, args...) do {\
391 	struct mac_policy_conf *mpc;					\
392 									\
393 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
394 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
395 			result = result composition			\
396 			    mpc->mpc_ops->mpo_ ## operation (args);	\
397 	}								\
398 	if (!LIST_EMPTY(&mac_policy_list)) {				\
399 		struct rm_priotracker tracker;				\
400 									\
401 		mac_policy_slock_nosleep(&tracker);			\
402 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
403 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
404 				result = result composition		\
405 				    mpc->mpc_ops->mpo_ ## operation	\
406 				    (args);				\
407 		}							\
408 		mac_policy_sunlock_nosleep(&tracker);			\
409 	}								\
410 } while (0)
411 
412 /*
413  * MAC_POLICY_EXTERNALIZE queries each policy to see if it can generate an
414  * externalized version of a label element by name.  Policies declare whether
415  * they have matched a particular element name, parsed from the string by
416  * MAC_POLICY_EXTERNALIZE, and an error is returned if any element is matched
417  * by no policy.
418  */
419 #define	MAC_POLICY_EXTERNALIZE(type, label, elementlist, outbuf, 	\
420     outbuflen) do {							\
421 	int claimed, first, ignorenotfound, savedlen;			\
422 	char *element_name, *element_temp;				\
423 	struct sbuf sb;							\
424 									\
425 	error = 0;							\
426 	first = 1;							\
427 	sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN);		\
428 	element_temp = elementlist;					\
429 	while ((element_name = strsep(&element_temp, ",")) != NULL) {	\
430 		if (element_name[0] == '?') {				\
431 			element_name++;					\
432 			ignorenotfound = 1;				\
433 		 } else							\
434 			ignorenotfound = 0;				\
435 		savedlen = sbuf_len(&sb);				\
436 		if (first)						\
437 			error = sbuf_printf(&sb, "%s/", element_name);	\
438 		else							\
439 			error = sbuf_printf(&sb, ",%s/", element_name);	\
440 		if (error == -1) {					\
441 			error = EINVAL;	/* XXX: E2BIG? */		\
442 			break;						\
443 		}							\
444 		claimed = 0;						\
445 		MAC_POLICY_CHECK(type ## _externalize_label, label,	\
446 		    element_name, &sb, &claimed);			\
447 		if (error)						\
448 			break;						\
449 		if (claimed == 0 && ignorenotfound) {			\
450 			/* Revert last label name. */			\
451 			sbuf_setpos(&sb, savedlen);			\
452 		} else if (claimed != 1) {				\
453 			error = EINVAL;	/* XXX: ENOLABEL? */		\
454 			break;						\
455 		} else {						\
456 			first = 0;					\
457 		}							\
458 	}								\
459 	sbuf_finish(&sb);						\
460 } while (0)
461 
462 /*
463  * MAC_POLICY_INTERNALIZE presents parsed element names and data to each
464  * policy to see if any is willing to claim it and internalize the label
465  * data.  If no policies match, an error is returned.
466  */
467 #define	MAC_POLICY_INTERNALIZE(type, label, instring) do {		\
468 	char *element, *element_name, *element_data;			\
469 	int claimed;							\
470 									\
471 	error = 0;							\
472 	element = instring;						\
473 	while ((element_name = strsep(&element, ",")) != NULL) {	\
474 		element_data = element_name;				\
475 		element_name = strsep(&element_data, "/");		\
476 		if (element_data == NULL) {				\
477 			error = EINVAL;					\
478 			break;						\
479 		}							\
480 		claimed = 0;						\
481 		MAC_POLICY_CHECK(type ## _internalize_label, label,	\
482 		    element_name, element_data, &claimed);		\
483 		if (error)						\
484 			break;						\
485 		if (claimed != 1) {					\
486 			/* XXXMAC: Another error here? */		\
487 			error = EINVAL;					\
488 			break;						\
489 		}							\
490 	}								\
491 } while (0)
492 
493 /*
494  * MAC_POLICY_PERFORM performs the designated operation by walking the policy
495  * module list and invoking that operation for each policy.
496  */
497 #define	MAC_POLICY_PERFORM(operation, args...) do {			\
498 	struct mac_policy_conf *mpc;					\
499 									\
500 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
501 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
502 			mpc->mpc_ops->mpo_ ## operation (args);		\
503 	}								\
504 	if (!LIST_EMPTY(&mac_policy_list)) {				\
505 		mac_policy_slock_sleep();				\
506 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
507 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
508 				mpc->mpc_ops->mpo_ ## operation (args);	\
509 		}							\
510 		mac_policy_sunlock_sleep();				\
511 	}								\
512 } while (0)
513 
514 #define	MAC_POLICY_PERFORM_NOSLEEP(operation, args...) do {		\
515 	struct mac_policy_conf *mpc;					\
516 									\
517 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {		\
518 		if (mpc->mpc_ops->mpo_ ## operation != NULL)		\
519 			mpc->mpc_ops->mpo_ ## operation (args);		\
520 	}								\
521 	if (!LIST_EMPTY(&mac_policy_list)) {				\
522 		struct rm_priotracker tracker;				\
523 									\
524 		mac_policy_slock_nosleep(&tracker);			\
525 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {		\
526 			if (mpc->mpc_ops->mpo_ ## operation != NULL)	\
527 				mpc->mpc_ops->mpo_ ## operation (args);	\
528 		}							\
529 		mac_policy_sunlock_nosleep(&tracker);			\
530 	}								\
531 } while (0)
532 
533 #endif /* !_SECURITY_MAC_MAC_INTERNAL_H_ */
534