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