xref: /freebsd/sys/security/mac_mls/mac_mls.c (revision 02e9120893770924227138ba49df1edb3896112a)
1 /*-
2  * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson
3  * Copyright (c) 2001-2005 McAfee, Inc.
4  * Copyright (c) 2006 SPARTA, Inc.
5  * All rights reserved.
6  *
7  * This software was developed by Robert Watson for the TrustedBSD Project.
8  *
9  * This software was developed for the FreeBSD Project in part by McAfee
10  * Research, the Security Research Division of McAfee, Inc. under
11  * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
12  * CHATS research program.
13  *
14  * This software was enhanced by SPARTA ISSO under SPAWAR contract
15  * N66001-04-C-6019 ("SEFOS").
16  *
17  * This software was developed at the University of Cambridge Computer
18  * Laboratory with support from a grant from Google, Inc.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  */
41 
42 /*
43  * Developed by the TrustedBSD Project.
44  *
45  * MLS fixed label mandatory confidentiality policy.
46  */
47 
48 #include <sys/types.h>
49 #include <sys/param.h>
50 #include <sys/acl.h>
51 #include <sys/conf.h>
52 #include <sys/extattr.h>
53 #include <sys/kernel.h>
54 #include <sys/ksem.h>
55 #include <sys/mman.h>
56 #include <sys/malloc.h>
57 #include <sys/mount.h>
58 #include <sys/proc.h>
59 #include <sys/sbuf.h>
60 #include <sys/systm.h>
61 #include <sys/sysproto.h>
62 #include <sys/sysent.h>
63 #include <sys/systm.h>
64 #include <sys/vnode.h>
65 #include <sys/file.h>
66 #include <sys/socket.h>
67 #include <sys/socketvar.h>
68 #include <sys/pipe.h>
69 #include <sys/sx.h>
70 #include <sys/sysctl.h>
71 #include <sys/msg.h>
72 #include <sys/sem.h>
73 #include <sys/shm.h>
74 
75 #include <fs/devfs/devfs.h>
76 
77 #include <net/bpfdesc.h>
78 #include <net/if.h>
79 #include <net/if_types.h>
80 #include <net/if_var.h>
81 
82 #include <netinet/in.h>
83 #include <netinet/in_pcb.h>
84 #include <netinet/ip_var.h>
85 
86 #include <vm/uma.h>
87 #include <vm/vm.h>
88 
89 #include <security/mac/mac_policy.h>
90 #include <security/mac_mls/mac_mls.h>
91 
92 SYSCTL_DECL(_security_mac);
93 
94 static SYSCTL_NODE(_security_mac, OID_AUTO, mls,
95     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
96     "TrustedBSD mac_mls policy controls");
97 
98 static int	mls_label_size = sizeof(struct mac_mls);
99 SYSCTL_INT(_security_mac_mls, OID_AUTO, label_size, CTLFLAG_RD,
100     &mls_label_size, 0, "Size of struct mac_mls");
101 
102 static int	mls_enabled = 1;
103 SYSCTL_INT(_security_mac_mls, OID_AUTO, enabled, CTLFLAG_RWTUN, &mls_enabled, 0,
104     "Enforce MAC/MLS policy");
105 
106 static int	destroyed_not_inited;
107 SYSCTL_INT(_security_mac_mls, OID_AUTO, destroyed_not_inited, CTLFLAG_RD,
108     &destroyed_not_inited, 0, "Count of labels destroyed but not inited");
109 
110 static int	ptys_equal = 0;
111 SYSCTL_INT(_security_mac_mls, OID_AUTO, ptys_equal, CTLFLAG_RWTUN,
112     &ptys_equal, 0, "Label pty devices as mls/equal on create");
113 
114 static int	revocation_enabled = 0;
115 SYSCTL_INT(_security_mac_mls, OID_AUTO, revocation_enabled, CTLFLAG_RWTUN,
116     &revocation_enabled, 0, "Revoke access to objects on relabel");
117 
118 static int	max_compartments = MAC_MLS_MAX_COMPARTMENTS;
119 SYSCTL_INT(_security_mac_mls, OID_AUTO, max_compartments, CTLFLAG_RD,
120     &max_compartments, 0, "Maximum compartments the policy supports");
121 
122 static int	mls_slot;
123 #define	SLOT(l)	((struct mac_mls *)mac_label_get((l), mls_slot))
124 #define	SLOT_SET(l, val) mac_label_set((l), mls_slot, (uintptr_t)(val))
125 
126 static uma_zone_t	zone_mls;
127 
128 static __inline int
129 mls_bit_set_empty(u_char *set) {
130 	int i;
131 
132 	for (i = 0; i < MAC_MLS_MAX_COMPARTMENTS >> 3; i++)
133 		if (set[i] != 0)
134 			return (0);
135 	return (1);
136 }
137 
138 static struct mac_mls *
139 mls_alloc(int flag)
140 {
141 
142 	return (uma_zalloc(zone_mls, flag | M_ZERO));
143 }
144 
145 static void
146 mls_free(struct mac_mls *mm)
147 {
148 
149 	if (mm != NULL)
150 		uma_zfree(zone_mls, mm);
151 	else
152 		atomic_add_int(&destroyed_not_inited, 1);
153 }
154 
155 static int
156 mls_atmostflags(struct mac_mls *mm, int flags)
157 {
158 
159 	if ((mm->mm_flags & flags) != mm->mm_flags)
160 		return (EINVAL);
161 	return (0);
162 }
163 
164 static int
165 mls_dominate_element(struct mac_mls_element *a, struct mac_mls_element *b)
166 {
167 	int bit;
168 
169 	switch (a->mme_type) {
170 	case MAC_MLS_TYPE_EQUAL:
171 	case MAC_MLS_TYPE_HIGH:
172 		return (1);
173 
174 	case MAC_MLS_TYPE_LOW:
175 		switch (b->mme_type) {
176 		case MAC_MLS_TYPE_LEVEL:
177 		case MAC_MLS_TYPE_HIGH:
178 			return (0);
179 
180 		case MAC_MLS_TYPE_EQUAL:
181 		case MAC_MLS_TYPE_LOW:
182 			return (1);
183 
184 		default:
185 			panic("mls_dominate_element: b->mme_type invalid");
186 		}
187 
188 	case MAC_MLS_TYPE_LEVEL:
189 		switch (b->mme_type) {
190 		case MAC_MLS_TYPE_EQUAL:
191 		case MAC_MLS_TYPE_LOW:
192 			return (1);
193 
194 		case MAC_MLS_TYPE_HIGH:
195 			return (0);
196 
197 		case MAC_MLS_TYPE_LEVEL:
198 			for (bit = 1; bit <= MAC_MLS_MAX_COMPARTMENTS; bit++)
199 				if (!MAC_MLS_BIT_TEST(bit,
200 				    a->mme_compartments) &&
201 				    MAC_MLS_BIT_TEST(bit, b->mme_compartments))
202 					return (0);
203 			return (a->mme_level >= b->mme_level);
204 
205 		default:
206 			panic("mls_dominate_element: b->mme_type invalid");
207 		}
208 
209 	default:
210 		panic("mls_dominate_element: a->mme_type invalid");
211 	}
212 
213 	return (0);
214 }
215 
216 static int
217 mls_range_in_range(struct mac_mls *rangea, struct mac_mls *rangeb)
218 {
219 
220 	return (mls_dominate_element(&rangeb->mm_rangehigh,
221 	    &rangea->mm_rangehigh) &&
222 	    mls_dominate_element(&rangea->mm_rangelow,
223 	    &rangeb->mm_rangelow));
224 }
225 
226 static int
227 mls_effective_in_range(struct mac_mls *effective, struct mac_mls *range)
228 {
229 
230 	KASSERT((effective->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
231 	    ("mls_effective_in_range: a not effective"));
232 	KASSERT((range->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
233 	    ("mls_effective_in_range: b not range"));
234 
235 	return (mls_dominate_element(&range->mm_rangehigh,
236 	    &effective->mm_effective) &&
237 	    mls_dominate_element(&effective->mm_effective,
238 	    &range->mm_rangelow));
239 
240 	return (1);
241 }
242 
243 static int
244 mls_dominate_effective(struct mac_mls *a, struct mac_mls *b)
245 {
246 	KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
247 	    ("mls_dominate_effective: a not effective"));
248 	KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
249 	    ("mls_dominate_effective: b not effective"));
250 
251 	return (mls_dominate_element(&a->mm_effective, &b->mm_effective));
252 }
253 
254 static int
255 mls_equal_element(struct mac_mls_element *a, struct mac_mls_element *b)
256 {
257 
258 	if (a->mme_type == MAC_MLS_TYPE_EQUAL ||
259 	    b->mme_type == MAC_MLS_TYPE_EQUAL)
260 		return (1);
261 
262 	return (a->mme_type == b->mme_type && a->mme_level == b->mme_level);
263 }
264 
265 static int
266 mls_equal_effective(struct mac_mls *a, struct mac_mls *b)
267 {
268 
269 	KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
270 	    ("mls_equal_effective: a not effective"));
271 	KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
272 	    ("mls_equal_effective: b not effective"));
273 
274 	return (mls_equal_element(&a->mm_effective, &b->mm_effective));
275 }
276 
277 static int
278 mls_contains_equal(struct mac_mls *mm)
279 {
280 
281 	if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
282 		if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
283 			return (1);
284 
285 	if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
286 		if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL)
287 			return (1);
288 		if (mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
289 			return (1);
290 	}
291 
292 	return (0);
293 }
294 
295 static int
296 mls_subject_privileged(struct mac_mls *mm)
297 {
298 
299 	KASSERT((mm->mm_flags & MAC_MLS_FLAGS_BOTH) == MAC_MLS_FLAGS_BOTH,
300 	    ("mls_subject_privileged: subject doesn't have both labels"));
301 
302 	/* If the effective is EQUAL, it's ok. */
303 	if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
304 		return (0);
305 
306 	/* If either range endpoint is EQUAL, it's ok. */
307 	if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL ||
308 	    mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
309 		return (0);
310 
311 	/* If the range is low-high, it's ok. */
312 	if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_LOW &&
313 	    mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_HIGH)
314 		return (0);
315 
316 	/* It's not ok. */
317 	return (EPERM);
318 }
319 
320 static int
321 mls_valid(struct mac_mls *mm)
322 {
323 
324 	if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
325 		switch (mm->mm_effective.mme_type) {
326 		case MAC_MLS_TYPE_LEVEL:
327 			break;
328 
329 		case MAC_MLS_TYPE_EQUAL:
330 		case MAC_MLS_TYPE_HIGH:
331 		case MAC_MLS_TYPE_LOW:
332 			if (mm->mm_effective.mme_level != 0 ||
333 			    !MAC_MLS_BIT_SET_EMPTY(
334 			    mm->mm_effective.mme_compartments))
335 				return (EINVAL);
336 			break;
337 
338 		default:
339 			return (EINVAL);
340 		}
341 	} else {
342 		if (mm->mm_effective.mme_type != MAC_MLS_TYPE_UNDEF)
343 			return (EINVAL);
344 	}
345 
346 	if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
347 		switch (mm->mm_rangelow.mme_type) {
348 		case MAC_MLS_TYPE_LEVEL:
349 			break;
350 
351 		case MAC_MLS_TYPE_EQUAL:
352 		case MAC_MLS_TYPE_HIGH:
353 		case MAC_MLS_TYPE_LOW:
354 			if (mm->mm_rangelow.mme_level != 0 ||
355 			    !MAC_MLS_BIT_SET_EMPTY(
356 			    mm->mm_rangelow.mme_compartments))
357 				return (EINVAL);
358 			break;
359 
360 		default:
361 			return (EINVAL);
362 		}
363 
364 		switch (mm->mm_rangehigh.mme_type) {
365 		case MAC_MLS_TYPE_LEVEL:
366 			break;
367 
368 		case MAC_MLS_TYPE_EQUAL:
369 		case MAC_MLS_TYPE_HIGH:
370 		case MAC_MLS_TYPE_LOW:
371 			if (mm->mm_rangehigh.mme_level != 0 ||
372 			    !MAC_MLS_BIT_SET_EMPTY(
373 			    mm->mm_rangehigh.mme_compartments))
374 				return (EINVAL);
375 			break;
376 
377 		default:
378 			return (EINVAL);
379 		}
380 		if (!mls_dominate_element(&mm->mm_rangehigh,
381 		    &mm->mm_rangelow))
382 			return (EINVAL);
383 	} else {
384 		if (mm->mm_rangelow.mme_type != MAC_MLS_TYPE_UNDEF ||
385 		    mm->mm_rangehigh.mme_type != MAC_MLS_TYPE_UNDEF)
386 			return (EINVAL);
387 	}
388 
389 	return (0);
390 }
391 
392 static void
393 mls_set_range(struct mac_mls *mm, u_short typelow, u_short levellow,
394     u_char *compartmentslow, u_short typehigh, u_short levelhigh,
395     u_char *compartmentshigh)
396 {
397 
398 	mm->mm_rangelow.mme_type = typelow;
399 	mm->mm_rangelow.mme_level = levellow;
400 	if (compartmentslow != NULL)
401 		memcpy(mm->mm_rangelow.mme_compartments, compartmentslow,
402 		    sizeof(mm->mm_rangelow.mme_compartments));
403 	mm->mm_rangehigh.mme_type = typehigh;
404 	mm->mm_rangehigh.mme_level = levelhigh;
405 	if (compartmentshigh != NULL)
406 		memcpy(mm->mm_rangehigh.mme_compartments, compartmentshigh,
407 		    sizeof(mm->mm_rangehigh.mme_compartments));
408 	mm->mm_flags |= MAC_MLS_FLAG_RANGE;
409 }
410 
411 static void
412 mls_set_effective(struct mac_mls *mm, u_short type, u_short level,
413     u_char *compartments)
414 {
415 
416 	mm->mm_effective.mme_type = type;
417 	mm->mm_effective.mme_level = level;
418 	if (compartments != NULL)
419 		memcpy(mm->mm_effective.mme_compartments, compartments,
420 		    sizeof(mm->mm_effective.mme_compartments));
421 	mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
422 }
423 
424 static void
425 mls_copy_range(struct mac_mls *labelfrom, struct mac_mls *labelto)
426 {
427 
428 	KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
429 	    ("mls_copy_range: labelfrom not range"));
430 
431 	labelto->mm_rangelow = labelfrom->mm_rangelow;
432 	labelto->mm_rangehigh = labelfrom->mm_rangehigh;
433 	labelto->mm_flags |= MAC_MLS_FLAG_RANGE;
434 }
435 
436 static void
437 mls_copy_effective(struct mac_mls *labelfrom, struct mac_mls *labelto)
438 {
439 
440 	KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
441 	    ("mls_copy_effective: labelfrom not effective"));
442 
443 	labelto->mm_effective = labelfrom->mm_effective;
444 	labelto->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
445 }
446 
447 static void
448 mls_copy(struct mac_mls *source, struct mac_mls *dest)
449 {
450 
451 	if (source->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
452 		mls_copy_effective(source, dest);
453 	if (source->mm_flags & MAC_MLS_FLAG_RANGE)
454 		mls_copy_range(source, dest);
455 }
456 
457 /*
458  * Policy module operations.
459  */
460 static void
461 mls_init(struct mac_policy_conf *conf)
462 {
463 
464 	zone_mls = uma_zcreate("mac_mls", sizeof(struct mac_mls), NULL,
465 	    NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
466 }
467 
468 /*
469  * Label operations.
470  */
471 static void
472 mls_init_label(struct label *label)
473 {
474 
475 	SLOT_SET(label, mls_alloc(M_WAITOK));
476 }
477 
478 static int
479 mls_init_label_waitcheck(struct label *label, int flag)
480 {
481 
482 	SLOT_SET(label, mls_alloc(flag));
483 	if (SLOT(label) == NULL)
484 		return (ENOMEM);
485 
486 	return (0);
487 }
488 
489 static void
490 mls_destroy_label(struct label *label)
491 {
492 
493 	mls_free(SLOT(label));
494 	SLOT_SET(label, NULL);
495 }
496 
497 /*
498  * mls_element_to_string() accepts an sbuf and MLS element.  It converts the
499  * MLS element to a string and stores the result in the sbuf; if there isn't
500  * space in the sbuf, -1 is returned.
501  */
502 static int
503 mls_element_to_string(struct sbuf *sb, struct mac_mls_element *element)
504 {
505 	int i, first;
506 
507 	switch (element->mme_type) {
508 	case MAC_MLS_TYPE_HIGH:
509 		return (sbuf_printf(sb, "high"));
510 
511 	case MAC_MLS_TYPE_LOW:
512 		return (sbuf_printf(sb, "low"));
513 
514 	case MAC_MLS_TYPE_EQUAL:
515 		return (sbuf_printf(sb, "equal"));
516 
517 	case MAC_MLS_TYPE_LEVEL:
518 		if (sbuf_printf(sb, "%d", element->mme_level) == -1)
519 			return (-1);
520 
521 		first = 1;
522 		for (i = 1; i <= MAC_MLS_MAX_COMPARTMENTS; i++) {
523 			if (MAC_MLS_BIT_TEST(i, element->mme_compartments)) {
524 				if (first) {
525 					if (sbuf_putc(sb, ':') == -1)
526 						return (-1);
527 					if (sbuf_printf(sb, "%d", i) == -1)
528 						return (-1);
529 					first = 0;
530 				} else {
531 					if (sbuf_printf(sb, "+%d", i) == -1)
532 						return (-1);
533 				}
534 			}
535 		}
536 		return (0);
537 
538 	default:
539 		panic("mls_element_to_string: invalid type (%d)",
540 		    element->mme_type);
541 	}
542 }
543 
544 /*
545  * mls_to_string() converts an MLS label to a string, and places the results
546  * in the passed sbuf.  It returns 0 on success, or EINVAL if there isn't
547  * room in the sbuf.  Note: the sbuf will be modified even in a failure case,
548  * so the caller may need to revert the sbuf by restoring the offset if
549  * that's undesired.
550  */
551 static int
552 mls_to_string(struct sbuf *sb, struct mac_mls *mm)
553 {
554 
555 	if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
556 		if (mls_element_to_string(sb, &mm->mm_effective) == -1)
557 			return (EINVAL);
558 	}
559 
560 	if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
561 		if (sbuf_putc(sb, '(') == -1)
562 			return (EINVAL);
563 
564 		if (mls_element_to_string(sb, &mm->mm_rangelow) == -1)
565 			return (EINVAL);
566 
567 		if (sbuf_putc(sb, '-') == -1)
568 			return (EINVAL);
569 
570 		if (mls_element_to_string(sb, &mm->mm_rangehigh) == -1)
571 			return (EINVAL);
572 
573 		if (sbuf_putc(sb, ')') == -1)
574 			return (EINVAL);
575 	}
576 
577 	return (0);
578 }
579 
580 static int
581 mls_externalize_label(struct label *label, char *element_name,
582     struct sbuf *sb, int *claimed)
583 {
584 	struct mac_mls *mm;
585 
586 	if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
587 		return (0);
588 
589 	(*claimed)++;
590 
591 	mm = SLOT(label);
592 
593 	return (mls_to_string(sb, mm));
594 }
595 
596 static int
597 mls_parse_element(struct mac_mls_element *element, char *string)
598 {
599 	char *compartment, *end, *level;
600 	int value;
601 
602 	if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) {
603 		element->mme_type = MAC_MLS_TYPE_HIGH;
604 		element->mme_level = MAC_MLS_TYPE_UNDEF;
605 	} else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) {
606 		element->mme_type = MAC_MLS_TYPE_LOW;
607 		element->mme_level = MAC_MLS_TYPE_UNDEF;
608 	} else if (strcmp(string, "equal") == 0 ||
609 	    strcmp(string, "eq") == 0) {
610 		element->mme_type = MAC_MLS_TYPE_EQUAL;
611 		element->mme_level = MAC_MLS_TYPE_UNDEF;
612 	} else {
613 		element->mme_type = MAC_MLS_TYPE_LEVEL;
614 
615 		/*
616 		 * Numeric level piece of the element.
617 		 */
618 		level = strsep(&string, ":");
619 		value = strtol(level, &end, 10);
620 		if (end == level || *end != '\0')
621 			return (EINVAL);
622 		if (value < 0 || value > 65535)
623 			return (EINVAL);
624 		element->mme_level = value;
625 
626 		/*
627 		 * Optional compartment piece of the element.  If none are
628 		 * included, we assume that the label has no compartments.
629 		 */
630 		if (string == NULL)
631 			return (0);
632 		if (*string == '\0')
633 			return (0);
634 
635 		while ((compartment = strsep(&string, "+")) != NULL) {
636 			value = strtol(compartment, &end, 10);
637 			if (compartment == end || *end != '\0')
638 				return (EINVAL);
639 			if (value < 1 || value > MAC_MLS_MAX_COMPARTMENTS)
640 				return (EINVAL);
641 			MAC_MLS_BIT_SET(value, element->mme_compartments);
642 		}
643 	}
644 
645 	return (0);
646 }
647 
648 /*
649  * Note: destructively consumes the string, make a local copy before calling
650  * if that's a problem.
651  */
652 static int
653 mls_parse(struct mac_mls *mm, char *string)
654 {
655 	char *rangehigh, *rangelow, *effective;
656 	int error;
657 
658 	effective = strsep(&string, "(");
659 	if (*effective == '\0')
660 		effective = NULL;
661 
662 	if (string != NULL) {
663 		rangelow = strsep(&string, "-");
664 		if (string == NULL)
665 			return (EINVAL);
666 		rangehigh = strsep(&string, ")");
667 		if (string == NULL)
668 			return (EINVAL);
669 		if (*string != '\0')
670 			return (EINVAL);
671 	} else {
672 		rangelow = NULL;
673 		rangehigh = NULL;
674 	}
675 
676 	KASSERT((rangelow != NULL && rangehigh != NULL) ||
677 	    (rangelow == NULL && rangehigh == NULL),
678 	    ("mls_parse: range mismatch"));
679 
680 	bzero(mm, sizeof(*mm));
681 	if (effective != NULL) {
682 		error = mls_parse_element(&mm->mm_effective, effective);
683 		if (error)
684 			return (error);
685 		mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
686 	}
687 
688 	if (rangelow != NULL) {
689 		error = mls_parse_element(&mm->mm_rangelow, rangelow);
690 		if (error)
691 			return (error);
692 		error = mls_parse_element(&mm->mm_rangehigh, rangehigh);
693 		if (error)
694 			return (error);
695 		mm->mm_flags |= MAC_MLS_FLAG_RANGE;
696 	}
697 
698 	error = mls_valid(mm);
699 	if (error)
700 		return (error);
701 
702 	return (0);
703 }
704 
705 static int
706 mls_internalize_label(struct label *label, char *element_name,
707     char *element_data, int *claimed)
708 {
709 	struct mac_mls *mm, mm_temp;
710 	int error;
711 
712 	if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
713 		return (0);
714 
715 	(*claimed)++;
716 
717 	error = mls_parse(&mm_temp, element_data);
718 	if (error)
719 		return (error);
720 
721 	mm = SLOT(label);
722 	*mm = mm_temp;
723 
724 	return (0);
725 }
726 
727 static void
728 mls_copy_label(struct label *src, struct label *dest)
729 {
730 
731 	*SLOT(dest) = *SLOT(src);
732 }
733 
734 /*
735  * Object-specific entry point implementations are sorted alphabetically by
736  * object type name and then by operation.
737  */
738 static int
739 mls_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
740      struct ifnet *ifp, struct label *ifplabel)
741 {
742 	struct mac_mls *a, *b;
743 
744 	if (!mls_enabled)
745 		return (0);
746 
747 	a = SLOT(dlabel);
748 	b = SLOT(ifplabel);
749 
750 	if (mls_equal_effective(a, b))
751 		return (0);
752 	return (EACCES);
753 }
754 
755 static void
756 mls_bpfdesc_create(struct ucred *cred, struct bpf_d *d, struct label *dlabel)
757 {
758 	struct mac_mls *source, *dest;
759 
760 	source = SLOT(cred->cr_label);
761 	dest = SLOT(dlabel);
762 
763 	mls_copy_effective(source, dest);
764 }
765 
766 static void
767 mls_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
768     struct mbuf *m, struct label *mlabel)
769 {
770 	struct mac_mls *source, *dest;
771 
772 	source = SLOT(dlabel);
773 	dest = SLOT(mlabel);
774 
775 	mls_copy_effective(source, dest);
776 }
777 
778 static void
779 mls_cred_associate_nfsd(struct ucred *cred)
780 {
781 	struct mac_mls *label;
782 
783 	label = SLOT(cred->cr_label);
784 	mls_set_effective(label, MAC_MLS_TYPE_LOW, 0, NULL);
785 	mls_set_range(label, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
786 	    NULL);
787 }
788 
789 static int
790 mls_cred_check_relabel(struct ucred *cred, struct label *newlabel)
791 {
792 	struct mac_mls *subj, *new;
793 	int error;
794 
795 	subj = SLOT(cred->cr_label);
796 	new = SLOT(newlabel);
797 
798 	/*
799 	 * If there is an MLS label update for the credential, it may be an
800 	 * update of effective, range, or both.
801 	 */
802 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
803 	if (error)
804 		return (error);
805 
806 	/*
807 	 * If the MLS label is to be changed, authorize as appropriate.
808 	 */
809 	if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
810 		/*
811 		 * If the change request modifies both the MLS label
812 		 * effective and range, check that the new effective will be
813 		 * in the new range.
814 		 */
815 		if ((new->mm_flags & MAC_MLS_FLAGS_BOTH) ==
816 		    MAC_MLS_FLAGS_BOTH && !mls_effective_in_range(new, new))
817 			return (EINVAL);
818 
819 		/*
820 		 * To change the MLS effective label on a credential, the new
821 		 * effective label must be in the current range.
822 		 */
823 		if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE &&
824 		    !mls_effective_in_range(new, subj))
825 			return (EPERM);
826 
827 		/*
828 		 * To change the MLS range label on a credential, the new
829 		 * range must be in the current range.
830 		 */
831 		if (new->mm_flags & MAC_MLS_FLAG_RANGE &&
832 		    !mls_range_in_range(new, subj))
833 			return (EPERM);
834 
835 		/*
836 		 * To have EQUAL in any component of the new credential MLS
837 		 * label, the subject must already have EQUAL in their label.
838 		 */
839 		if (mls_contains_equal(new)) {
840 			error = mls_subject_privileged(subj);
841 			if (error)
842 				return (error);
843 		}
844 	}
845 
846 	return (0);
847 }
848 
849 static int
850 mls_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
851 {
852 	struct mac_mls *subj, *obj;
853 
854 	if (!mls_enabled)
855 		return (0);
856 
857 	subj = SLOT(cr1->cr_label);
858 	obj = SLOT(cr2->cr_label);
859 
860 	/* XXX: range */
861 	if (!mls_dominate_effective(subj, obj))
862 		return (ESRCH);
863 
864 	return (0);
865 }
866 
867 static void
868 mls_cred_create_init(struct ucred *cred)
869 {
870 	struct mac_mls *dest;
871 
872 	dest = SLOT(cred->cr_label);
873 
874 	mls_set_effective(dest, MAC_MLS_TYPE_LOW, 0, NULL);
875 	mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
876 	    NULL);
877 }
878 
879 static void
880 mls_cred_create_swapper(struct ucred *cred)
881 {
882 	struct mac_mls *dest;
883 
884 	dest = SLOT(cred->cr_label);
885 
886 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
887 	mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
888 	    NULL);
889 }
890 
891 static void
892 mls_cred_relabel(struct ucred *cred, struct label *newlabel)
893 {
894 	struct mac_mls *source, *dest;
895 
896 	source = SLOT(newlabel);
897 	dest = SLOT(cred->cr_label);
898 
899 	mls_copy(source, dest);
900 }
901 
902 static void
903 mls_devfs_create_device(struct ucred *cred, struct mount *mp,
904     struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
905 {
906 	struct mac_mls *mm;
907 	const char *dn;
908 	int mls_type;
909 
910 	mm = SLOT(delabel);
911 	dn = devtoname(dev);
912 	if (strcmp(dn, "null") == 0 ||
913 	    strcmp(dn, "zero") == 0 ||
914 	    strcmp(dn, "random") == 0 ||
915 	    strncmp(dn, "fd/", strlen("fd/")) == 0)
916 		mls_type = MAC_MLS_TYPE_EQUAL;
917 	else if (strcmp(dn, "kmem") == 0 ||
918 	    strcmp(dn, "mem") == 0)
919 		mls_type = MAC_MLS_TYPE_HIGH;
920 	else if (ptys_equal &&
921 	    (strncmp(dn, "ttyp", strlen("ttyp")) == 0 ||
922 	    strncmp(dn, "pts/", strlen("pts/")) == 0 ||
923 	    strncmp(dn, "ptyp", strlen("ptyp")) == 0))
924 		mls_type = MAC_MLS_TYPE_EQUAL;
925 	else
926 		mls_type = MAC_MLS_TYPE_LOW;
927 	mls_set_effective(mm, mls_type, 0, NULL);
928 }
929 
930 static void
931 mls_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
932     struct devfs_dirent *de, struct label *delabel)
933 {
934 	struct mac_mls *mm;
935 
936 	mm = SLOT(delabel);
937 	mls_set_effective(mm, MAC_MLS_TYPE_LOW, 0, NULL);
938 }
939 
940 static void
941 mls_devfs_create_symlink(struct ucred *cred, struct mount *mp,
942     struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
943     struct label *delabel)
944 {
945 	struct mac_mls *source, *dest;
946 
947 	source = SLOT(cred->cr_label);
948 	dest = SLOT(delabel);
949 
950 	mls_copy_effective(source, dest);
951 }
952 
953 static void
954 mls_devfs_update(struct mount *mp, struct devfs_dirent *de,
955     struct label *delabel, struct vnode *vp, struct label *vplabel)
956 {
957 	struct mac_mls *source, *dest;
958 
959 	source = SLOT(vplabel);
960 	dest = SLOT(delabel);
961 
962 	mls_copy_effective(source, dest);
963 }
964 
965 static void
966 mls_devfs_vnode_associate(struct mount *mp, struct label *mplabel,
967     struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
968     struct label *vplabel)
969 {
970 	struct mac_mls *source, *dest;
971 
972 	source = SLOT(delabel);
973 	dest = SLOT(vplabel);
974 
975 	mls_copy_effective(source, dest);
976 }
977 
978 static int
979 mls_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
980     struct label *ifplabel, struct label *newlabel)
981 {
982 	struct mac_mls *subj, *new;
983 	int error;
984 
985 	subj = SLOT(cred->cr_label);
986 	new = SLOT(newlabel);
987 
988 	/*
989 	 * If there is an MLS label update for the interface, it may be an
990 	 * update of effective, range, or both.
991 	 */
992 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
993 	if (error)
994 		return (error);
995 
996 	/*
997 	 * Relabeling network interfaces requires MLS privilege.
998 	 */
999 	return (mls_subject_privileged(subj));
1000 }
1001 
1002 static int
1003 mls_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
1004     struct mbuf *m, struct label *mlabel)
1005 {
1006 	struct mac_mls *p, *i;
1007 
1008 	if (!mls_enabled)
1009 		return (0);
1010 
1011 	p = SLOT(mlabel);
1012 	i = SLOT(ifplabel);
1013 
1014 	return (mls_effective_in_range(p, i) ? 0 : EACCES);
1015 }
1016 
1017 static void
1018 mls_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
1019 {
1020 	struct mac_mls *dest;
1021 	int type;
1022 
1023 	dest = SLOT(ifplabel);
1024 
1025 	if (if_gettype(ifp) == IFT_LOOP)
1026 		type = MAC_MLS_TYPE_EQUAL;
1027 	else
1028 		type = MAC_MLS_TYPE_LOW;
1029 
1030 	mls_set_effective(dest, type, 0, NULL);
1031 	mls_set_range(dest, type, 0, NULL, type, 0, NULL);
1032 }
1033 
1034 static void
1035 mls_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
1036     struct mbuf *m, struct label *mlabel)
1037 {
1038 	struct mac_mls *source, *dest;
1039 
1040 	source = SLOT(ifplabel);
1041 	dest = SLOT(mlabel);
1042 
1043 	mls_copy_effective(source, dest);
1044 }
1045 
1046 static void
1047 mls_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
1048     struct label *ifplabel, struct label *newlabel)
1049 {
1050 	struct mac_mls *source, *dest;
1051 
1052 	source = SLOT(newlabel);
1053 	dest = SLOT(ifplabel);
1054 
1055 	mls_copy(source, dest);
1056 }
1057 
1058 static int
1059 mls_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
1060     struct mbuf *m, struct label *mlabel)
1061 {
1062 	struct mac_mls *p, *i;
1063 
1064 	if (!mls_enabled)
1065 		return (0);
1066 
1067 	p = SLOT(mlabel);
1068 	i = SLOT(inplabel);
1069 
1070 	return (mls_equal_effective(p, i) ? 0 : EACCES);
1071 }
1072 
1073 static int
1074 mls_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
1075     struct label *inplabel)
1076 {
1077 	struct mac_mls *subj, *obj;
1078 
1079 	if (!mls_enabled)
1080 		return (0);
1081 
1082 	subj = SLOT(cred->cr_label);
1083 	obj = SLOT(inplabel);
1084 
1085 	if (!mls_dominate_effective(subj, obj))
1086 		return (ENOENT);
1087 
1088 	return (0);
1089 }
1090 
1091 static void
1092 mls_inpcb_create(struct socket *so, struct label *solabel, struct inpcb *inp,
1093     struct label *inplabel)
1094 {
1095 	struct mac_mls *source, *dest;
1096 
1097 	source = SLOT(solabel);
1098 	dest = SLOT(inplabel);
1099 
1100 	mls_copy_effective(source, dest);
1101 }
1102 
1103 static void
1104 mls_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
1105     struct mbuf *m, struct label *mlabel)
1106 {
1107 	struct mac_mls *source, *dest;
1108 
1109 	source = SLOT(inplabel);
1110 	dest = SLOT(mlabel);
1111 
1112 	mls_copy_effective(source, dest);
1113 }
1114 
1115 static void
1116 mls_inpcb_sosetlabel(struct socket *so, struct label *solabel,
1117     struct inpcb *inp, struct label *inplabel)
1118 {
1119 	struct mac_mls *source, *dest;
1120 
1121 	SOCK_LOCK_ASSERT(so);
1122 
1123 	source = SLOT(solabel);
1124 	dest = SLOT(inplabel);
1125 
1126 	mls_copy(source, dest);
1127 }
1128 
1129 static void
1130 mls_ip6q_create(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1131     struct label *q6label)
1132 {
1133 	struct mac_mls *source, *dest;
1134 
1135 	source = SLOT(mlabel);
1136 	dest = SLOT(q6label);
1137 
1138 	mls_copy_effective(source, dest);
1139 }
1140 
1141 static int
1142 mls_ip6q_match(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1143     struct label *q6label)
1144 {
1145 	struct mac_mls *a, *b;
1146 
1147 	a = SLOT(q6label);
1148 	b = SLOT(mlabel);
1149 
1150 	return (mls_equal_effective(a, b));
1151 }
1152 
1153 static void
1154 mls_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
1155     struct label *mlabel)
1156 {
1157 	struct mac_mls *source, *dest;
1158 
1159 	source = SLOT(q6label);
1160 	dest = SLOT(mlabel);
1161 
1162 	/* Just use the head, since we require them all to match. */
1163 	mls_copy_effective(source, dest);
1164 }
1165 
1166 static void
1167 mls_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1168     struct label *q6label)
1169 {
1170 
1171 	/* NOOP: we only accept matching labels, so no need to update */
1172 }
1173 
1174 static void
1175 mls_ipq_create(struct mbuf *m, struct label *mlabel, struct ipq *q,
1176     struct label *qlabel)
1177 {
1178 	struct mac_mls *source, *dest;
1179 
1180 	source = SLOT(mlabel);
1181 	dest = SLOT(qlabel);
1182 
1183 	mls_copy_effective(source, dest);
1184 }
1185 
1186 static int
1187 mls_ipq_match(struct mbuf *m, struct label *mlabel, struct ipq *q,
1188     struct label *qlabel)
1189 {
1190 	struct mac_mls *a, *b;
1191 
1192 	a = SLOT(qlabel);
1193 	b = SLOT(mlabel);
1194 
1195 	return (mls_equal_effective(a, b));
1196 }
1197 
1198 static void
1199 mls_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
1200     struct label *mlabel)
1201 {
1202 	struct mac_mls *source, *dest;
1203 
1204 	source = SLOT(qlabel);
1205 	dest = SLOT(mlabel);
1206 
1207 	/* Just use the head, since we require them all to match. */
1208 	mls_copy_effective(source, dest);
1209 }
1210 
1211 static void
1212 mls_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
1213     struct label *qlabel)
1214 {
1215 
1216 	/* NOOP: we only accept matching labels, so no need to update */
1217 }
1218 
1219 static int
1220 mls_mount_check_stat(struct ucred *cred, struct mount *mp,
1221     struct label *mntlabel)
1222 {
1223 	struct mac_mls *subj, *obj;
1224 
1225 	if (!mls_enabled)
1226 		return (0);
1227 
1228 	subj = SLOT(cred->cr_label);
1229 	obj = SLOT(mntlabel);
1230 
1231 	if (!mls_dominate_effective(subj, obj))
1232 		return (EACCES);
1233 
1234 	return (0);
1235 }
1236 
1237 static void
1238 mls_mount_create(struct ucred *cred, struct mount *mp, struct label *mplabel)
1239 {
1240 	struct mac_mls *source, *dest;
1241 
1242 	source = SLOT(cred->cr_label);
1243 	dest = SLOT(mplabel);
1244 
1245 	mls_copy_effective(source, dest);
1246 }
1247 
1248 static void
1249 mls_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
1250     struct mbuf *m, struct label *mlabel)
1251 {
1252 	struct mac_mls *dest;
1253 
1254 	dest = SLOT(mlabel);
1255 
1256 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1257 }
1258 
1259 static void
1260 mls_netinet_firewall_reply(struct mbuf *mrecv, struct label *mrecvlabel,
1261     struct mbuf *msend, struct label *msendlabel)
1262 {
1263 	struct mac_mls *source, *dest;
1264 
1265 	source = SLOT(mrecvlabel);
1266 	dest = SLOT(msendlabel);
1267 
1268 	mls_copy_effective(source, dest);
1269 }
1270 
1271 static void
1272 mls_netinet_firewall_send(struct mbuf *m, struct label *mlabel)
1273 {
1274 	struct mac_mls *dest;
1275 
1276 	dest = SLOT(mlabel);
1277 
1278 	/* XXX: where is the label for the firewall really coming from? */
1279 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1280 }
1281 
1282 static void
1283 mls_netinet_fragment(struct mbuf *m, struct label *mlabel, struct mbuf *frag,
1284     struct label *fraglabel)
1285 {
1286 	struct mac_mls *source, *dest;
1287 
1288 	source = SLOT(mlabel);
1289 	dest = SLOT(fraglabel);
1290 
1291 	mls_copy_effective(source, dest);
1292 }
1293 
1294 static void
1295 mls_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
1296     struct mbuf *msend, struct label *msendlabel)
1297 {
1298 	struct mac_mls *source, *dest;
1299 
1300 	source = SLOT(mrecvlabel);
1301 	dest = SLOT(msendlabel);
1302 
1303 	mls_copy_effective(source, dest);
1304 }
1305 
1306 static void
1307 mls_netinet_igmp_send(struct ifnet *ifp, struct label *ifplabel,
1308     struct mbuf *m, struct label *mlabel)
1309 {
1310 	struct mac_mls *dest;
1311 
1312 	dest = SLOT(mlabel);
1313 
1314 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1315 }
1316 
1317 static void
1318 mls_netinet6_nd6_send(struct ifnet *ifp, struct label *ifplabel,
1319     struct mbuf *m, struct label *mlabel)
1320 {
1321 	struct mac_mls *dest;
1322 
1323 	dest = SLOT(mlabel);
1324 
1325 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1326 }
1327 
1328 static int
1329 mls_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
1330     struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
1331 {
1332 
1333 	if (!mls_enabled)
1334 		return (0);
1335 
1336 	/* XXX: This will be implemented soon... */
1337 
1338 	return (0);
1339 }
1340 
1341 static int
1342 mls_pipe_check_poll(struct ucred *cred, struct pipepair *pp,
1343     struct label *pplabel)
1344 {
1345 	struct mac_mls *subj, *obj;
1346 
1347 	if (!mls_enabled)
1348 		return (0);
1349 
1350 	subj = SLOT(cred->cr_label);
1351 	obj = SLOT(pplabel);
1352 
1353 	if (!mls_dominate_effective(subj, obj))
1354 		return (EACCES);
1355 
1356 	return (0);
1357 }
1358 
1359 static int
1360 mls_pipe_check_read(struct ucred *cred, struct pipepair *pp,
1361     struct label *pplabel)
1362 {
1363 	struct mac_mls *subj, *obj;
1364 
1365 	if (!mls_enabled)
1366 		return (0);
1367 
1368 	subj = SLOT(cred->cr_label);
1369 	obj = SLOT(pplabel);
1370 
1371 	if (!mls_dominate_effective(subj, obj))
1372 		return (EACCES);
1373 
1374 	return (0);
1375 }
1376 
1377 static int
1378 mls_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
1379     struct label *pplabel, struct label *newlabel)
1380 {
1381 	struct mac_mls *subj, *obj, *new;
1382 	int error;
1383 
1384 	new = SLOT(newlabel);
1385 	subj = SLOT(cred->cr_label);
1386 	obj = SLOT(pplabel);
1387 
1388 	/*
1389 	 * If there is an MLS label update for a pipe, it must be a effective
1390 	 * update.
1391 	 */
1392 	error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
1393 	if (error)
1394 		return (error);
1395 
1396 	/*
1397 	 * To perform a relabel of a pipe (MLS label or not), MLS must
1398 	 * authorize the relabel.
1399 	 */
1400 	if (!mls_effective_in_range(obj, subj))
1401 		return (EPERM);
1402 
1403 	/*
1404 	 * If the MLS label is to be changed, authorize as appropriate.
1405 	 */
1406 	if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
1407 		/*
1408 		 * To change the MLS label on a pipe, the new pipe label must
1409 		 * be in the subject range.
1410 		 */
1411 		if (!mls_effective_in_range(new, subj))
1412 			return (EPERM);
1413 
1414 		/*
1415 		 * To change the MLS label on a pipe to be EQUAL, the subject
1416 		 * must have appropriate privilege.
1417 		 */
1418 		if (mls_contains_equal(new)) {
1419 			error = mls_subject_privileged(subj);
1420 			if (error)
1421 				return (error);
1422 		}
1423 	}
1424 
1425 	return (0);
1426 }
1427 
1428 static int
1429 mls_pipe_check_stat(struct ucred *cred, struct pipepair *pp,
1430     struct label *pplabel)
1431 {
1432 	struct mac_mls *subj, *obj;
1433 
1434 	if (!mls_enabled)
1435 		return (0);
1436 
1437 	subj = SLOT(cred->cr_label);
1438 	obj = SLOT(pplabel);
1439 
1440 	if (!mls_dominate_effective(subj, obj))
1441 		return (EACCES);
1442 
1443 	return (0);
1444 }
1445 
1446 static int
1447 mls_pipe_check_write(struct ucred *cred, struct pipepair *pp,
1448     struct label *pplabel)
1449 {
1450 	struct mac_mls *subj, *obj;
1451 
1452 	if (!mls_enabled)
1453 		return (0);
1454 
1455 	subj = SLOT(cred->cr_label);
1456 	obj = SLOT(pplabel);
1457 
1458 	if (!mls_dominate_effective(obj, subj))
1459 		return (EACCES);
1460 
1461 	return (0);
1462 }
1463 
1464 static void
1465 mls_pipe_create(struct ucred *cred, struct pipepair *pp,
1466     struct label *pplabel)
1467 {
1468 	struct mac_mls *source, *dest;
1469 
1470 	source = SLOT(cred->cr_label);
1471 	dest = SLOT(pplabel);
1472 
1473 	mls_copy_effective(source, dest);
1474 }
1475 
1476 static void
1477 mls_pipe_relabel(struct ucred *cred, struct pipepair *pp,
1478     struct label *pplabel, struct label *newlabel)
1479 {
1480 	struct mac_mls *source, *dest;
1481 
1482 	source = SLOT(newlabel);
1483 	dest = SLOT(pplabel);
1484 
1485 	mls_copy(source, dest);
1486 }
1487 
1488 static int
1489 mls_posixsem_check_openunlink(struct ucred *cred, struct ksem *ks,
1490     struct label *kslabel)
1491 {
1492 	struct mac_mls *subj, *obj;
1493 
1494 	if (!mls_enabled)
1495 		return (0);
1496 
1497 	subj = SLOT(cred->cr_label);
1498 	obj = SLOT(kslabel);
1499 
1500 	if (!mls_dominate_effective(obj, subj))
1501 		return (EACCES);
1502 
1503 	return (0);
1504 }
1505 
1506 static int
1507 mls_posixsem_check_rdonly(struct ucred *active_cred, struct ucred *file_cred,
1508     struct ksem *ks, struct label *kslabel)
1509 {
1510 	struct mac_mls *subj, *obj;
1511 
1512 	if (!mls_enabled)
1513 		return (0);
1514 
1515 	subj = SLOT(active_cred->cr_label);
1516 	obj = SLOT(kslabel);
1517 
1518 	if (!mls_dominate_effective(subj, obj))
1519 		return (EACCES);
1520 
1521 	return (0);
1522 }
1523 
1524 static int
1525 mls_posixsem_check_setmode(struct ucred *cred, struct ksem *ks,
1526     struct label *shmlabel, mode_t mode)
1527 {
1528 	struct mac_mls *subj, *obj;
1529 
1530 	if (!mls_enabled)
1531 		return (0);
1532 
1533 	subj = SLOT(cred->cr_label);
1534 	obj = SLOT(shmlabel);
1535 
1536 	if (!mls_dominate_effective(obj, subj))
1537 		return (EACCES);
1538 
1539 	return (0);
1540 }
1541 
1542 static int
1543 mls_posixsem_check_setowner(struct ucred *cred, struct ksem *ks,
1544     struct label *shmlabel, uid_t uid, gid_t gid)
1545 {
1546 	struct mac_mls *subj, *obj;
1547 
1548 	if (!mls_enabled)
1549 		return (0);
1550 
1551 	subj = SLOT(cred->cr_label);
1552 	obj = SLOT(shmlabel);
1553 
1554 	if (!mls_dominate_effective(obj, subj))
1555 		return (EACCES);
1556 
1557 	return (0);
1558 }
1559 
1560 static int
1561 mls_posixsem_check_write(struct ucred *active_cred, struct ucred *file_cred,
1562     struct ksem *ks, struct label *kslabel)
1563 {
1564 	struct mac_mls *subj, *obj;
1565 
1566 	if (!mls_enabled)
1567 		return (0);
1568 
1569 	subj = SLOT(active_cred->cr_label);
1570 	obj = SLOT(kslabel);
1571 
1572 	if (!mls_dominate_effective(obj, subj))
1573 		return (EACCES);
1574 
1575 	return (0);
1576 }
1577 
1578 static void
1579 mls_posixsem_create(struct ucred *cred, struct ksem *ks,
1580     struct label *kslabel)
1581 {
1582 	struct mac_mls *source, *dest;
1583 
1584 	source = SLOT(cred->cr_label);
1585 	dest = SLOT(kslabel);
1586 
1587 	mls_copy_effective(source, dest);
1588 }
1589 
1590 static int
1591 mls_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd,
1592     struct label *shmlabel, int prot, int flags)
1593 {
1594 	struct mac_mls *subj, *obj;
1595 
1596 	if (!mls_enabled)
1597 		return (0);
1598 
1599 	subj = SLOT(cred->cr_label);
1600 	obj = SLOT(shmlabel);
1601 
1602 	if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
1603 		if (!mls_dominate_effective(subj, obj))
1604 			return (EACCES);
1605 	}
1606 	if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
1607 		if (!mls_dominate_effective(obj, subj))
1608 			return (EACCES);
1609 	}
1610 
1611 	return (0);
1612 }
1613 
1614 static int
1615 mls_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd,
1616     struct label *shmlabel, accmode_t accmode)
1617 {
1618 	struct mac_mls *subj, *obj;
1619 
1620 	if (!mls_enabled)
1621 		return (0);
1622 
1623 	subj = SLOT(cred->cr_label);
1624 	obj = SLOT(shmlabel);
1625 
1626 	if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) {
1627 		if (!mls_dominate_effective(subj, obj))
1628 			return (EACCES);
1629 	}
1630 	if (accmode & VMODIFY_PERMS) {
1631 		if (!mls_dominate_effective(obj, subj))
1632 			return (EACCES);
1633 	}
1634 
1635 	return (0);
1636 }
1637 
1638 static int
1639 mls_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred,
1640     struct shmfd *shm, struct label *shmlabel)
1641 {
1642 	struct mac_mls *subj, *obj;
1643 
1644 	if (!mls_enabled || !revocation_enabled)
1645 		return (0);
1646 
1647 	subj = SLOT(active_cred->cr_label);
1648 	obj = SLOT(shmlabel);
1649 
1650 	if (!mls_dominate_effective(subj, obj))
1651 		return (EACCES);
1652 
1653 	return (0);
1654 }
1655 
1656 static int
1657 mls_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
1658     struct label *shmlabel, mode_t mode)
1659 {
1660 	struct mac_mls *subj, *obj;
1661 
1662 	if (!mls_enabled)
1663 		return (0);
1664 
1665 	subj = SLOT(cred->cr_label);
1666 	obj = SLOT(shmlabel);
1667 
1668 	if (!mls_dominate_effective(obj, subj))
1669 		return (EACCES);
1670 
1671 	return (0);
1672 }
1673 
1674 static int
1675 mls_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd,
1676     struct label *shmlabel, uid_t uid, gid_t gid)
1677 {
1678 	struct mac_mls *subj, *obj;
1679 
1680 	if (!mls_enabled)
1681 		return (0);
1682 
1683 	subj = SLOT(cred->cr_label);
1684 	obj = SLOT(shmlabel);
1685 
1686 	if (!mls_dominate_effective(obj, subj))
1687 		return (EACCES);
1688 
1689 	return (0);
1690 }
1691 
1692 static int
1693 mls_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred,
1694     struct shmfd *shmfd, struct label *shmlabel)
1695 {
1696 	struct mac_mls *subj, *obj;
1697 
1698 	if (!mls_enabled)
1699 		return (0);
1700 
1701 	subj = SLOT(active_cred->cr_label);
1702 	obj = SLOT(shmlabel);
1703 
1704 	if (!mls_dominate_effective(subj, obj))
1705 		return (EACCES);
1706 
1707 	return (0);
1708 }
1709 
1710 static int
1711 mls_posixshm_check_truncate(struct ucred *active_cred,
1712     struct ucred *file_cred, struct shmfd *shmfd, struct label *shmlabel)
1713 {
1714 	struct mac_mls *subj, *obj;
1715 
1716 	if (!mls_enabled)
1717 		return (0);
1718 
1719 	subj = SLOT(active_cred->cr_label);
1720 	obj = SLOT(shmlabel);
1721 
1722 	if (!mls_dominate_effective(obj, subj))
1723 		return (EACCES);
1724 
1725 	return (0);
1726 }
1727 
1728 static int
1729 mls_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd,
1730     struct label *shmlabel)
1731 {
1732 	struct mac_mls *subj, *obj;
1733 
1734 	if (!mls_enabled)
1735 		return (0);
1736 
1737 	subj = SLOT(cred->cr_label);
1738 	obj = SLOT(shmlabel);
1739 
1740 	if (!mls_dominate_effective(obj, subj))
1741 		return (EACCES);
1742 
1743 	return (0);
1744 }
1745 
1746 static int
1747 mls_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred,
1748     struct shmfd *shm, struct label *shmlabel)
1749 {
1750 	struct mac_mls *subj, *obj;
1751 
1752 	if (!mls_enabled || !revocation_enabled)
1753 		return (0);
1754 
1755 	subj = SLOT(active_cred->cr_label);
1756 	obj = SLOT(shmlabel);
1757 
1758 	if (!mls_dominate_effective(subj, obj))
1759 		return (EACCES);
1760 
1761 	return (0);
1762 }
1763 
1764 static void
1765 mls_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
1766     struct label *shmlabel)
1767 {
1768 	struct mac_mls *source, *dest;
1769 
1770 	source = SLOT(cred->cr_label);
1771 	dest = SLOT(shmlabel);
1772 
1773 	mls_copy_effective(source, dest);
1774 }
1775 
1776 static int
1777 mls_proc_check_debug(struct ucred *cred, struct proc *p)
1778 {
1779 	struct mac_mls *subj, *obj;
1780 
1781 	if (!mls_enabled)
1782 		return (0);
1783 
1784 	subj = SLOT(cred->cr_label);
1785 	obj = SLOT(p->p_ucred->cr_label);
1786 
1787 	/* XXX: range checks */
1788 	if (!mls_dominate_effective(subj, obj))
1789 		return (ESRCH);
1790 	if (!mls_dominate_effective(obj, subj))
1791 		return (EACCES);
1792 
1793 	return (0);
1794 }
1795 
1796 static int
1797 mls_proc_check_sched(struct ucred *cred, struct proc *p)
1798 {
1799 	struct mac_mls *subj, *obj;
1800 
1801 	if (!mls_enabled)
1802 		return (0);
1803 
1804 	subj = SLOT(cred->cr_label);
1805 	obj = SLOT(p->p_ucred->cr_label);
1806 
1807 	/* XXX: range checks */
1808 	if (!mls_dominate_effective(subj, obj))
1809 		return (ESRCH);
1810 	if (!mls_dominate_effective(obj, subj))
1811 		return (EACCES);
1812 
1813 	return (0);
1814 }
1815 
1816 static int
1817 mls_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
1818 {
1819 	struct mac_mls *subj, *obj;
1820 
1821 	if (!mls_enabled)
1822 		return (0);
1823 
1824 	subj = SLOT(cred->cr_label);
1825 	obj = SLOT(p->p_ucred->cr_label);
1826 
1827 	/* XXX: range checks */
1828 	if (!mls_dominate_effective(subj, obj))
1829 		return (ESRCH);
1830 	if (!mls_dominate_effective(obj, subj))
1831 		return (EACCES);
1832 
1833 	return (0);
1834 }
1835 
1836 static int
1837 mls_socket_check_deliver(struct socket *so, struct label *solabel,
1838     struct mbuf *m, struct label *mlabel)
1839 {
1840 	struct mac_mls *p, *s;
1841 	int error;
1842 
1843 	if (!mls_enabled)
1844 		return (0);
1845 
1846 	p = SLOT(mlabel);
1847 	s = SLOT(solabel);
1848 
1849 	SOCK_LOCK(so);
1850 	error = mls_equal_effective(p, s) ? 0 : EACCES;
1851 	SOCK_UNLOCK(so);
1852 
1853 	return (error);
1854 }
1855 
1856 static int
1857 mls_socket_check_relabel(struct ucred *cred, struct socket *so,
1858     struct label *solabel, struct label *newlabel)
1859 {
1860 	struct mac_mls *subj, *obj, *new;
1861 	int error;
1862 
1863 	SOCK_LOCK_ASSERT(so);
1864 
1865 	new = SLOT(newlabel);
1866 	subj = SLOT(cred->cr_label);
1867 	obj = SLOT(solabel);
1868 
1869 	/*
1870 	 * If there is an MLS label update for the socket, it may be an
1871 	 * update of effective.
1872 	 */
1873 	error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
1874 	if (error)
1875 		return (error);
1876 
1877 	/*
1878 	 * To relabel a socket, the old socket effective must be in the
1879 	 * subject range.
1880 	 */
1881 	if (!mls_effective_in_range(obj, subj))
1882 		return (EPERM);
1883 
1884 	/*
1885 	 * If the MLS label is to be changed, authorize as appropriate.
1886 	 */
1887 	if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
1888 		/*
1889 		 * To relabel a socket, the new socket effective must be in
1890 		 * the subject range.
1891 		 */
1892 		if (!mls_effective_in_range(new, subj))
1893 			return (EPERM);
1894 
1895 		/*
1896 		 * To change the MLS label on the socket to contain EQUAL,
1897 		 * the subject must have appropriate privilege.
1898 		 */
1899 		if (mls_contains_equal(new)) {
1900 			error = mls_subject_privileged(subj);
1901 			if (error)
1902 				return (error);
1903 		}
1904 	}
1905 
1906 	return (0);
1907 }
1908 
1909 static int
1910 mls_socket_check_visible(struct ucred *cred, struct socket *so,
1911     struct label *solabel)
1912 {
1913 	struct mac_mls *subj, *obj;
1914 
1915 	if (!mls_enabled)
1916 		return (0);
1917 
1918 	subj = SLOT(cred->cr_label);
1919 	obj = SLOT(solabel);
1920 
1921 	SOCK_LOCK(so);
1922 	if (!mls_dominate_effective(subj, obj)) {
1923 		SOCK_UNLOCK(so);
1924 		return (ENOENT);
1925 	}
1926 	SOCK_UNLOCK(so);
1927 
1928 	return (0);
1929 }
1930 
1931 static void
1932 mls_socket_create(struct ucred *cred, struct socket *so,
1933     struct label *solabel)
1934 {
1935 	struct mac_mls *source, *dest;
1936 
1937 	source = SLOT(cred->cr_label);
1938 	dest = SLOT(solabel);
1939 
1940 	mls_copy_effective(source, dest);
1941 }
1942 
1943 static void
1944 mls_socket_create_mbuf(struct socket *so, struct label *solabel,
1945     struct mbuf *m, struct label *mlabel)
1946 {
1947 	struct mac_mls *source, *dest;
1948 
1949 	source = SLOT(solabel);
1950 	dest = SLOT(mlabel);
1951 
1952 	SOCK_LOCK(so);
1953 	mls_copy_effective(source, dest);
1954 	SOCK_UNLOCK(so);
1955 }
1956 
1957 static void
1958 mls_socket_newconn(struct socket *oldso, struct label *oldsolabel,
1959     struct socket *newso, struct label *newsolabel)
1960 {
1961 	struct mac_mls source, *dest;
1962 
1963 	SOCK_LOCK(oldso);
1964 	source = *SLOT(oldsolabel);
1965 	SOCK_UNLOCK(oldso);
1966 
1967 	dest = SLOT(newsolabel);
1968 
1969 	SOCK_LOCK(newso);
1970 	mls_copy_effective(&source, dest);
1971 	SOCK_UNLOCK(newso);
1972 }
1973 
1974 static void
1975 mls_socket_relabel(struct ucred *cred, struct socket *so,
1976     struct label *solabel, struct label *newlabel)
1977 {
1978 	struct mac_mls *source, *dest;
1979 
1980 	SOCK_LOCK_ASSERT(so);
1981 
1982 	source = SLOT(newlabel);
1983 	dest = SLOT(solabel);
1984 
1985 	mls_copy(source, dest);
1986 }
1987 
1988 static void
1989 mls_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
1990     struct socket *so, struct label *sopeerlabel)
1991 {
1992 	struct mac_mls *source, *dest;
1993 
1994 	source = SLOT(mlabel);
1995 	dest = SLOT(sopeerlabel);
1996 
1997 	SOCK_LOCK(so);
1998 	mls_copy_effective(source, dest);
1999 	SOCK_UNLOCK(so);
2000 }
2001 
2002 static void
2003 mls_socketpeer_set_from_socket(struct socket *oldso,
2004     struct label *oldsolabel, struct socket *newso,
2005     struct label *newsopeerlabel)
2006 {
2007 	struct mac_mls source, *dest;
2008 
2009 	SOCK_LOCK(oldso);
2010 	source = *SLOT(oldsolabel);
2011 	SOCK_UNLOCK(oldso);
2012 
2013 	dest = SLOT(newsopeerlabel);
2014 
2015 	SOCK_LOCK(newso);
2016 	mls_copy_effective(&source, dest);
2017 	SOCK_UNLOCK(newso);
2018 }
2019 
2020 static void
2021 mls_syncache_create(struct label *label, struct inpcb *inp)
2022 {
2023 	struct mac_mls *source, *dest;
2024 
2025 	source = SLOT(inp->inp_label);
2026 	dest = SLOT(label);
2027 
2028 	mls_copy_effective(source, dest);
2029 }
2030 
2031 static void
2032 mls_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
2033     struct label *mlabel)
2034 {
2035 	struct mac_mls *source, *dest;
2036 
2037 	source = SLOT(sc_label);
2038 	dest = SLOT(mlabel);
2039 
2040 	mls_copy_effective(source, dest);
2041 }
2042 
2043 static int
2044 mls_system_check_acct(struct ucred *cred, struct vnode *vp,
2045     struct label *vplabel)
2046 {
2047 	struct mac_mls *subj, *obj;
2048 
2049 	if (!mls_enabled)
2050 		return (0);
2051 
2052 	if (vplabel == NULL)
2053 		return (0);
2054 
2055 	subj = SLOT(cred->cr_label);
2056 	obj = SLOT(vplabel);
2057 
2058 	if (!mls_dominate_effective(obj, subj) ||
2059 	    !mls_dominate_effective(subj, obj))
2060 		return (EACCES);
2061 
2062 	return (0);
2063 }
2064 
2065 static int
2066 mls_system_check_auditctl(struct ucred *cred, struct vnode *vp,
2067     struct label *vplabel)
2068 {
2069 	struct mac_mls *subj, *obj;
2070 
2071 	if (!mls_enabled)
2072 		return (0);
2073 
2074 	subj = SLOT(cred->cr_label);
2075 	obj = SLOT(vplabel);
2076 
2077 	if (!mls_dominate_effective(obj, subj) ||
2078 	    !mls_dominate_effective(subj, obj))
2079 		return (EACCES);
2080 
2081 	return (0);
2082 }
2083 
2084 static int
2085 mls_system_check_swapon(struct ucred *cred, struct vnode *vp,
2086     struct label *vplabel)
2087 {
2088 	struct mac_mls *subj, *obj;
2089 
2090 	if (!mls_enabled)
2091 		return (0);
2092 
2093 	subj = SLOT(cred->cr_label);
2094 	obj = SLOT(vplabel);
2095 
2096 	if (!mls_dominate_effective(obj, subj) ||
2097 	    !mls_dominate_effective(subj, obj))
2098 		return (EACCES);
2099 
2100 	return (0);
2101 }
2102 
2103 static void
2104 mls_sysvmsg_cleanup(struct label *msglabel)
2105 {
2106 
2107 	bzero(SLOT(msglabel), sizeof(struct mac_mls));
2108 }
2109 
2110 static void
2111 mls_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
2112     struct label *msqlabel, struct msg *msgptr, struct label *msglabel)
2113 {
2114 	struct mac_mls *source, *dest;
2115 
2116 	/* Ignore the msgq label. */
2117 	source = SLOT(cred->cr_label);
2118 	dest = SLOT(msglabel);
2119 
2120 	mls_copy_effective(source, dest);
2121 }
2122 
2123 static int
2124 mls_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr,
2125     struct label *msglabel)
2126 {
2127 	struct mac_mls *subj, *obj;
2128 
2129 	if (!mls_enabled)
2130 		return (0);
2131 
2132 	subj = SLOT(cred->cr_label);
2133 	obj = SLOT(msglabel);
2134 
2135 	if (!mls_dominate_effective(subj, obj))
2136 		return (EACCES);
2137 
2138 	return (0);
2139 }
2140 
2141 static int
2142 mls_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr,
2143     struct label *msglabel)
2144 {
2145 	struct mac_mls *subj, *obj;
2146 
2147 	if (!mls_enabled)
2148 		return (0);
2149 
2150 	subj = SLOT(cred->cr_label);
2151 	obj = SLOT(msglabel);
2152 
2153 	if (!mls_dominate_effective(obj, subj))
2154 		return (EACCES);
2155 
2156 	return (0);
2157 }
2158 
2159 static int
2160 mls_sysvmsq_check_msqget(struct ucred *cred, struct msqid_kernel *msqkptr,
2161     struct label *msqklabel)
2162 {
2163 	struct mac_mls *subj, *obj;
2164 
2165 	if (!mls_enabled)
2166 		return (0);
2167 
2168 	subj = SLOT(cred->cr_label);
2169 	obj = SLOT(msqklabel);
2170 
2171 	if (!mls_dominate_effective(subj, obj))
2172 		return (EACCES);
2173 
2174 	return (0);
2175 }
2176 
2177 static int
2178 mls_sysvmsq_check_msqsnd(struct ucred *cred, struct msqid_kernel *msqkptr,
2179     struct label *msqklabel)
2180 {
2181 	struct mac_mls *subj, *obj;
2182 
2183 	if (!mls_enabled)
2184 		return (0);
2185 
2186 	subj = SLOT(cred->cr_label);
2187 	obj = SLOT(msqklabel);
2188 
2189 	if (!mls_dominate_effective(obj, subj))
2190 		return (EACCES);
2191 
2192 	return (0);
2193 }
2194 
2195 static int
2196 mls_sysvmsq_check_msqrcv(struct ucred *cred, struct msqid_kernel *msqkptr,
2197     struct label *msqklabel)
2198 {
2199 	struct mac_mls *subj, *obj;
2200 
2201 	if (!mls_enabled)
2202 		return (0);
2203 
2204 	subj = SLOT(cred->cr_label);
2205 	obj = SLOT(msqklabel);
2206 
2207 	if (!mls_dominate_effective(subj, obj))
2208 		return (EACCES);
2209 
2210 	return (0);
2211 }
2212 
2213 static int
2214 mls_sysvmsq_check_msqctl(struct ucred *cred, struct msqid_kernel *msqkptr,
2215     struct label *msqklabel, int cmd)
2216 {
2217 	struct mac_mls *subj, *obj;
2218 
2219 	if (!mls_enabled)
2220 		return (0);
2221 
2222 	subj = SLOT(cred->cr_label);
2223 	obj = SLOT(msqklabel);
2224 
2225 	switch(cmd) {
2226 	case IPC_RMID:
2227 	case IPC_SET:
2228 		if (!mls_dominate_effective(obj, subj))
2229 			return (EACCES);
2230 		break;
2231 
2232 	case IPC_STAT:
2233 		if (!mls_dominate_effective(subj, obj))
2234 			return (EACCES);
2235 		break;
2236 
2237 	default:
2238 		return (EACCES);
2239 	}
2240 
2241 	return (0);
2242 }
2243 
2244 static void
2245 mls_sysvmsq_cleanup(struct label *msqlabel)
2246 {
2247 
2248 	bzero(SLOT(msqlabel), sizeof(struct mac_mls));
2249 }
2250 
2251 static void
2252 mls_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr,
2253     struct label *msqlabel)
2254 {
2255 	struct mac_mls *source, *dest;
2256 
2257 	source = SLOT(cred->cr_label);
2258 	dest = SLOT(msqlabel);
2259 
2260 	mls_copy_effective(source, dest);
2261 }
2262 
2263 static int
2264 mls_sysvsem_check_semctl(struct ucred *cred, struct semid_kernel *semakptr,
2265     struct label *semaklabel, int cmd)
2266 {
2267 	struct mac_mls *subj, *obj;
2268 
2269 	if (!mls_enabled)
2270 		return (0);
2271 
2272 	subj = SLOT(cred->cr_label);
2273 	obj = SLOT(semaklabel);
2274 
2275 	switch(cmd) {
2276 	case IPC_RMID:
2277 	case IPC_SET:
2278 	case SETVAL:
2279 	case SETALL:
2280 		if (!mls_dominate_effective(obj, subj))
2281 			return (EACCES);
2282 		break;
2283 
2284 	case IPC_STAT:
2285 	case GETVAL:
2286 	case GETPID:
2287 	case GETNCNT:
2288 	case GETZCNT:
2289 	case GETALL:
2290 		if (!mls_dominate_effective(subj, obj))
2291 			return (EACCES);
2292 		break;
2293 
2294 	default:
2295 		return (EACCES);
2296 	}
2297 
2298 	return (0);
2299 }
2300 
2301 static int
2302 mls_sysvsem_check_semget(struct ucred *cred, struct semid_kernel *semakptr,
2303     struct label *semaklabel)
2304 {
2305 	struct mac_mls *subj, *obj;
2306 
2307 	if (!mls_enabled)
2308 		return (0);
2309 
2310 	subj = SLOT(cred->cr_label);
2311 	obj = SLOT(semaklabel);
2312 
2313 	if (!mls_dominate_effective(subj, obj))
2314 		return (EACCES);
2315 
2316 	return (0);
2317 }
2318 
2319 static int
2320 mls_sysvsem_check_semop(struct ucred *cred, struct semid_kernel *semakptr,
2321     struct label *semaklabel, size_t accesstype)
2322 {
2323 	struct mac_mls *subj, *obj;
2324 
2325 	if (!mls_enabled)
2326 		return (0);
2327 
2328 	subj = SLOT(cred->cr_label);
2329 	obj = SLOT(semaklabel);
2330 
2331 	if( accesstype & SEM_R )
2332 		if (!mls_dominate_effective(subj, obj))
2333 			return (EACCES);
2334 
2335 	if( accesstype & SEM_A )
2336 		if (!mls_dominate_effective(obj, subj))
2337 			return (EACCES);
2338 
2339 	return (0);
2340 }
2341 
2342 static void
2343 mls_sysvsem_cleanup(struct label *semalabel)
2344 {
2345 
2346 	bzero(SLOT(semalabel), sizeof(struct mac_mls));
2347 }
2348 
2349 static void
2350 mls_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr,
2351     struct label *semalabel)
2352 {
2353 	struct mac_mls *source, *dest;
2354 
2355 	source = SLOT(cred->cr_label);
2356 	dest = SLOT(semalabel);
2357 
2358 	mls_copy_effective(source, dest);
2359 }
2360 
2361 static int
2362 mls_sysvshm_check_shmat(struct ucred *cred, struct shmid_kernel *shmsegptr,
2363     struct label *shmseglabel, int shmflg)
2364 {
2365 	struct mac_mls *subj, *obj;
2366 
2367 	if (!mls_enabled)
2368 		return (0);
2369 
2370 	subj = SLOT(cred->cr_label);
2371 	obj = SLOT(shmseglabel);
2372 
2373 	if (!mls_dominate_effective(subj, obj))
2374 		return (EACCES);
2375 	if ((shmflg & SHM_RDONLY) == 0) {
2376 		if (!mls_dominate_effective(obj, subj))
2377 			return (EACCES);
2378 	}
2379 
2380 	return (0);
2381 }
2382 
2383 static int
2384 mls_sysvshm_check_shmctl(struct ucred *cred, struct shmid_kernel *shmsegptr,
2385     struct label *shmseglabel, int cmd)
2386 {
2387 	struct mac_mls *subj, *obj;
2388 
2389 	if (!mls_enabled)
2390 		return (0);
2391 
2392 	subj = SLOT(cred->cr_label);
2393 	obj = SLOT(shmseglabel);
2394 
2395 	switch(cmd) {
2396 	case IPC_RMID:
2397 	case IPC_SET:
2398 		if (!mls_dominate_effective(obj, subj))
2399 			return (EACCES);
2400 		break;
2401 
2402 	case IPC_STAT:
2403 	case SHM_STAT:
2404 		if (!mls_dominate_effective(subj, obj))
2405 			return (EACCES);
2406 		break;
2407 
2408 	default:
2409 		return (EACCES);
2410 	}
2411 
2412 	return (0);
2413 }
2414 
2415 static int
2416 mls_sysvshm_check_shmget(struct ucred *cred, struct shmid_kernel *shmsegptr,
2417     struct label *shmseglabel, int shmflg)
2418 {
2419 	struct mac_mls *subj, *obj;
2420 
2421 	if (!mls_enabled)
2422 		return (0);
2423 
2424 	subj = SLOT(cred->cr_label);
2425 	obj = SLOT(shmseglabel);
2426 
2427 	if (!mls_dominate_effective(obj, subj))
2428 		return (EACCES);
2429 
2430 	return (0);
2431 }
2432 
2433 static void
2434 mls_sysvshm_cleanup(struct label *shmlabel)
2435 {
2436 
2437 	bzero(SLOT(shmlabel), sizeof(struct mac_mls));
2438 }
2439 
2440 static void
2441 mls_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr,
2442     struct label *shmlabel)
2443 {
2444 	struct mac_mls *source, *dest;
2445 
2446 	source = SLOT(cred->cr_label);
2447 	dest = SLOT(shmlabel);
2448 
2449 	mls_copy_effective(source, dest);
2450 }
2451 
2452 static int
2453 mls_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
2454     struct vnode *vp, struct label *vplabel)
2455 {
2456 	struct mac_mls mm_temp, *source, *dest;
2457 	int buflen, error;
2458 
2459 	source = SLOT(mplabel);
2460 	dest = SLOT(vplabel);
2461 
2462 	buflen = sizeof(mm_temp);
2463 	bzero(&mm_temp, buflen);
2464 
2465 	error = vn_extattr_get(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
2466 	    MAC_MLS_EXTATTR_NAME, &buflen, (char *) &mm_temp, curthread);
2467 	if (error == ENOATTR || error == EOPNOTSUPP) {
2468 		/* Fall back to the mntlabel. */
2469 		mls_copy_effective(source, dest);
2470 		return (0);
2471 	} else if (error)
2472 		return (error);
2473 
2474 	if (buflen != sizeof(mm_temp)) {
2475 		printf("mls_vnode_associate_extattr: bad size %d\n", buflen);
2476 		return (EPERM);
2477 	}
2478 	if (mls_valid(&mm_temp) != 0) {
2479 		printf("mls_vnode_associate_extattr: invalid\n");
2480 		return (EPERM);
2481 	}
2482 	if ((mm_temp.mm_flags & MAC_MLS_FLAGS_BOTH) !=
2483 	    MAC_MLS_FLAG_EFFECTIVE) {
2484 		printf("mls_associated_vnode_extattr: not effective\n");
2485 		return (EPERM);
2486 	}
2487 
2488 	mls_copy_effective(&mm_temp, dest);
2489 	return (0);
2490 }
2491 
2492 static void
2493 mls_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
2494     struct vnode *vp, struct label *vplabel)
2495 {
2496 	struct mac_mls *source, *dest;
2497 
2498 	source = SLOT(mplabel);
2499 	dest = SLOT(vplabel);
2500 
2501 	mls_copy_effective(source, dest);
2502 }
2503 
2504 static int
2505 mls_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
2506     struct label *dvplabel)
2507 {
2508 	struct mac_mls *subj, *obj;
2509 
2510 	if (!mls_enabled)
2511 		return (0);
2512 
2513 	subj = SLOT(cred->cr_label);
2514 	obj = SLOT(dvplabel);
2515 
2516 	if (!mls_dominate_effective(subj, obj))
2517 		return (EACCES);
2518 
2519 	return (0);
2520 }
2521 
2522 static int
2523 mls_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
2524     struct label *dvplabel)
2525 {
2526 	struct mac_mls *subj, *obj;
2527 
2528 	if (!mls_enabled)
2529 		return (0);
2530 
2531 	subj = SLOT(cred->cr_label);
2532 	obj = SLOT(dvplabel);
2533 
2534 	if (!mls_dominate_effective(subj, obj))
2535 		return (EACCES);
2536 
2537 	return (0);
2538 }
2539 
2540 static int
2541 mls_vnode_check_create(struct ucred *cred, struct vnode *dvp,
2542     struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
2543 {
2544 	struct mac_mls *subj, *obj;
2545 
2546 	if (!mls_enabled)
2547 		return (0);
2548 
2549 	subj = SLOT(cred->cr_label);
2550 	obj = SLOT(dvplabel);
2551 
2552 	if (!mls_dominate_effective(obj, subj))
2553 		return (EACCES);
2554 
2555 	return (0);
2556 }
2557 
2558 static int
2559 mls_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
2560     struct label *vplabel, acl_type_t type)
2561 {
2562 	struct mac_mls *subj, *obj;
2563 
2564 	if (!mls_enabled)
2565 		return (0);
2566 
2567 	subj = SLOT(cred->cr_label);
2568 	obj = SLOT(vplabel);
2569 
2570 	if (!mls_dominate_effective(obj, subj))
2571 		return (EACCES);
2572 
2573 	return (0);
2574 }
2575 
2576 static int
2577 mls_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
2578     struct label *vplabel, int attrnamespace, const char *name)
2579 {
2580 	struct mac_mls *subj, *obj;
2581 
2582 	if (!mls_enabled)
2583 		return (0);
2584 
2585 	subj = SLOT(cred->cr_label);
2586 	obj = SLOT(vplabel);
2587 
2588 	if (!mls_dominate_effective(obj, subj))
2589 		return (EACCES);
2590 
2591 	return (0);
2592 }
2593 
2594 static int
2595 mls_vnode_check_exec(struct ucred *cred, struct vnode *vp,
2596     struct label *vplabel, struct image_params *imgp,
2597     struct label *execlabel)
2598 {
2599 	struct mac_mls *subj, *obj, *exec;
2600 	int error;
2601 
2602 	if (execlabel != NULL) {
2603 		/*
2604 		 * We currently don't permit labels to be changed at
2605 		 * exec-time as part of MLS, so disallow non-NULL MLS label
2606 		 * elements in the execlabel.
2607 		 */
2608 		exec = SLOT(execlabel);
2609 		error = mls_atmostflags(exec, 0);
2610 		if (error)
2611 			return (error);
2612 	}
2613 
2614 	if (!mls_enabled)
2615 		return (0);
2616 
2617 	subj = SLOT(cred->cr_label);
2618 	obj = SLOT(vplabel);
2619 
2620 	if (!mls_dominate_effective(subj, obj))
2621 		return (EACCES);
2622 
2623 	return (0);
2624 }
2625 
2626 static int
2627 mls_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
2628     struct label *vplabel, acl_type_t type)
2629 {
2630 	struct mac_mls *subj, *obj;
2631 
2632 	if (!mls_enabled)
2633 		return (0);
2634 
2635 	subj = SLOT(cred->cr_label);
2636 	obj = SLOT(vplabel);
2637 
2638 	if (!mls_dominate_effective(subj, obj))
2639 		return (EACCES);
2640 
2641 	return (0);
2642 }
2643 
2644 static int
2645 mls_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
2646     struct label *vplabel, int attrnamespace, const char *name)
2647 {
2648 	struct mac_mls *subj, *obj;
2649 
2650 	if (!mls_enabled)
2651 		return (0);
2652 
2653 	subj = SLOT(cred->cr_label);
2654 	obj = SLOT(vplabel);
2655 
2656 	if (!mls_dominate_effective(subj, obj))
2657 		return (EACCES);
2658 
2659 	return (0);
2660 }
2661 
2662 static int
2663 mls_vnode_check_link(struct ucred *cred, struct vnode *dvp,
2664     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2665     struct componentname *cnp)
2666 {
2667 	struct mac_mls *subj, *obj;
2668 
2669 	if (!mls_enabled)
2670 		return (0);
2671 
2672 	subj = SLOT(cred->cr_label);
2673 	obj = SLOT(dvplabel);
2674 
2675 	if (!mls_dominate_effective(obj, subj))
2676 		return (EACCES);
2677 
2678 	obj = SLOT(vplabel);
2679 	if (!mls_dominate_effective(obj, subj))
2680 		return (EACCES);
2681 
2682 	return (0);
2683 }
2684 
2685 static int
2686 mls_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
2687     struct label *vplabel, int attrnamespace)
2688 {
2689 
2690 	struct mac_mls *subj, *obj;
2691 
2692 	if (!mls_enabled)
2693 		return (0);
2694 
2695 	subj = SLOT(cred->cr_label);
2696 	obj = SLOT(vplabel);
2697 
2698 	if (!mls_dominate_effective(subj, obj))
2699 		return (EACCES);
2700 
2701 	return (0);
2702 }
2703 
2704 static int
2705 mls_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
2706     struct label *dvplabel, struct componentname *cnp)
2707 {
2708 	struct mac_mls *subj, *obj;
2709 
2710 	if (!mls_enabled)
2711 		return (0);
2712 
2713 	subj = SLOT(cred->cr_label);
2714 	obj = SLOT(dvplabel);
2715 
2716 	if (!mls_dominate_effective(subj, obj))
2717 		return (EACCES);
2718 
2719 	return (0);
2720 }
2721 
2722 static int
2723 mls_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
2724     struct label *vplabel, int prot, int flags)
2725 {
2726 	struct mac_mls *subj, *obj;
2727 
2728 	/*
2729 	 * Rely on the use of open()-time protections to handle
2730 	 * non-revocation cases.
2731 	 */
2732 	if (!mls_enabled || !revocation_enabled)
2733 		return (0);
2734 
2735 	subj = SLOT(cred->cr_label);
2736 	obj = SLOT(vplabel);
2737 
2738 	if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
2739 		if (!mls_dominate_effective(subj, obj))
2740 			return (EACCES);
2741 	}
2742 	if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
2743 		if (!mls_dominate_effective(obj, subj))
2744 			return (EACCES);
2745 	}
2746 
2747 	return (0);
2748 }
2749 
2750 static int
2751 mls_vnode_check_open(struct ucred *cred, struct vnode *vp,
2752     struct label *vplabel, accmode_t accmode)
2753 {
2754 	struct mac_mls *subj, *obj;
2755 
2756 	if (!mls_enabled)
2757 		return (0);
2758 
2759 	subj = SLOT(cred->cr_label);
2760 	obj = SLOT(vplabel);
2761 
2762 	/* XXX privilege override for admin? */
2763 	if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) {
2764 		if (!mls_dominate_effective(subj, obj))
2765 			return (EACCES);
2766 	}
2767 	if (accmode & VMODIFY_PERMS) {
2768 		if (!mls_dominate_effective(obj, subj))
2769 			return (EACCES);
2770 	}
2771 
2772 	return (0);
2773 }
2774 
2775 static int
2776 mls_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
2777     struct vnode *vp, struct label *vplabel)
2778 {
2779 	struct mac_mls *subj, *obj;
2780 
2781 	if (!mls_enabled || !revocation_enabled)
2782 		return (0);
2783 
2784 	subj = SLOT(active_cred->cr_label);
2785 	obj = SLOT(vplabel);
2786 
2787 	if (!mls_dominate_effective(subj, obj))
2788 		return (EACCES);
2789 
2790 	return (0);
2791 }
2792 
2793 static int
2794 mls_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
2795     struct vnode *vp, struct label *vplabel)
2796 {
2797 	struct mac_mls *subj, *obj;
2798 
2799 	if (!mls_enabled || !revocation_enabled)
2800 		return (0);
2801 
2802 	subj = SLOT(active_cred->cr_label);
2803 	obj = SLOT(vplabel);
2804 
2805 	if (!mls_dominate_effective(subj, obj))
2806 		return (EACCES);
2807 
2808 	return (0);
2809 }
2810 
2811 static int
2812 mls_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
2813     struct label *dvplabel)
2814 {
2815 	struct mac_mls *subj, *obj;
2816 
2817 	if (!mls_enabled)
2818 		return (0);
2819 
2820 	subj = SLOT(cred->cr_label);
2821 	obj = SLOT(dvplabel);
2822 
2823 	if (!mls_dominate_effective(subj, obj))
2824 		return (EACCES);
2825 
2826 	return (0);
2827 }
2828 
2829 static int
2830 mls_vnode_check_readlink(struct ucred *cred, struct vnode *vp,
2831     struct label *vplabel)
2832 {
2833 	struct mac_mls *subj, *obj;
2834 
2835 	if (!mls_enabled)
2836 		return (0);
2837 
2838 	subj = SLOT(cred->cr_label);
2839 	obj = SLOT(vplabel);
2840 
2841 	if (!mls_dominate_effective(subj, obj))
2842 		return (EACCES);
2843 
2844 	return (0);
2845 }
2846 
2847 static int
2848 mls_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
2849     struct label *vplabel, struct label *newlabel)
2850 {
2851 	struct mac_mls *old, *new, *subj;
2852 	int error;
2853 
2854 	old = SLOT(vplabel);
2855 	new = SLOT(newlabel);
2856 	subj = SLOT(cred->cr_label);
2857 
2858 	/*
2859 	 * If there is an MLS label update for the vnode, it must be a
2860 	 * effective label.
2861 	 */
2862 	error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
2863 	if (error)
2864 		return (error);
2865 
2866 	/*
2867 	 * To perform a relabel of the vnode (MLS label or not), MLS must
2868 	 * authorize the relabel.
2869 	 */
2870 	if (!mls_effective_in_range(old, subj))
2871 		return (EPERM);
2872 
2873 	/*
2874 	 * If the MLS label is to be changed, authorize as appropriate.
2875 	 */
2876 	if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
2877 		/*
2878 		 * To change the MLS label on a vnode, the new vnode label
2879 		 * must be in the subject range.
2880 		 */
2881 		if (!mls_effective_in_range(new, subj))
2882 			return (EPERM);
2883 
2884 		/*
2885 		 * To change the MLS label on the vnode to be EQUAL, the
2886 		 * subject must have appropriate privilege.
2887 		 */
2888 		if (mls_contains_equal(new)) {
2889 			error = mls_subject_privileged(subj);
2890 			if (error)
2891 				return (error);
2892 		}
2893 	}
2894 
2895 	return (0);
2896 }
2897 
2898 static int
2899 mls_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
2900     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2901     struct componentname *cnp)
2902 {
2903 	struct mac_mls *subj, *obj;
2904 
2905 	if (!mls_enabled)
2906 		return (0);
2907 
2908 	subj = SLOT(cred->cr_label);
2909 	obj = SLOT(dvplabel);
2910 
2911 	if (!mls_dominate_effective(obj, subj))
2912 		return (EACCES);
2913 
2914 	obj = SLOT(vplabel);
2915 
2916 	if (!mls_dominate_effective(obj, subj))
2917 		return (EACCES);
2918 
2919 	return (0);
2920 }
2921 
2922 static int
2923 mls_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
2924     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2925     int samedir, struct componentname *cnp)
2926 {
2927 	struct mac_mls *subj, *obj;
2928 
2929 	if (!mls_enabled)
2930 		return (0);
2931 
2932 	subj = SLOT(cred->cr_label);
2933 	obj = SLOT(dvplabel);
2934 
2935 	if (!mls_dominate_effective(obj, subj))
2936 		return (EACCES);
2937 
2938 	if (vp != NULL) {
2939 		obj = SLOT(vplabel);
2940 
2941 		if (!mls_dominate_effective(obj, subj))
2942 			return (EACCES);
2943 	}
2944 
2945 	return (0);
2946 }
2947 
2948 static int
2949 mls_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
2950     struct label *vplabel)
2951 {
2952 	struct mac_mls *subj, *obj;
2953 
2954 	if (!mls_enabled)
2955 		return (0);
2956 
2957 	subj = SLOT(cred->cr_label);
2958 	obj = SLOT(vplabel);
2959 
2960 	if (!mls_dominate_effective(obj, subj))
2961 		return (EACCES);
2962 
2963 	return (0);
2964 }
2965 
2966 static int
2967 mls_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
2968     struct label *vplabel, acl_type_t type, struct acl *acl)
2969 {
2970 	struct mac_mls *subj, *obj;
2971 
2972 	if (!mls_enabled)
2973 		return (0);
2974 
2975 	subj = SLOT(cred->cr_label);
2976 	obj = SLOT(vplabel);
2977 
2978 	if (!mls_dominate_effective(obj, subj))
2979 		return (EACCES);
2980 
2981 	return (0);
2982 }
2983 
2984 static int
2985 mls_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
2986     struct label *vplabel, int attrnamespace, const char *name)
2987 {
2988 	struct mac_mls *subj, *obj;
2989 
2990 	if (!mls_enabled)
2991 		return (0);
2992 
2993 	subj = SLOT(cred->cr_label);
2994 	obj = SLOT(vplabel);
2995 
2996 	if (!mls_dominate_effective(obj, subj))
2997 		return (EACCES);
2998 
2999 	/* XXX: protect the MAC EA in a special way? */
3000 
3001 	return (0);
3002 }
3003 
3004 static int
3005 mls_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
3006     struct label *vplabel, u_long flags)
3007 {
3008 	struct mac_mls *subj, *obj;
3009 
3010 	if (!mls_enabled)
3011 		return (0);
3012 
3013 	subj = SLOT(cred->cr_label);
3014 	obj = SLOT(vplabel);
3015 
3016 	if (!mls_dominate_effective(obj, subj))
3017 		return (EACCES);
3018 
3019 	return (0);
3020 }
3021 
3022 static int
3023 mls_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
3024     struct label *vplabel, mode_t mode)
3025 {
3026 	struct mac_mls *subj, *obj;
3027 
3028 	if (!mls_enabled)
3029 		return (0);
3030 
3031 	subj = SLOT(cred->cr_label);
3032 	obj = SLOT(vplabel);
3033 
3034 	if (!mls_dominate_effective(obj, subj))
3035 		return (EACCES);
3036 
3037 	return (0);
3038 }
3039 
3040 static int
3041 mls_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
3042     struct label *vplabel, uid_t uid, gid_t gid)
3043 {
3044 	struct mac_mls *subj, *obj;
3045 
3046 	if (!mls_enabled)
3047 		return (0);
3048 
3049 	subj = SLOT(cred->cr_label);
3050 	obj = SLOT(vplabel);
3051 
3052 	if (!mls_dominate_effective(obj, subj))
3053 		return (EACCES);
3054 
3055 	return (0);
3056 }
3057 
3058 static int
3059 mls_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
3060     struct label *vplabel, struct timespec atime, struct timespec mtime)
3061 {
3062 	struct mac_mls *subj, *obj;
3063 
3064 	if (!mls_enabled)
3065 		return (0);
3066 
3067 	subj = SLOT(cred->cr_label);
3068 	obj = SLOT(vplabel);
3069 
3070 	if (!mls_dominate_effective(obj, subj))
3071 		return (EACCES);
3072 
3073 	return (0);
3074 }
3075 
3076 static int
3077 mls_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
3078     struct vnode *vp, struct label *vplabel)
3079 {
3080 	struct mac_mls *subj, *obj;
3081 
3082 	if (!mls_enabled)
3083 		return (0);
3084 
3085 	subj = SLOT(active_cred->cr_label);
3086 	obj = SLOT(vplabel);
3087 
3088 	if (!mls_dominate_effective(subj, obj))
3089 		return (EACCES);
3090 
3091 	return (0);
3092 }
3093 
3094 static int
3095 mls_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
3096     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
3097     struct componentname *cnp)
3098 {
3099 	struct mac_mls *subj, *obj;
3100 
3101 	if (!mls_enabled)
3102 		return (0);
3103 
3104 	subj = SLOT(cred->cr_label);
3105 	obj = SLOT(dvplabel);
3106 
3107 	if (!mls_dominate_effective(obj, subj))
3108 		return (EACCES);
3109 
3110 	obj = SLOT(vplabel);
3111 
3112 	if (!mls_dominate_effective(obj, subj))
3113 		return (EACCES);
3114 
3115 	return (0);
3116 }
3117 
3118 static int
3119 mls_vnode_check_write(struct ucred *active_cred, struct ucred *file_cred,
3120     struct vnode *vp, struct label *vplabel)
3121 {
3122 	struct mac_mls *subj, *obj;
3123 
3124 	if (!mls_enabled || !revocation_enabled)
3125 		return (0);
3126 
3127 	subj = SLOT(active_cred->cr_label);
3128 	obj = SLOT(vplabel);
3129 
3130 	if (!mls_dominate_effective(obj, subj))
3131 		return (EACCES);
3132 
3133 	return (0);
3134 }
3135 
3136 static int
3137 mls_vnode_create_extattr(struct ucred *cred, struct mount *mp,
3138     struct label *mplabel, struct vnode *dvp, struct label *dvplabel,
3139     struct vnode *vp, struct label *vplabel, struct componentname *cnp)
3140 {
3141 	struct mac_mls *source, *dest, mm_temp;
3142 	size_t buflen;
3143 	int error;
3144 
3145 	buflen = sizeof(mm_temp);
3146 	bzero(&mm_temp, buflen);
3147 
3148 	source = SLOT(cred->cr_label);
3149 	dest = SLOT(vplabel);
3150 	mls_copy_effective(source, &mm_temp);
3151 
3152 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
3153 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
3154 	if (error == 0)
3155 		mls_copy_effective(source, dest);
3156 	return (error);
3157 }
3158 
3159 static void
3160 mls_vnode_relabel(struct ucred *cred, struct vnode *vp,
3161     struct label *vplabel, struct label *label)
3162 {
3163 	struct mac_mls *source, *dest;
3164 
3165 	source = SLOT(label);
3166 	dest = SLOT(vplabel);
3167 
3168 	mls_copy(source, dest);
3169 }
3170 
3171 static int
3172 mls_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
3173     struct label *vplabel, struct label *intlabel)
3174 {
3175 	struct mac_mls *source, mm_temp;
3176 	size_t buflen;
3177 	int error;
3178 
3179 	buflen = sizeof(mm_temp);
3180 	bzero(&mm_temp, buflen);
3181 
3182 	source = SLOT(intlabel);
3183 	if ((source->mm_flags & MAC_MLS_FLAG_EFFECTIVE) == 0)
3184 		return (0);
3185 
3186 	mls_copy_effective(source, &mm_temp);
3187 
3188 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
3189 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
3190 	return (error);
3191 }
3192 
3193 static struct mac_policy_ops mls_ops =
3194 {
3195 	.mpo_init = mls_init,
3196 
3197 	.mpo_bpfdesc_check_receive = mls_bpfdesc_check_receive,
3198 	.mpo_bpfdesc_create = mls_bpfdesc_create,
3199 	.mpo_bpfdesc_create_mbuf = mls_bpfdesc_create_mbuf,
3200 	.mpo_bpfdesc_destroy_label = mls_destroy_label,
3201 	.mpo_bpfdesc_init_label = mls_init_label,
3202 
3203 	.mpo_cred_associate_nfsd = mls_cred_associate_nfsd,
3204 	.mpo_cred_check_relabel = mls_cred_check_relabel,
3205 	.mpo_cred_check_visible = mls_cred_check_visible,
3206 	.mpo_cred_copy_label = mls_copy_label,
3207 	.mpo_cred_create_init = mls_cred_create_init,
3208 	.mpo_cred_create_swapper = mls_cred_create_swapper,
3209 	.mpo_cred_destroy_label = mls_destroy_label,
3210 	.mpo_cred_externalize_label = mls_externalize_label,
3211 	.mpo_cred_init_label = mls_init_label,
3212 	.mpo_cred_internalize_label = mls_internalize_label,
3213 	.mpo_cred_relabel = mls_cred_relabel,
3214 
3215 	.mpo_devfs_create_device = mls_devfs_create_device,
3216 	.mpo_devfs_create_directory = mls_devfs_create_directory,
3217 	.mpo_devfs_create_symlink = mls_devfs_create_symlink,
3218 	.mpo_devfs_destroy_label = mls_destroy_label,
3219 	.mpo_devfs_init_label = mls_init_label,
3220 	.mpo_devfs_update = mls_devfs_update,
3221 	.mpo_devfs_vnode_associate = mls_devfs_vnode_associate,
3222 
3223 	.mpo_ifnet_check_relabel = mls_ifnet_check_relabel,
3224 	.mpo_ifnet_check_transmit = mls_ifnet_check_transmit,
3225 	.mpo_ifnet_copy_label = mls_copy_label,
3226 	.mpo_ifnet_create = mls_ifnet_create,
3227 	.mpo_ifnet_create_mbuf = mls_ifnet_create_mbuf,
3228 	.mpo_ifnet_destroy_label = mls_destroy_label,
3229 	.mpo_ifnet_externalize_label = mls_externalize_label,
3230 	.mpo_ifnet_init_label = mls_init_label,
3231 	.mpo_ifnet_internalize_label = mls_internalize_label,
3232 	.mpo_ifnet_relabel = mls_ifnet_relabel,
3233 
3234 	.mpo_inpcb_check_deliver = mls_inpcb_check_deliver,
3235 	.mpo_inpcb_check_visible = mls_inpcb_check_visible,
3236 	.mpo_inpcb_create = mls_inpcb_create,
3237 	.mpo_inpcb_create_mbuf = mls_inpcb_create_mbuf,
3238 	.mpo_inpcb_destroy_label = mls_destroy_label,
3239 	.mpo_inpcb_init_label = mls_init_label_waitcheck,
3240 	.mpo_inpcb_sosetlabel = mls_inpcb_sosetlabel,
3241 
3242 	.mpo_ip6q_create = mls_ip6q_create,
3243 	.mpo_ip6q_destroy_label = mls_destroy_label,
3244 	.mpo_ip6q_init_label = mls_init_label_waitcheck,
3245 	.mpo_ip6q_match = mls_ip6q_match,
3246 	.mpo_ip6q_reassemble = mls_ip6q_reassemble,
3247 	.mpo_ip6q_update = mls_ip6q_update,
3248 
3249 	.mpo_ipq_create = mls_ipq_create,
3250 	.mpo_ipq_destroy_label = mls_destroy_label,
3251 	.mpo_ipq_init_label = mls_init_label_waitcheck,
3252 	.mpo_ipq_match = mls_ipq_match,
3253 	.mpo_ipq_reassemble = mls_ipq_reassemble,
3254 	.mpo_ipq_update = mls_ipq_update,
3255 
3256 	.mpo_mbuf_copy_label = mls_copy_label,
3257 	.mpo_mbuf_destroy_label = mls_destroy_label,
3258 	.mpo_mbuf_init_label = mls_init_label_waitcheck,
3259 
3260 	.mpo_mount_check_stat = mls_mount_check_stat,
3261 	.mpo_mount_create = mls_mount_create,
3262 	.mpo_mount_destroy_label = mls_destroy_label,
3263 	.mpo_mount_init_label = mls_init_label,
3264 
3265 	.mpo_netinet_arp_send = mls_netinet_arp_send,
3266 	.mpo_netinet_firewall_reply = mls_netinet_firewall_reply,
3267 	.mpo_netinet_firewall_send = mls_netinet_firewall_send,
3268 	.mpo_netinet_fragment = mls_netinet_fragment,
3269 	.mpo_netinet_icmp_reply = mls_netinet_icmp_reply,
3270 	.mpo_netinet_igmp_send = mls_netinet_igmp_send,
3271 
3272 	.mpo_netinet6_nd6_send = mls_netinet6_nd6_send,
3273 
3274 	.mpo_pipe_check_ioctl = mls_pipe_check_ioctl,
3275 	.mpo_pipe_check_poll = mls_pipe_check_poll,
3276 	.mpo_pipe_check_read = mls_pipe_check_read,
3277 	.mpo_pipe_check_relabel = mls_pipe_check_relabel,
3278 	.mpo_pipe_check_stat = mls_pipe_check_stat,
3279 	.mpo_pipe_check_write = mls_pipe_check_write,
3280 	.mpo_pipe_copy_label = mls_copy_label,
3281 	.mpo_pipe_create = mls_pipe_create,
3282 	.mpo_pipe_destroy_label = mls_destroy_label,
3283 	.mpo_pipe_externalize_label = mls_externalize_label,
3284 	.mpo_pipe_init_label = mls_init_label,
3285 	.mpo_pipe_internalize_label = mls_internalize_label,
3286 	.mpo_pipe_relabel = mls_pipe_relabel,
3287 
3288 	.mpo_posixsem_check_getvalue = mls_posixsem_check_rdonly,
3289 	.mpo_posixsem_check_open = mls_posixsem_check_openunlink,
3290 	.mpo_posixsem_check_post = mls_posixsem_check_write,
3291 	.mpo_posixsem_check_setmode = mls_posixsem_check_setmode,
3292 	.mpo_posixsem_check_setowner = mls_posixsem_check_setowner,
3293 	.mpo_posixsem_check_stat = mls_posixsem_check_rdonly,
3294 	.mpo_posixsem_check_unlink = mls_posixsem_check_openunlink,
3295 	.mpo_posixsem_check_wait = mls_posixsem_check_write,
3296 	.mpo_posixsem_create = mls_posixsem_create,
3297 	.mpo_posixsem_destroy_label = mls_destroy_label,
3298 	.mpo_posixsem_init_label = mls_init_label,
3299 
3300 	.mpo_posixshm_check_mmap = mls_posixshm_check_mmap,
3301 	.mpo_posixshm_check_open = mls_posixshm_check_open,
3302 	.mpo_posixshm_check_read = mls_posixshm_check_read,
3303 	.mpo_posixshm_check_setmode = mls_posixshm_check_setmode,
3304 	.mpo_posixshm_check_setowner = mls_posixshm_check_setowner,
3305 	.mpo_posixshm_check_stat = mls_posixshm_check_stat,
3306 	.mpo_posixshm_check_truncate = mls_posixshm_check_truncate,
3307 	.mpo_posixshm_check_unlink = mls_posixshm_check_unlink,
3308 	.mpo_posixshm_check_write = mls_posixshm_check_write,
3309 	.mpo_posixshm_create = mls_posixshm_create,
3310 	.mpo_posixshm_destroy_label = mls_destroy_label,
3311 	.mpo_posixshm_init_label = mls_init_label,
3312 
3313 	.mpo_proc_check_debug = mls_proc_check_debug,
3314 	.mpo_proc_check_sched = mls_proc_check_sched,
3315 	.mpo_proc_check_signal = mls_proc_check_signal,
3316 
3317 	.mpo_socket_check_deliver = mls_socket_check_deliver,
3318 	.mpo_socket_check_relabel = mls_socket_check_relabel,
3319 	.mpo_socket_check_visible = mls_socket_check_visible,
3320 	.mpo_socket_copy_label = mls_copy_label,
3321 	.mpo_socket_create = mls_socket_create,
3322 	.mpo_socket_create_mbuf = mls_socket_create_mbuf,
3323 	.mpo_socket_destroy_label = mls_destroy_label,
3324 	.mpo_socket_externalize_label = mls_externalize_label,
3325 	.mpo_socket_init_label = mls_init_label_waitcheck,
3326 	.mpo_socket_internalize_label = mls_internalize_label,
3327 	.mpo_socket_newconn = mls_socket_newconn,
3328 	.mpo_socket_relabel = mls_socket_relabel,
3329 
3330 	.mpo_socketpeer_destroy_label = mls_destroy_label,
3331 	.mpo_socketpeer_externalize_label = mls_externalize_label,
3332 	.mpo_socketpeer_init_label = mls_init_label_waitcheck,
3333 	.mpo_socketpeer_set_from_mbuf = mls_socketpeer_set_from_mbuf,
3334 	.mpo_socketpeer_set_from_socket = mls_socketpeer_set_from_socket,
3335 
3336 	.mpo_syncache_create = mls_syncache_create,
3337 	.mpo_syncache_create_mbuf = mls_syncache_create_mbuf,
3338 	.mpo_syncache_destroy_label = mls_destroy_label,
3339 	.mpo_syncache_init_label = mls_init_label_waitcheck,
3340 
3341 	.mpo_sysvmsg_cleanup = mls_sysvmsg_cleanup,
3342 	.mpo_sysvmsg_create = mls_sysvmsg_create,
3343 	.mpo_sysvmsg_destroy_label = mls_destroy_label,
3344 	.mpo_sysvmsg_init_label = mls_init_label,
3345 
3346 	.mpo_sysvmsq_check_msgrcv = mls_sysvmsq_check_msgrcv,
3347 	.mpo_sysvmsq_check_msgrmid = mls_sysvmsq_check_msgrmid,
3348 	.mpo_sysvmsq_check_msqget = mls_sysvmsq_check_msqget,
3349 	.mpo_sysvmsq_check_msqsnd = mls_sysvmsq_check_msqsnd,
3350 	.mpo_sysvmsq_check_msqrcv = mls_sysvmsq_check_msqrcv,
3351 	.mpo_sysvmsq_check_msqctl = mls_sysvmsq_check_msqctl,
3352 	.mpo_sysvmsq_cleanup = mls_sysvmsq_cleanup,
3353 	.mpo_sysvmsq_destroy_label = mls_destroy_label,
3354 	.mpo_sysvmsq_init_label = mls_init_label,
3355 	.mpo_sysvmsq_create = mls_sysvmsq_create,
3356 
3357 	.mpo_sysvsem_check_semctl = mls_sysvsem_check_semctl,
3358 	.mpo_sysvsem_check_semget = mls_sysvsem_check_semget,
3359 	.mpo_sysvsem_check_semop = mls_sysvsem_check_semop,
3360 	.mpo_sysvsem_cleanup = mls_sysvsem_cleanup,
3361 	.mpo_sysvsem_create = mls_sysvsem_create,
3362 	.mpo_sysvsem_destroy_label = mls_destroy_label,
3363 	.mpo_sysvsem_init_label = mls_init_label,
3364 
3365 	.mpo_sysvshm_check_shmat = mls_sysvshm_check_shmat,
3366 	.mpo_sysvshm_check_shmctl = mls_sysvshm_check_shmctl,
3367 	.mpo_sysvshm_check_shmget = mls_sysvshm_check_shmget,
3368 	.mpo_sysvshm_cleanup = mls_sysvshm_cleanup,
3369 	.mpo_sysvshm_create = mls_sysvshm_create,
3370 	.mpo_sysvshm_destroy_label = mls_destroy_label,
3371 	.mpo_sysvshm_init_label = mls_init_label,
3372 
3373 	.mpo_system_check_acct = mls_system_check_acct,
3374 	.mpo_system_check_auditctl = mls_system_check_auditctl,
3375 	.mpo_system_check_swapon = mls_system_check_swapon,
3376 
3377 	.mpo_vnode_associate_extattr = mls_vnode_associate_extattr,
3378 	.mpo_vnode_associate_singlelabel = mls_vnode_associate_singlelabel,
3379 	.mpo_vnode_check_access = mls_vnode_check_open,
3380 	.mpo_vnode_check_chdir = mls_vnode_check_chdir,
3381 	.mpo_vnode_check_chroot = mls_vnode_check_chroot,
3382 	.mpo_vnode_check_create = mls_vnode_check_create,
3383 	.mpo_vnode_check_deleteacl = mls_vnode_check_deleteacl,
3384 	.mpo_vnode_check_deleteextattr = mls_vnode_check_deleteextattr,
3385 	.mpo_vnode_check_exec = mls_vnode_check_exec,
3386 	.mpo_vnode_check_getacl = mls_vnode_check_getacl,
3387 	.mpo_vnode_check_getextattr = mls_vnode_check_getextattr,
3388 	.mpo_vnode_check_link = mls_vnode_check_link,
3389 	.mpo_vnode_check_listextattr = mls_vnode_check_listextattr,
3390 	.mpo_vnode_check_lookup = mls_vnode_check_lookup,
3391 	.mpo_vnode_check_mmap = mls_vnode_check_mmap,
3392 	.mpo_vnode_check_open = mls_vnode_check_open,
3393 	.mpo_vnode_check_poll = mls_vnode_check_poll,
3394 	.mpo_vnode_check_read = mls_vnode_check_read,
3395 	.mpo_vnode_check_readdir = mls_vnode_check_readdir,
3396 	.mpo_vnode_check_readlink = mls_vnode_check_readlink,
3397 	.mpo_vnode_check_relabel = mls_vnode_check_relabel,
3398 	.mpo_vnode_check_rename_from = mls_vnode_check_rename_from,
3399 	.mpo_vnode_check_rename_to = mls_vnode_check_rename_to,
3400 	.mpo_vnode_check_revoke = mls_vnode_check_revoke,
3401 	.mpo_vnode_check_setacl = mls_vnode_check_setacl,
3402 	.mpo_vnode_check_setextattr = mls_vnode_check_setextattr,
3403 	.mpo_vnode_check_setflags = mls_vnode_check_setflags,
3404 	.mpo_vnode_check_setmode = mls_vnode_check_setmode,
3405 	.mpo_vnode_check_setowner = mls_vnode_check_setowner,
3406 	.mpo_vnode_check_setutimes = mls_vnode_check_setutimes,
3407 	.mpo_vnode_check_stat = mls_vnode_check_stat,
3408 	.mpo_vnode_check_unlink = mls_vnode_check_unlink,
3409 	.mpo_vnode_check_write = mls_vnode_check_write,
3410 	.mpo_vnode_copy_label = mls_copy_label,
3411 	.mpo_vnode_create_extattr = mls_vnode_create_extattr,
3412 	.mpo_vnode_destroy_label = mls_destroy_label,
3413 	.mpo_vnode_externalize_label = mls_externalize_label,
3414 	.mpo_vnode_init_label = mls_init_label,
3415 	.mpo_vnode_internalize_label = mls_internalize_label,
3416 	.mpo_vnode_relabel = mls_vnode_relabel,
3417 	.mpo_vnode_setlabel_extattr = mls_vnode_setlabel_extattr,
3418 };
3419 
3420 MAC_POLICY_SET(&mls_ops, mac_mls, "TrustedBSD MAC/MLS",
3421     MPC_LOADTIME_FLAG_NOTLATE, &mls_slot);
3422