xref: /freebsd/sys/security/mac_mls/mac_mls.c (revision e0c27215058b5786c78fcfb3963eebe61a989511)
1 /*-
2  * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3  * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc.
4  * All rights reserved.
5  *
6  * This software was developed by Robert Watson for the TrustedBSD Project.
7  *
8  * This software was developed for the FreeBSD Project in part by Network
9  * Associates Laboratories, the Security Research Division of Network
10  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
11  * as part of the DARPA CHATS research program.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $FreeBSD$
35  */
36 
37 /*
38  * Developed by the TrustedBSD Project.
39  * MLS fixed label mandatory confidentiality policy.
40  */
41 
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/acl.h>
45 #include <sys/conf.h>
46 #include <sys/extattr.h>
47 #include <sys/kernel.h>
48 #include <sys/mac.h>
49 #include <sys/malloc.h>
50 #include <sys/mount.h>
51 #include <sys/proc.h>
52 #include <sys/sbuf.h>
53 #include <sys/systm.h>
54 #include <sys/sysproto.h>
55 #include <sys/sysent.h>
56 #include <sys/systm.h>
57 #include <sys/vnode.h>
58 #include <sys/file.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/pipe.h>
62 #include <sys/sysctl.h>
63 
64 #include <fs/devfs/devfs.h>
65 
66 #include <net/bpfdesc.h>
67 #include <net/if.h>
68 #include <net/if_types.h>
69 #include <net/if_var.h>
70 
71 #include <netinet/in.h>
72 #include <netinet/ip_var.h>
73 
74 #include <vm/vm.h>
75 
76 #include <sys/mac_policy.h>
77 
78 #include <security/mac_mls/mac_mls.h>
79 
80 SYSCTL_DECL(_security_mac);
81 
82 SYSCTL_NODE(_security_mac, OID_AUTO, mls, CTLFLAG_RW, 0,
83     "TrustedBSD mac_mls policy controls");
84 
85 static int	mac_mls_label_size = sizeof(struct mac_mls);
86 SYSCTL_INT(_security_mac_mls, OID_AUTO, label_size, CTLFLAG_RD,
87     &mac_mls_label_size, 0, "Size of struct mac_mls");
88 
89 static int	mac_mls_enabled = 1;
90 SYSCTL_INT(_security_mac_mls, OID_AUTO, enabled, CTLFLAG_RW,
91     &mac_mls_enabled, 0, "Enforce MAC/MLS policy");
92 TUNABLE_INT("security.mac.mls.enabled", &mac_mls_enabled);
93 
94 static int	destroyed_not_inited;
95 SYSCTL_INT(_security_mac_mls, OID_AUTO, destroyed_not_inited, CTLFLAG_RD,
96     &destroyed_not_inited, 0, "Count of labels destroyed but not inited");
97 
98 static int	ptys_equal = 0;
99 SYSCTL_INT(_security_mac_mls, OID_AUTO, ptys_equal, CTLFLAG_RW,
100     &ptys_equal, 0, "Label pty devices as mls/equal on create");
101 TUNABLE_INT("security.mac.mls.ptys_equal", &ptys_equal);
102 
103 static int	revocation_enabled = 0;
104 SYSCTL_INT(_security_mac_mls, OID_AUTO, revocation_enabled, CTLFLAG_RW,
105     &revocation_enabled, 0, "Revoke access to objects on relabel");
106 TUNABLE_INT("security.mac.mls.revocation_enabled", &revocation_enabled);
107 
108 static int	max_compartments = MAC_MLS_MAX_COMPARTMENTS;
109 SYSCTL_INT(_security_mac_mls, OID_AUTO, max_compartments, CTLFLAG_RD,
110     &max_compartments, 0, "Maximum compartments the policy supports");
111 
112 static int	mac_mls_slot;
113 #define	SLOT(l)	((struct mac_mls *)LABEL_TO_SLOT((l), mac_mls_slot).l_ptr)
114 
115 MALLOC_DEFINE(M_MACMLS, "mls label", "MAC/MLS labels");
116 
117 static __inline int
118 mls_bit_set_empty(u_char *set) {
119 	int i;
120 
121 	for (i = 0; i < MAC_MLS_MAX_COMPARTMENTS >> 3; i++)
122 		if (set[i] != 0)
123 			return (0);
124 	return (1);
125 }
126 
127 static struct mac_mls *
128 mls_alloc(int flag)
129 {
130 	struct mac_mls *mac_mls;
131 
132 	mac_mls = malloc(sizeof(struct mac_mls), M_MACMLS, M_ZERO | flag);
133 
134 	return (mac_mls);
135 }
136 
137 static void
138 mls_free(struct mac_mls *mac_mls)
139 {
140 
141 	if (mac_mls != NULL)
142 		free(mac_mls, M_MACMLS);
143 	else
144 		atomic_add_int(&destroyed_not_inited, 1);
145 }
146 
147 static int
148 mls_atmostflags(struct mac_mls *mac_mls, int flags)
149 {
150 
151 	if ((mac_mls->mm_flags & flags) != mac_mls->mm_flags)
152 		return (EINVAL);
153 	return (0);
154 }
155 
156 static int
157 mac_mls_dominate_element(struct mac_mls_element *a,
158     struct mac_mls_element *b)
159 {
160 	int bit;
161 
162 	switch (a->mme_type) {
163 	case MAC_MLS_TYPE_EQUAL:
164 	case MAC_MLS_TYPE_HIGH:
165 		return (1);
166 
167 	case MAC_MLS_TYPE_LOW:
168 		switch (b->mme_type) {
169 		case MAC_MLS_TYPE_LEVEL:
170 		case MAC_MLS_TYPE_HIGH:
171 			return (0);
172 
173 		case MAC_MLS_TYPE_EQUAL:
174 		case MAC_MLS_TYPE_LOW:
175 			return (1);
176 
177 		default:
178 			panic("mac_mls_dominate_element: b->mme_type invalid");
179 		}
180 
181 	case MAC_MLS_TYPE_LEVEL:
182 		switch (b->mme_type) {
183 		case MAC_MLS_TYPE_EQUAL:
184 		case MAC_MLS_TYPE_LOW:
185 			return (1);
186 
187 		case MAC_MLS_TYPE_HIGH:
188 			return (0);
189 
190 		case MAC_MLS_TYPE_LEVEL:
191 			for (bit = 1; bit <= MAC_MLS_MAX_COMPARTMENTS; bit++)
192 				if (!MAC_MLS_BIT_TEST(bit,
193 				    a->mme_compartments) &&
194 				    MAC_MLS_BIT_TEST(bit, b->mme_compartments))
195 					return (0);
196 			return (a->mme_level >= b->mme_level);
197 
198 		default:
199 			panic("mac_mls_dominate_element: b->mme_type invalid");
200 		}
201 
202 	default:
203 		panic("mac_mls_dominate_element: a->mme_type invalid");
204 	}
205 
206 	return (0);
207 }
208 
209 static int
210 mac_mls_range_in_range(struct mac_mls *rangea, struct mac_mls *rangeb)
211 {
212 
213 	return (mac_mls_dominate_element(&rangeb->mm_rangehigh,
214 	    &rangea->mm_rangehigh) &&
215 	    mac_mls_dominate_element(&rangea->mm_rangelow,
216 	    &rangeb->mm_rangelow));
217 }
218 
219 static int
220 mac_mls_single_in_range(struct mac_mls *single, struct mac_mls *range)
221 {
222 
223 	KASSERT((single->mm_flags & MAC_MLS_FLAG_SINGLE) != 0,
224 	    ("mac_mls_single_in_range: a not single"));
225 	KASSERT((range->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
226 	    ("mac_mls_single_in_range: b not range"));
227 
228 	return (mac_mls_dominate_element(&range->mm_rangehigh,
229 	    &single->mm_single) &&
230 	    mac_mls_dominate_element(&single->mm_single,
231 	    &range->mm_rangelow));
232 
233 	return (1);
234 }
235 
236 static int
237 mac_mls_dominate_single(struct mac_mls *a, struct mac_mls *b)
238 {
239 	KASSERT((a->mm_flags & MAC_MLS_FLAG_SINGLE) != 0,
240 	    ("mac_mls_dominate_single: a not single"));
241 	KASSERT((b->mm_flags & MAC_MLS_FLAG_SINGLE) != 0,
242 	    ("mac_mls_dominate_single: b not single"));
243 
244 	return (mac_mls_dominate_element(&a->mm_single, &b->mm_single));
245 }
246 
247 static int
248 mac_mls_equal_element(struct mac_mls_element *a, struct mac_mls_element *b)
249 {
250 
251 	if (a->mme_type == MAC_MLS_TYPE_EQUAL ||
252 	    b->mme_type == MAC_MLS_TYPE_EQUAL)
253 		return (1);
254 
255 	return (a->mme_type == b->mme_type && a->mme_level == b->mme_level);
256 }
257 
258 static int
259 mac_mls_equal_single(struct mac_mls *a, struct mac_mls *b)
260 {
261 
262 	KASSERT((a->mm_flags & MAC_MLS_FLAG_SINGLE) != 0,
263 	    ("mac_mls_equal_single: a not single"));
264 	KASSERT((b->mm_flags & MAC_MLS_FLAG_SINGLE) != 0,
265 	    ("mac_mls_equal_single: b not single"));
266 
267 	return (mac_mls_equal_element(&a->mm_single, &b->mm_single));
268 }
269 
270 static int
271 mac_mls_contains_equal(struct mac_mls *mac_mls)
272 {
273 
274 	if (mac_mls->mm_flags & MAC_MLS_FLAG_SINGLE)
275 		if (mac_mls->mm_single.mme_type == MAC_MLS_TYPE_EQUAL)
276 			return (1);
277 
278 	if (mac_mls->mm_flags & MAC_MLS_FLAG_RANGE) {
279 		if (mac_mls->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL)
280 			return (1);
281 		if (mac_mls->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
282 			return (1);
283 	}
284 
285 	return (0);
286 }
287 
288 static int
289 mac_mls_subject_equal_ok(struct mac_mls *mac_mls)
290 {
291 
292 	KASSERT((mac_mls->mm_flags & MAC_MLS_FLAGS_BOTH) == MAC_MLS_FLAGS_BOTH,
293 	    ("mac_mls_subject_equal_ok: subject doesn't have both labels"));
294 
295 	/* If the single is EQUAL, it's ok. */
296 	if (mac_mls->mm_single.mme_type == MAC_MLS_TYPE_EQUAL)
297 		return (0);
298 
299 	/* If either range endpoint is EQUAL, it's ok. */
300 	if (mac_mls->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL ||
301 	    mac_mls->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
302 		return (0);
303 
304 	/* If the range is low-high, it's ok. */
305 	if (mac_mls->mm_rangelow.mme_type == MAC_MLS_TYPE_LOW &&
306 	    mac_mls->mm_rangehigh.mme_type == MAC_MLS_TYPE_HIGH)
307 		return (0);
308 
309 	/* It's not ok. */
310 	return (EPERM);
311 }
312 
313 static int
314 mac_mls_valid(struct mac_mls *mac_mls)
315 {
316 
317 	if (mac_mls->mm_flags & MAC_MLS_FLAG_SINGLE) {
318 		switch (mac_mls->mm_single.mme_type) {
319 		case MAC_MLS_TYPE_LEVEL:
320 			break;
321 
322 		case MAC_MLS_TYPE_EQUAL:
323 		case MAC_MLS_TYPE_HIGH:
324 		case MAC_MLS_TYPE_LOW:
325 			if (mac_mls->mm_single.mme_level != 0 ||
326 			    !MAC_MLS_BIT_SET_EMPTY(
327 			    mac_mls->mm_single.mme_compartments))
328 				return (EINVAL);
329 			break;
330 
331 		default:
332 			return (EINVAL);
333 		}
334 	} else {
335 		if (mac_mls->mm_single.mme_type != MAC_MLS_TYPE_UNDEF)
336 			return (EINVAL);
337 	}
338 
339 	if (mac_mls->mm_flags & MAC_MLS_FLAG_RANGE) {
340 		switch (mac_mls->mm_rangelow.mme_type) {
341 		case MAC_MLS_TYPE_LEVEL:
342 			break;
343 
344 		case MAC_MLS_TYPE_EQUAL:
345 		case MAC_MLS_TYPE_HIGH:
346 		case MAC_MLS_TYPE_LOW:
347 			if (mac_mls->mm_rangelow.mme_level != 0 ||
348 			    !MAC_MLS_BIT_SET_EMPTY(
349 			    mac_mls->mm_rangelow.mme_compartments))
350 				return (EINVAL);
351 			break;
352 
353 		default:
354 			return (EINVAL);
355 		}
356 
357 		switch (mac_mls->mm_rangehigh.mme_type) {
358 		case MAC_MLS_TYPE_LEVEL:
359 			break;
360 
361 		case MAC_MLS_TYPE_EQUAL:
362 		case MAC_MLS_TYPE_HIGH:
363 		case MAC_MLS_TYPE_LOW:
364 			if (mac_mls->mm_rangehigh.mme_level != 0 ||
365 			    !MAC_MLS_BIT_SET_EMPTY(
366 			    mac_mls->mm_rangehigh.mme_compartments))
367 				return (EINVAL);
368 			break;
369 
370 		default:
371 			return (EINVAL);
372 		}
373 		if (!mac_mls_dominate_element(&mac_mls->mm_rangehigh,
374 		    &mac_mls->mm_rangelow))
375 			return (EINVAL);
376 	} else {
377 		if (mac_mls->mm_rangelow.mme_type != MAC_MLS_TYPE_UNDEF ||
378 		    mac_mls->mm_rangehigh.mme_type != MAC_MLS_TYPE_UNDEF)
379 			return (EINVAL);
380 	}
381 
382 	return (0);
383 }
384 
385 static void
386 mac_mls_set_range(struct mac_mls *mac_mls, u_short typelow,
387     u_short levellow, u_char *compartmentslow, u_short typehigh,
388     u_short levelhigh, u_char *compartmentshigh)
389 {
390 
391 	mac_mls->mm_rangelow.mme_type = typelow;
392 	mac_mls->mm_rangelow.mme_level = levellow;
393 	if (compartmentslow != NULL)
394 		memcpy(mac_mls->mm_rangelow.mme_compartments,
395 		    compartmentslow,
396 		    sizeof(mac_mls->mm_rangelow.mme_compartments));
397 	mac_mls->mm_rangehigh.mme_type = typehigh;
398 	mac_mls->mm_rangehigh.mme_level = levelhigh;
399 	if (compartmentshigh != NULL)
400 		memcpy(mac_mls->mm_rangehigh.mme_compartments,
401 		    compartmentshigh,
402 		    sizeof(mac_mls->mm_rangehigh.mme_compartments));
403 	mac_mls->mm_flags |= MAC_MLS_FLAG_RANGE;
404 }
405 
406 static void
407 mac_mls_set_single(struct mac_mls *mac_mls, u_short type, u_short level,
408     u_char *compartments)
409 {
410 
411 	mac_mls->mm_single.mme_type = type;
412 	mac_mls->mm_single.mme_level = level;
413 	if (compartments != NULL)
414 		memcpy(mac_mls->mm_single.mme_compartments, compartments,
415 		    sizeof(mac_mls->mm_single.mme_compartments));
416 	mac_mls->mm_flags |= MAC_MLS_FLAG_SINGLE;
417 }
418 
419 static void
420 mac_mls_copy_range(struct mac_mls *labelfrom, struct mac_mls *labelto)
421 {
422 
423 	KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
424 	    ("mac_mls_copy_range: labelfrom not range"));
425 
426 	labelto->mm_rangelow = labelfrom->mm_rangelow;
427 	labelto->mm_rangehigh = labelfrom->mm_rangehigh;
428 	labelto->mm_flags |= MAC_MLS_FLAG_RANGE;
429 }
430 
431 static void
432 mac_mls_copy_single(struct mac_mls *labelfrom, struct mac_mls *labelto)
433 {
434 
435 	KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_SINGLE) != 0,
436 	    ("mac_mls_copy_single: labelfrom not single"));
437 
438 	labelto->mm_single = labelfrom->mm_single;
439 	labelto->mm_flags |= MAC_MLS_FLAG_SINGLE;
440 }
441 
442 static void
443 mac_mls_copy(struct mac_mls *source, struct mac_mls *dest)
444 {
445 
446 	if (source->mm_flags & MAC_MLS_FLAG_SINGLE)
447 		mac_mls_copy_single(source, dest);
448 	if (source->mm_flags & MAC_MLS_FLAG_RANGE)
449 		mac_mls_copy_range(source, dest);
450 }
451 
452 /*
453  * Policy module operations.
454  */
455 static void
456 mac_mls_destroy(struct mac_policy_conf *conf)
457 {
458 
459 }
460 
461 static void
462 mac_mls_init(struct mac_policy_conf *conf)
463 {
464 
465 }
466 
467 /*
468  * Label operations.
469  */
470 static void
471 mac_mls_init_label(struct label *label)
472 {
473 
474 	SLOT(label) = mls_alloc(M_WAITOK);
475 }
476 
477 static int
478 mac_mls_init_label_waitcheck(struct label *label, int flag)
479 {
480 
481 	SLOT(label) = mls_alloc(flag);
482 	if (SLOT(label) == NULL)
483 		return (ENOMEM);
484 
485 	return (0);
486 }
487 
488 static void
489 mac_mls_destroy_label(struct label *label)
490 {
491 
492 	mls_free(SLOT(label));
493 	SLOT(label) = NULL;
494 }
495 
496 /*
497  * mac_mls_element_to_string() accepts an sbuf and MLS element.  It
498  * converts the MLS element to a string and stores the result in the
499  * sbuf; if there isn't space in the sbuf, -1 is returned.
500  */
501 static int
502 mac_mls_element_to_string(struct sbuf *sb, struct mac_mls_element *element)
503 {
504 	int i, first;
505 
506 	switch (element->mme_type) {
507 	case MAC_MLS_TYPE_HIGH:
508 		return (sbuf_printf(sb, "high"));
509 
510 	case MAC_MLS_TYPE_LOW:
511 		return (sbuf_printf(sb, "low"));
512 
513 	case MAC_MLS_TYPE_EQUAL:
514 		return (sbuf_printf(sb, "equal"));
515 
516 	case MAC_MLS_TYPE_LEVEL:
517 		if (sbuf_printf(sb, "%d", element->mme_level) == -1)
518 			return (-1);
519 
520 		first = 1;
521 		for (i = 1; i <= MAC_MLS_MAX_COMPARTMENTS; i++) {
522 			if (MAC_MLS_BIT_TEST(i, element->mme_compartments)) {
523 				if (first) {
524 					if (sbuf_putc(sb, ':') == -1)
525 						return (-1);
526 					if (sbuf_printf(sb, "%d", i) == -1)
527 						return (-1);
528 					first = 0;
529 				} else {
530 					if (sbuf_printf(sb, "+%d", i) == -1)
531 						return (-1);
532 				}
533 			}
534 		}
535 		return (0);
536 
537 	default:
538 		panic("mac_mls_element_to_string: invalid type (%d)",
539 		    element->mme_type);
540 	}
541 }
542 
543 /*
544  * mac_mls_to_string() converts an MLS label to a string, and places
545  * the results in the passed sbuf.  It returns 0 on success, or EINVAL
546  * if there isn't room in the sbuf.  Note: the sbuf will be modified
547  * even in a failure case, so the caller may need to revert the sbuf
548  * by restoring the offset if that's undesired.
549  */
550 static int
551 mac_mls_to_string(struct sbuf *sb, struct mac_mls *mac_mls)
552 {
553 
554 	if (mac_mls->mm_flags & MAC_MLS_FLAG_SINGLE) {
555 		if (mac_mls_element_to_string(sb, &mac_mls->mm_single)
556 		    == -1)
557 			return (EINVAL);
558 	}
559 
560 	if (mac_mls->mm_flags & MAC_MLS_FLAG_RANGE) {
561 		if (sbuf_putc(sb, '(') == -1)
562 			return (EINVAL);
563 
564 		if (mac_mls_element_to_string(sb, &mac_mls->mm_rangelow)
565 		    == -1)
566 			return (EINVAL);
567 
568 		if (sbuf_putc(sb, '-') == -1)
569 			return (EINVAL);
570 
571 		if (mac_mls_element_to_string(sb, &mac_mls->mm_rangehigh)
572 		    == -1)
573 			return (EINVAL);
574 
575 		if (sbuf_putc(sb, ')') == -1)
576 			return (EINVAL);
577 	}
578 
579 	return (0);
580 }
581 
582 static int
583 mac_mls_externalize_label(struct label *label, char *element_name,
584     struct sbuf *sb, int *claimed)
585 {
586 	struct mac_mls *mac_mls;
587 
588 	if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
589 		return (0);
590 
591 	(*claimed)++;
592 
593 	mac_mls = SLOT(label);
594 
595 	return (mac_mls_to_string(sb, mac_mls));
596 }
597 
598 static int
599 mac_mls_parse_element(struct mac_mls_element *element, char *string)
600 {
601 	char *compartment, *end, *level;
602 	int value;
603 
604 	if (strcmp(string, "high") == 0 ||
605 	    strcmp(string, "hi") == 0) {
606 		element->mme_type = MAC_MLS_TYPE_HIGH;
607 		element->mme_level = MAC_MLS_TYPE_UNDEF;
608 	} else if (strcmp(string, "low") == 0 ||
609 	    strcmp(string, "lo") == 0) {
610 		element->mme_type = MAC_MLS_TYPE_LOW;
611 		element->mme_level = MAC_MLS_TYPE_UNDEF;
612 	} else if (strcmp(string, "equal") == 0 ||
613 	    strcmp(string, "eq") == 0) {
614 		element->mme_type = MAC_MLS_TYPE_EQUAL;
615 		element->mme_level = MAC_MLS_TYPE_UNDEF;
616 	} else {
617 		element->mme_type = MAC_MLS_TYPE_LEVEL;
618 
619 		/*
620 		 * Numeric level piece of the element.
621 		 */
622 		level = strsep(&string, ":");
623 		value = strtol(level, &end, 10);
624 		if (end == level || *end != '\0')
625 			return (EINVAL);
626 		if (value < 0 || value > 65535)
627 			return (EINVAL);
628 		element->mme_level = value;
629 
630 		/*
631 		 * Optional compartment piece of the element.  If none
632 		 * are included, we assume that the label has no
633 		 * compartments.
634 		 */
635 		if (string == NULL)
636 			return (0);
637 		if (*string == '\0')
638 			return (0);
639 
640 		while ((compartment = strsep(&string, "+")) != NULL) {
641 			value = strtol(compartment, &end, 10);
642 			if (compartment == end || *end != '\0')
643 				return (EINVAL);
644 			if (value < 1 || value > MAC_MLS_MAX_COMPARTMENTS)
645 				return (EINVAL);
646 			MAC_MLS_BIT_SET(value, element->mme_compartments);
647 		}
648 	}
649 
650 	return (0);
651 }
652 
653 /*
654  * Note: destructively consumes the string, make a local copy before
655  * calling if that's a problem.
656  */
657 static int
658 mac_mls_parse(struct mac_mls *mac_mls, char *string)
659 {
660 	char *rangehigh, *rangelow, *single;
661 	int error;
662 
663 	single = strsep(&string, "(");
664 	if (*single == '\0')
665 		single = NULL;
666 
667 	if (string != NULL) {
668 		rangelow = strsep(&string, "-");
669 		if (string == NULL)
670 			return (EINVAL);
671 		rangehigh = strsep(&string, ")");
672 		if (string == NULL)
673 			return (EINVAL);
674 		if (*string != '\0')
675 			return (EINVAL);
676 	} else {
677 		rangelow = NULL;
678 		rangehigh = NULL;
679 	}
680 
681 	KASSERT((rangelow != NULL && rangehigh != NULL) ||
682 	    (rangelow == NULL && rangehigh == NULL),
683 	    ("mac_mls_parse: range mismatch"));
684 
685 	bzero(mac_mls, sizeof(*mac_mls));
686 	if (single != NULL) {
687 		error = mac_mls_parse_element(&mac_mls->mm_single, single);
688 		if (error)
689 			return (error);
690 		mac_mls->mm_flags |= MAC_MLS_FLAG_SINGLE;
691 	}
692 
693 	if (rangelow != NULL) {
694 		error = mac_mls_parse_element(&mac_mls->mm_rangelow,
695 		    rangelow);
696 		if (error)
697 			return (error);
698 		error = mac_mls_parse_element(&mac_mls->mm_rangehigh,
699 		    rangehigh);
700 		if (error)
701 			return (error);
702 		mac_mls->mm_flags |= MAC_MLS_FLAG_RANGE;
703 	}
704 
705 	error = mac_mls_valid(mac_mls);
706 	if (error)
707 		return (error);
708 
709 	return (0);
710 }
711 
712 static int
713 mac_mls_internalize_label(struct label *label, char *element_name,
714     char *element_data, int *claimed)
715 {
716 	struct mac_mls *mac_mls, mac_mls_temp;
717 	int error;
718 
719 	if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
720 		return (0);
721 
722 	(*claimed)++;
723 
724 	error = mac_mls_parse(&mac_mls_temp, element_data);
725 	if (error)
726 		return (error);
727 
728 	mac_mls = SLOT(label);
729 	*mac_mls = mac_mls_temp;
730 
731 	return (0);
732 }
733 
734 static void
735 mac_mls_copy_label(struct label *src, struct label *dest)
736 {
737 
738 	*SLOT(dest) = *SLOT(src);
739 }
740 
741 /*
742  * Labeling event operations: file system objects, and things that look
743  * a lot like file system objects.
744  */
745 static void
746 mac_mls_create_devfs_device(struct mount *mp, dev_t dev,
747     struct devfs_dirent *devfs_dirent, struct label *label)
748 {
749 	struct mac_mls *mac_mls;
750 	int mls_type;
751 
752 	mac_mls = SLOT(label);
753 	if (strcmp(dev->si_name, "null") == 0 ||
754 	    strcmp(dev->si_name, "zero") == 0 ||
755 	    strcmp(dev->si_name, "random") == 0 ||
756 	    strncmp(dev->si_name, "fd/", strlen("fd/")) == 0)
757 		mls_type = MAC_MLS_TYPE_EQUAL;
758 	else if (strcmp(dev->si_name, "kmem") == 0 ||
759 	    strcmp(dev->si_name, "mem") == 0)
760 		mls_type = MAC_MLS_TYPE_HIGH;
761 	else if (ptys_equal &&
762 	    (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
763 	    strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
764 		mls_type = MAC_MLS_TYPE_EQUAL;
765 	else
766 		mls_type = MAC_MLS_TYPE_LOW;
767 	mac_mls_set_single(mac_mls, mls_type, 0, NULL);
768 }
769 
770 static void
771 mac_mls_create_devfs_directory(struct mount *mp, char *dirname,
772     int dirnamelen, struct devfs_dirent *devfs_dirent, struct label *label)
773 {
774 	struct mac_mls *mac_mls;
775 
776 	mac_mls = SLOT(label);
777 	mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL);
778 }
779 
780 static void
781 mac_mls_create_devfs_symlink(struct ucred *cred, struct mount *mp,
782     struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
783     struct label *delabel)
784 {
785 	struct mac_mls *source, *dest;
786 
787 	source = SLOT(&cred->cr_label);
788 	dest = SLOT(delabel);
789 
790 	mac_mls_copy_single(source, dest);
791 }
792 
793 static void
794 mac_mls_create_mount(struct ucred *cred, struct mount *mp,
795     struct label *mntlabel, struct label *fslabel)
796 {
797 	struct mac_mls *source, *dest;
798 
799 	source = SLOT(&cred->cr_label);
800 	dest = SLOT(mntlabel);
801 	mac_mls_copy_single(source, dest);
802 	dest = SLOT(fslabel);
803 	mac_mls_copy_single(source, dest);
804 }
805 
806 static void
807 mac_mls_create_root_mount(struct ucred *cred, struct mount *mp,
808     struct label *mntlabel, struct label *fslabel)
809 {
810 	struct mac_mls *mac_mls;
811 
812 	/* Always mount root as high integrity. */
813 	mac_mls = SLOT(fslabel);
814 	mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL);
815 	mac_mls = SLOT(mntlabel);
816 	mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL);
817 }
818 
819 static void
820 mac_mls_relabel_vnode(struct ucred *cred, struct vnode *vp,
821     struct label *vnodelabel, struct label *label)
822 {
823 	struct mac_mls *source, *dest;
824 
825 	source = SLOT(label);
826 	dest = SLOT(vnodelabel);
827 
828 	mac_mls_copy(source, dest);
829 }
830 
831 static void
832 mac_mls_update_devfsdirent(struct mount *mp,
833     struct devfs_dirent *devfs_dirent, struct label *direntlabel,
834     struct vnode *vp, struct label *vnodelabel)
835 {
836 	struct mac_mls *source, *dest;
837 
838 	source = SLOT(vnodelabel);
839 	dest = SLOT(direntlabel);
840 
841 	mac_mls_copy_single(source, dest);
842 }
843 
844 static void
845 mac_mls_associate_vnode_devfs(struct mount *mp, struct label *fslabel,
846     struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
847     struct label *vlabel)
848 {
849 	struct mac_mls *source, *dest;
850 
851 	source = SLOT(delabel);
852 	dest = SLOT(vlabel);
853 
854 	mac_mls_copy_single(source, dest);
855 }
856 
857 static int
858 mac_mls_associate_vnode_extattr(struct mount *mp, struct label *fslabel,
859     struct vnode *vp, struct label *vlabel)
860 {
861 	struct mac_mls temp, *source, *dest;
862 	int buflen, error;
863 
864 	source = SLOT(fslabel);
865 	dest = SLOT(vlabel);
866 
867 	buflen = sizeof(temp);
868 	bzero(&temp, buflen);
869 
870 	error = vn_extattr_get(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
871 	    MAC_MLS_EXTATTR_NAME, &buflen, (char *) &temp, curthread);
872 	if (error == ENOATTR || error == EOPNOTSUPP) {
873 		/* Fall back to the fslabel. */
874 		mac_mls_copy_single(source, dest);
875 		return (0);
876 	} else if (error)
877 		return (error);
878 
879 	if (buflen != sizeof(temp)) {
880 		printf("mac_mls_associate_vnode_extattr: bad size %d\n",
881 		    buflen);
882 		return (EPERM);
883 	}
884 	if (mac_mls_valid(&temp) != 0) {
885 		printf("mac_mls_associate_vnode_extattr: invalid\n");
886 		return (EPERM);
887 	}
888 	if ((temp.mm_flags & MAC_MLS_FLAGS_BOTH) != MAC_MLS_FLAG_SINGLE) {
889 		printf("mac_mls_associated_vnode_extattr: not single\n");
890 		return (EPERM);
891 	}
892 
893 	mac_mls_copy_single(&temp, dest);
894 	return (0);
895 }
896 
897 static void
898 mac_mls_associate_vnode_singlelabel(struct mount *mp,
899     struct label *fslabel, struct vnode *vp, struct label *vlabel)
900 {
901 	struct mac_mls *source, *dest;
902 
903 	source = SLOT(fslabel);
904 	dest = SLOT(vlabel);
905 
906 	mac_mls_copy_single(source, dest);
907 }
908 
909 static int
910 mac_mls_create_vnode_extattr(struct ucred *cred, struct mount *mp,
911     struct label *fslabel, struct vnode *dvp, struct label *dlabel,
912     struct vnode *vp, struct label *vlabel, struct componentname *cnp)
913 {
914 	struct mac_mls *source, *dest, temp;
915 	size_t buflen;
916 	int error;
917 
918 	buflen = sizeof(temp);
919 	bzero(&temp, buflen);
920 
921 	source = SLOT(&cred->cr_label);
922 	dest = SLOT(vlabel);
923 	mac_mls_copy_single(source, &temp);
924 
925 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
926 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &temp, curthread);
927 	if (error == 0)
928 		mac_mls_copy_single(source, dest);
929 	return (error);
930 }
931 
932 static int
933 mac_mls_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp,
934     struct label *vlabel, struct label *intlabel)
935 {
936 	struct mac_mls *source, temp;
937 	size_t buflen;
938 	int error;
939 
940 	buflen = sizeof(temp);
941 	bzero(&temp, buflen);
942 
943 	source = SLOT(intlabel);
944 	if ((source->mm_flags & MAC_MLS_FLAG_SINGLE) == 0)
945 		return (0);
946 
947 	mac_mls_copy_single(source, &temp);
948 
949 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
950 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &temp, curthread);
951 	return (error);
952 }
953 
954 /*
955  * Labeling event operations: IPC object.
956  */
957 static void
958 mac_mls_create_mbuf_from_socket(struct socket *so, struct label *socketlabel,
959     struct mbuf *m, struct label *mbuflabel)
960 {
961 	struct mac_mls *source, *dest;
962 
963 	source = SLOT(socketlabel);
964 	dest = SLOT(mbuflabel);
965 
966 	mac_mls_copy_single(source, dest);
967 }
968 
969 static void
970 mac_mls_create_socket(struct ucred *cred, struct socket *socket,
971     struct label *socketlabel)
972 {
973 	struct mac_mls *source, *dest;
974 
975 	source = SLOT(&cred->cr_label);
976 	dest = SLOT(socketlabel);
977 
978 	mac_mls_copy_single(source, dest);
979 }
980 
981 static void
982 mac_mls_create_pipe(struct ucred *cred, struct pipe *pipe,
983     struct label *pipelabel)
984 {
985 	struct mac_mls *source, *dest;
986 
987 	source = SLOT(&cred->cr_label);
988 	dest = SLOT(pipelabel);
989 
990 	mac_mls_copy_single(source, dest);
991 }
992 
993 static void
994 mac_mls_create_socket_from_socket(struct socket *oldsocket,
995     struct label *oldsocketlabel, struct socket *newsocket,
996     struct label *newsocketlabel)
997 {
998 	struct mac_mls *source, *dest;
999 
1000 	source = SLOT(oldsocketlabel);
1001 	dest = SLOT(newsocketlabel);
1002 
1003 	mac_mls_copy_single(source, dest);
1004 }
1005 
1006 static void
1007 mac_mls_relabel_socket(struct ucred *cred, struct socket *socket,
1008     struct label *socketlabel, struct label *newlabel)
1009 {
1010 	struct mac_mls *source, *dest;
1011 
1012 	source = SLOT(newlabel);
1013 	dest = SLOT(socketlabel);
1014 
1015 	mac_mls_copy(source, dest);
1016 }
1017 
1018 static void
1019 mac_mls_relabel_pipe(struct ucred *cred, struct pipe *pipe,
1020     struct label *pipelabel, struct label *newlabel)
1021 {
1022 	struct mac_mls *source, *dest;
1023 
1024 	source = SLOT(newlabel);
1025 	dest = SLOT(pipelabel);
1026 
1027 	mac_mls_copy(source, dest);
1028 }
1029 
1030 static void
1031 mac_mls_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel,
1032     struct socket *socket, struct label *socketpeerlabel)
1033 {
1034 	struct mac_mls *source, *dest;
1035 
1036 	source = SLOT(mbuflabel);
1037 	dest = SLOT(socketpeerlabel);
1038 
1039 	mac_mls_copy_single(source, dest);
1040 }
1041 
1042 /*
1043  * Labeling event operations: network objects.
1044  */
1045 static void
1046 mac_mls_set_socket_peer_from_socket(struct socket *oldsocket,
1047     struct label *oldsocketlabel, struct socket *newsocket,
1048     struct label *newsocketpeerlabel)
1049 {
1050 	struct mac_mls *source, *dest;
1051 
1052 	source = SLOT(oldsocketlabel);
1053 	dest = SLOT(newsocketpeerlabel);
1054 
1055 	mac_mls_copy_single(source, dest);
1056 }
1057 
1058 static void
1059 mac_mls_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d,
1060     struct label *bpflabel)
1061 {
1062 	struct mac_mls *source, *dest;
1063 
1064 	source = SLOT(&cred->cr_label);
1065 	dest = SLOT(bpflabel);
1066 
1067 	mac_mls_copy_single(source, dest);
1068 }
1069 
1070 static void
1071 mac_mls_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel)
1072 {
1073 	struct mac_mls *dest;
1074 	int type;
1075 
1076 	dest = SLOT(ifnetlabel);
1077 
1078 	if (ifnet->if_type == IFT_LOOP)
1079 		type = MAC_MLS_TYPE_EQUAL;
1080 	else
1081 		type = MAC_MLS_TYPE_LOW;
1082 
1083 	mac_mls_set_single(dest, type, 0, NULL);
1084 	mac_mls_set_range(dest, type, 0, NULL, type, 0, NULL);
1085 }
1086 
1087 static void
1088 mac_mls_create_ipq(struct mbuf *fragment, struct label *fragmentlabel,
1089     struct ipq *ipq, struct label *ipqlabel)
1090 {
1091 	struct mac_mls *source, *dest;
1092 
1093 	source = SLOT(fragmentlabel);
1094 	dest = SLOT(ipqlabel);
1095 
1096 	mac_mls_copy_single(source, dest);
1097 }
1098 
1099 static void
1100 mac_mls_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel,
1101     struct mbuf *datagram, struct label *datagramlabel)
1102 {
1103 	struct mac_mls *source, *dest;
1104 
1105 	source = SLOT(ipqlabel);
1106 	dest = SLOT(datagramlabel);
1107 
1108 	/* Just use the head, since we require them all to match. */
1109 	mac_mls_copy_single(source, dest);
1110 }
1111 
1112 static void
1113 mac_mls_create_fragment(struct mbuf *datagram, struct label *datagramlabel,
1114     struct mbuf *fragment, struct label *fragmentlabel)
1115 {
1116 	struct mac_mls *source, *dest;
1117 
1118 	source = SLOT(datagramlabel);
1119 	dest = SLOT(fragmentlabel);
1120 
1121 	mac_mls_copy_single(source, dest);
1122 }
1123 
1124 static void
1125 mac_mls_create_mbuf_from_mbuf(struct mbuf *oldmbuf,
1126     struct label *oldmbuflabel, struct mbuf *newmbuf,
1127     struct label *newmbuflabel)
1128 {
1129 	struct mac_mls *source, *dest;
1130 
1131 	source = SLOT(oldmbuflabel);
1132 	dest = SLOT(newmbuflabel);
1133 
1134 	/*
1135 	 * Because the source mbuf may not yet have been "created",
1136 	 * just initialized, we do a conditional copy.  Since we don't
1137 	 * allow mbufs to have ranges, do a KASSERT to make sure that
1138 	 * doesn't happen.
1139 	 */
1140 	KASSERT((source->mm_flags & MAC_MLS_FLAG_RANGE) == 0,
1141 	    ("mac_mls_create_mbuf_from_mbuf: source mbuf has range"));
1142 	mac_mls_copy(source, dest);
1143 }
1144 
1145 static void
1146 mac_mls_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel,
1147     struct mbuf *mbuf, struct label *mbuflabel)
1148 {
1149 	struct mac_mls *dest;
1150 
1151 	dest = SLOT(mbuflabel);
1152 
1153 	mac_mls_set_single(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1154 }
1155 
1156 static void
1157 mac_mls_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel,
1158     struct mbuf *mbuf, struct label *mbuflabel)
1159 {
1160 	struct mac_mls *source, *dest;
1161 
1162 	source = SLOT(bpflabel);
1163 	dest = SLOT(mbuflabel);
1164 
1165 	mac_mls_copy_single(source, dest);
1166 }
1167 
1168 static void
1169 mac_mls_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel,
1170     struct mbuf *m, struct label *mbuflabel)
1171 {
1172 	struct mac_mls *source, *dest;
1173 
1174 	source = SLOT(ifnetlabel);
1175 	dest = SLOT(mbuflabel);
1176 
1177 	mac_mls_copy_single(source, dest);
1178 }
1179 
1180 static void
1181 mac_mls_create_mbuf_multicast_encap(struct mbuf *oldmbuf,
1182     struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel,
1183     struct mbuf *newmbuf, struct label *newmbuflabel)
1184 {
1185 	struct mac_mls *source, *dest;
1186 
1187 	source = SLOT(oldmbuflabel);
1188 	dest = SLOT(newmbuflabel);
1189 
1190 	mac_mls_copy_single(source, dest);
1191 }
1192 
1193 static void
1194 mac_mls_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel,
1195     struct mbuf *newmbuf, struct label *newmbuflabel)
1196 {
1197 	struct mac_mls *source, *dest;
1198 
1199 	source = SLOT(oldmbuflabel);
1200 	dest = SLOT(newmbuflabel);
1201 
1202 	mac_mls_copy_single(source, dest);
1203 }
1204 
1205 static int
1206 mac_mls_fragment_match(struct mbuf *fragment, struct label *fragmentlabel,
1207     struct ipq *ipq, struct label *ipqlabel)
1208 {
1209 	struct mac_mls *a, *b;
1210 
1211 	a = SLOT(ipqlabel);
1212 	b = SLOT(fragmentlabel);
1213 
1214 	return (mac_mls_equal_single(a, b));
1215 }
1216 
1217 static void
1218 mac_mls_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet,
1219     struct label *ifnetlabel, struct label *newlabel)
1220 {
1221 	struct mac_mls *source, *dest;
1222 
1223 	source = SLOT(newlabel);
1224 	dest = SLOT(ifnetlabel);
1225 
1226 	mac_mls_copy(source, dest);
1227 }
1228 
1229 static void
1230 mac_mls_update_ipq(struct mbuf *fragment, struct label *fragmentlabel,
1231     struct ipq *ipq, struct label *ipqlabel)
1232 {
1233 
1234 	/* NOOP: we only accept matching labels, so no need to update */
1235 }
1236 
1237 /*
1238  * Labeling event operations: processes.
1239  */
1240 static void
1241 mac_mls_create_cred(struct ucred *cred_parent, struct ucred *cred_child)
1242 {
1243 	struct mac_mls *source, *dest;
1244 
1245 	source = SLOT(&cred_parent->cr_label);
1246 	dest = SLOT(&cred_child->cr_label);
1247 
1248 	mac_mls_copy_single(source, dest);
1249 	mac_mls_copy_range(source, dest);
1250 }
1251 
1252 static void
1253 mac_mls_create_proc0(struct ucred *cred)
1254 {
1255 	struct mac_mls *dest;
1256 
1257 	dest = SLOT(&cred->cr_label);
1258 
1259 	mac_mls_set_single(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1260 	mac_mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH,
1261 	    0, NULL);
1262 }
1263 
1264 static void
1265 mac_mls_create_proc1(struct ucred *cred)
1266 {
1267 	struct mac_mls *dest;
1268 
1269 	dest = SLOT(&cred->cr_label);
1270 
1271 	mac_mls_set_single(dest, MAC_MLS_TYPE_LOW, 0, NULL);
1272 	mac_mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH,
1273 	    0, NULL);
1274 }
1275 
1276 static void
1277 mac_mls_relabel_cred(struct ucred *cred, struct label *newlabel)
1278 {
1279 	struct mac_mls *source, *dest;
1280 
1281 	source = SLOT(newlabel);
1282 	dest = SLOT(&cred->cr_label);
1283 
1284 	mac_mls_copy(source, dest);
1285 }
1286 
1287 /*
1288  * Access control checks.
1289  */
1290 static int
1291 mac_mls_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel,
1292      struct ifnet *ifnet, struct label *ifnetlabel)
1293 {
1294 	struct mac_mls *a, *b;
1295 
1296 	if (!mac_mls_enabled)
1297 		return (0);
1298 
1299 	a = SLOT(bpflabel);
1300 	b = SLOT(ifnetlabel);
1301 
1302 	if (mac_mls_equal_single(a, b))
1303 		return (0);
1304 	return (EACCES);
1305 }
1306 
1307 static int
1308 mac_mls_check_cred_relabel(struct ucred *cred, struct label *newlabel)
1309 {
1310 	struct mac_mls *subj, *new;
1311 	int error;
1312 
1313 	subj = SLOT(&cred->cr_label);
1314 	new = SLOT(newlabel);
1315 
1316 	/*
1317 	 * If there is an MLS label update for the credential, it may be
1318 	 * an update of single, range, or both.
1319 	 */
1320 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
1321 	if (error)
1322 		return (error);
1323 
1324 	/*
1325 	 * If the MLS label is to be changed, authorize as appropriate.
1326 	 */
1327 	if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
1328 		/*
1329 		 * If the change request modifies both the MLS label single
1330 		 * and range, check that the new single will be in the
1331 		 * new range.
1332 		 */
1333 		if ((new->mm_flags & MAC_MLS_FLAGS_BOTH) ==
1334 		    MAC_MLS_FLAGS_BOTH &&
1335 		    !mac_mls_single_in_range(new, new))
1336 			return (EINVAL);
1337 
1338 		/*
1339 		 * To change the MLS single label on a credential, the
1340 		 * new single label must be in the current range.
1341 		 */
1342 		if (new->mm_flags & MAC_MLS_FLAG_SINGLE &&
1343 		    !mac_mls_single_in_range(new, subj))
1344 			return (EPERM);
1345 
1346 		/*
1347 		 * To change the MLS range label on a credential, the
1348 		 * new range must be in the current range.
1349 		 */
1350 		if (new->mm_flags & MAC_MLS_FLAG_RANGE &&
1351 		    !mac_mls_range_in_range(new, subj))
1352 			return (EPERM);
1353 
1354 		/*
1355 		 * To have EQUAL in any component of the new credential
1356 		 * MLS label, the subject must already have EQUAL in
1357 		 * their label.
1358 		 */
1359 		if (mac_mls_contains_equal(new)) {
1360 			error = mac_mls_subject_equal_ok(subj);
1361 			if (error)
1362 				return (error);
1363 		}
1364 	}
1365 
1366 	return (0);
1367 }
1368 
1369 static int
1370 mac_mls_check_cred_visible(struct ucred *u1, struct ucred *u2)
1371 {
1372 	struct mac_mls *subj, *obj;
1373 
1374 	if (!mac_mls_enabled)
1375 		return (0);
1376 
1377 	subj = SLOT(&u1->cr_label);
1378 	obj = SLOT(&u2->cr_label);
1379 
1380 	/* XXX: range */
1381 	if (!mac_mls_dominate_single(subj, obj))
1382 		return (ESRCH);
1383 
1384 	return (0);
1385 }
1386 
1387 static int
1388 mac_mls_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet,
1389     struct label *ifnetlabel, struct label *newlabel)
1390 {
1391 	struct mac_mls *subj, *new;
1392 	int error;
1393 
1394 	subj = SLOT(&cred->cr_label);
1395 	new = SLOT(newlabel);
1396 
1397 	/*
1398 	 * If there is an MLS label update for the interface, it may
1399 	 * be an update of single, range, or both.
1400 	 */
1401 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
1402 	if (error)
1403 		return (error);
1404 
1405 	/*
1406 	 * If the MLS label is to be changed, authorize as appropriate.
1407 	 */
1408 	if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
1409 		/*
1410 		 * Rely on traditional superuser status for the MLS
1411 		 * interface relabel requirements.  XXX: This will go
1412 		 * away.
1413 		 */
1414 		error = suser_cred(cred, 0);
1415 		if (error)
1416 			return (EPERM);
1417 
1418 		/*
1419 		 * XXXMAC: Additional consistency tests regarding the single
1420 		 * and the range of the new label might be performed here.
1421 		 */
1422 	}
1423 
1424 	return (0);
1425 }
1426 
1427 static int
1428 mac_mls_check_ifnet_transmit(struct ifnet *ifnet, struct label *ifnetlabel,
1429     struct mbuf *m, struct label *mbuflabel)
1430 {
1431 	struct mac_mls *p, *i;
1432 
1433 	if (!mac_mls_enabled)
1434 		return (0);
1435 
1436 	p = SLOT(mbuflabel);
1437 	i = SLOT(ifnetlabel);
1438 
1439 	return (mac_mls_single_in_range(p, i) ? 0 : EACCES);
1440 }
1441 
1442 static int
1443 mac_mls_check_mount_stat(struct ucred *cred, struct mount *mp,
1444     struct label *mntlabel)
1445 {
1446 	struct mac_mls *subj, *obj;
1447 
1448 	if (!mac_mls_enabled)
1449 		return (0);
1450 
1451 	subj = SLOT(&cred->cr_label);
1452 	obj = SLOT(mntlabel);
1453 
1454 	if (!mac_mls_dominate_single(subj, obj))
1455 		return (EACCES);
1456 
1457 	return (0);
1458 }
1459 
1460 static int
1461 mac_mls_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe,
1462     struct label *pipelabel, unsigned long cmd, void /* caddr_t */ *data)
1463 {
1464 
1465 	if(!mac_mls_enabled)
1466 		return (0);
1467 
1468 	/* XXX: This will be implemented soon... */
1469 
1470 	return (0);
1471 }
1472 
1473 static int
1474 mac_mls_check_pipe_poll(struct ucred *cred, struct pipe *pipe,
1475     struct label *pipelabel)
1476 {
1477 	struct mac_mls *subj, *obj;
1478 
1479 	if (!mac_mls_enabled)
1480 		return (0);
1481 
1482 	subj = SLOT(&cred->cr_label);
1483 	obj = SLOT((pipelabel));
1484 
1485 	if (!mac_mls_dominate_single(subj, obj))
1486 		return (EACCES);
1487 
1488 	return (0);
1489 }
1490 
1491 static int
1492 mac_mls_check_pipe_read(struct ucred *cred, struct pipe *pipe,
1493     struct label *pipelabel)
1494 {
1495 	struct mac_mls *subj, *obj;
1496 
1497 	if (!mac_mls_enabled)
1498 		return (0);
1499 
1500 	subj = SLOT(&cred->cr_label);
1501 	obj = SLOT((pipelabel));
1502 
1503 	if (!mac_mls_dominate_single(subj, obj))
1504 		return (EACCES);
1505 
1506 	return (0);
1507 }
1508 
1509 static int
1510 mac_mls_check_pipe_relabel(struct ucred *cred, struct pipe *pipe,
1511     struct label *pipelabel, struct label *newlabel)
1512 {
1513 	struct mac_mls *subj, *obj, *new;
1514 	int error;
1515 
1516 	new = SLOT(newlabel);
1517 	subj = SLOT(&cred->cr_label);
1518 	obj = SLOT(pipelabel);
1519 
1520 	/*
1521 	 * If there is an MLS label update for a pipe, it must be a
1522 	 * single update.
1523 	 */
1524 	error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE);
1525 	if (error)
1526 		return (error);
1527 
1528 	/*
1529 	 * To perform a relabel of a pipe (MLS label or not), MLS must
1530 	 * authorize the relabel.
1531 	 */
1532 	if (!mac_mls_single_in_range(obj, subj))
1533 		return (EPERM);
1534 
1535 	/*
1536 	 * If the MLS label is to be changed, authorize as appropriate.
1537 	 */
1538 	if (new->mm_flags & MAC_MLS_FLAG_SINGLE) {
1539 		/*
1540 		 * To change the MLS label on a pipe, the new pipe label
1541 		 * must be in the subject range.
1542 		 */
1543 		if (!mac_mls_single_in_range(new, subj))
1544 			return (EPERM);
1545 
1546 		/*
1547 		 * To change the MLS label on a pipe to be EQUAL, the
1548 		 * subject must have appropriate privilege.
1549 		 */
1550 		if (mac_mls_contains_equal(new)) {
1551 			error = mac_mls_subject_equal_ok(subj);
1552 			if (error)
1553 				return (error);
1554 		}
1555 	}
1556 
1557 	return (0);
1558 }
1559 
1560 static int
1561 mac_mls_check_pipe_stat(struct ucred *cred, struct pipe *pipe,
1562     struct label *pipelabel)
1563 {
1564 	struct mac_mls *subj, *obj;
1565 
1566 	if (!mac_mls_enabled)
1567 		return (0);
1568 
1569 	subj = SLOT(&cred->cr_label);
1570 	obj = SLOT((pipelabel));
1571 
1572 	if (!mac_mls_dominate_single(subj, obj))
1573 		return (EACCES);
1574 
1575 	return (0);
1576 }
1577 
1578 static int
1579 mac_mls_check_pipe_write(struct ucred *cred, struct pipe *pipe,
1580     struct label *pipelabel)
1581 {
1582 	struct mac_mls *subj, *obj;
1583 
1584 	if (!mac_mls_enabled)
1585 		return (0);
1586 
1587 	subj = SLOT(&cred->cr_label);
1588 	obj = SLOT((pipelabel));
1589 
1590 	if (!mac_mls_dominate_single(obj, subj))
1591 		return (EACCES);
1592 
1593 	return (0);
1594 }
1595 
1596 static int
1597 mac_mls_check_proc_debug(struct ucred *cred, struct proc *proc)
1598 {
1599 	struct mac_mls *subj, *obj;
1600 
1601 	if (!mac_mls_enabled)
1602 		return (0);
1603 
1604 	subj = SLOT(&cred->cr_label);
1605 	obj = SLOT(&proc->p_ucred->cr_label);
1606 
1607 	/* XXX: range checks */
1608 	if (!mac_mls_dominate_single(subj, obj))
1609 		return (ESRCH);
1610 	if (!mac_mls_dominate_single(obj, subj))
1611 		return (EACCES);
1612 
1613 	return (0);
1614 }
1615 
1616 static int
1617 mac_mls_check_proc_sched(struct ucred *cred, struct proc *proc)
1618 {
1619 	struct mac_mls *subj, *obj;
1620 
1621 	if (!mac_mls_enabled)
1622 		return (0);
1623 
1624 	subj = SLOT(&cred->cr_label);
1625 	obj = SLOT(&proc->p_ucred->cr_label);
1626 
1627 	/* XXX: range checks */
1628 	if (!mac_mls_dominate_single(subj, obj))
1629 		return (ESRCH);
1630 	if (!mac_mls_dominate_single(obj, subj))
1631 		return (EACCES);
1632 
1633 	return (0);
1634 }
1635 
1636 static int
1637 mac_mls_check_proc_signal(struct ucred *cred, struct proc *proc, int signum)
1638 {
1639 	struct mac_mls *subj, *obj;
1640 
1641 	if (!mac_mls_enabled)
1642 		return (0);
1643 
1644 	subj = SLOT(&cred->cr_label);
1645 	obj = SLOT(&proc->p_ucred->cr_label);
1646 
1647 	/* XXX: range checks */
1648 	if (!mac_mls_dominate_single(subj, obj))
1649 		return (ESRCH);
1650 	if (!mac_mls_dominate_single(obj, subj))
1651 		return (EACCES);
1652 
1653 	return (0);
1654 }
1655 
1656 static int
1657 mac_mls_check_socket_deliver(struct socket *so, struct label *socketlabel,
1658     struct mbuf *m, struct label *mbuflabel)
1659 {
1660 	struct mac_mls *p, *s;
1661 
1662 	if (!mac_mls_enabled)
1663 		return (0);
1664 
1665 	p = SLOT(mbuflabel);
1666 	s = SLOT(socketlabel);
1667 
1668 	return (mac_mls_equal_single(p, s) ? 0 : EACCES);
1669 }
1670 
1671 static int
1672 mac_mls_check_socket_relabel(struct ucred *cred, struct socket *socket,
1673     struct label *socketlabel, struct label *newlabel)
1674 {
1675 	struct mac_mls *subj, *obj, *new;
1676 	int error;
1677 
1678 	new = SLOT(newlabel);
1679 	subj = SLOT(&cred->cr_label);
1680 	obj = SLOT(socketlabel);
1681 
1682 	/*
1683 	 * If there is an MLS label update for the socket, it may be
1684 	 * an update of single.
1685 	 */
1686 	error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE);
1687 	if (error)
1688 		return (error);
1689 
1690 	/*
1691 	 * To relabel a socket, the old socket single must be in the subject
1692 	 * range.
1693 	 */
1694 	if (!mac_mls_single_in_range(obj, subj))
1695 		return (EPERM);
1696 
1697 	/*
1698 	 * If the MLS label is to be changed, authorize as appropriate.
1699 	 */
1700 	if (new->mm_flags & MAC_MLS_FLAG_SINGLE) {
1701 		/*
1702 		 * To relabel a socket, the new socket single must be in
1703 		 * the subject range.
1704 		 */
1705 		if (!mac_mls_single_in_range(new, subj))
1706 			return (EPERM);
1707 
1708 		/*
1709 		 * To change the MLS label on the socket to contain EQUAL,
1710 		 * the subject must have appropriate privilege.
1711 		 */
1712 		if (mac_mls_contains_equal(new)) {
1713 			error = mac_mls_subject_equal_ok(subj);
1714 			if (error)
1715 				return (error);
1716 		}
1717 	}
1718 
1719 	return (0);
1720 }
1721 
1722 static int
1723 mac_mls_check_socket_visible(struct ucred *cred, struct socket *socket,
1724     struct label *socketlabel)
1725 {
1726 	struct mac_mls *subj, *obj;
1727 
1728 	if (!mac_mls_enabled)
1729 		return (0);
1730 
1731 	subj = SLOT(&cred->cr_label);
1732 	obj = SLOT(socketlabel);
1733 
1734 	if (!mac_mls_dominate_single(subj, obj))
1735 		return (ENOENT);
1736 
1737 	return (0);
1738 }
1739 
1740 static int
1741 mac_mls_check_system_swapon(struct ucred *cred, struct vnode *vp,
1742     struct label *label)
1743 {
1744 	struct mac_mls *subj, *obj;
1745 
1746 	if (!mac_mls_enabled)
1747 		return (0);
1748 
1749 	subj = SLOT(&cred->cr_label);
1750 	obj = SLOT(label);
1751 
1752 	if (!mac_mls_dominate_single(obj, subj) ||
1753 	    !mac_mls_dominate_single(subj, obj))
1754 		return (EACCES);
1755 
1756 	return (0);
1757 }
1758 
1759 static int
1760 mac_mls_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
1761     struct label *dlabel)
1762 {
1763 	struct mac_mls *subj, *obj;
1764 
1765 	if (!mac_mls_enabled)
1766 		return (0);
1767 
1768 	subj = SLOT(&cred->cr_label);
1769 	obj = SLOT(dlabel);
1770 
1771 	if (!mac_mls_dominate_single(subj, obj))
1772 		return (EACCES);
1773 
1774 	return (0);
1775 }
1776 
1777 static int
1778 mac_mls_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
1779     struct label *dlabel)
1780 {
1781 	struct mac_mls *subj, *obj;
1782 
1783 	if (!mac_mls_enabled)
1784 		return (0);
1785 
1786 	subj = SLOT(&cred->cr_label);
1787 	obj = SLOT(dlabel);
1788 
1789 	if (!mac_mls_dominate_single(subj, obj))
1790 		return (EACCES);
1791 
1792 	return (0);
1793 }
1794 
1795 static int
1796 mac_mls_check_vnode_create(struct ucred *cred, struct vnode *dvp,
1797     struct label *dlabel, struct componentname *cnp, struct vattr *vap)
1798 {
1799 	struct mac_mls *subj, *obj;
1800 
1801 	if (!mac_mls_enabled)
1802 		return (0);
1803 
1804 	subj = SLOT(&cred->cr_label);
1805 	obj = SLOT(dlabel);
1806 
1807 	if (!mac_mls_dominate_single(obj, subj))
1808 		return (EACCES);
1809 
1810 	return (0);
1811 }
1812 
1813 static int
1814 mac_mls_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
1815     struct label *dlabel, struct vnode *vp, struct label *label,
1816     struct componentname *cnp)
1817 {
1818 	struct mac_mls *subj, *obj;
1819 
1820 	if (!mac_mls_enabled)
1821 		return (0);
1822 
1823 	subj = SLOT(&cred->cr_label);
1824 	obj = SLOT(dlabel);
1825 
1826 	if (!mac_mls_dominate_single(obj, subj))
1827 		return (EACCES);
1828 
1829 	obj = SLOT(label);
1830 
1831 	if (!mac_mls_dominate_single(obj, subj))
1832 		return (EACCES);
1833 
1834 	return (0);
1835 }
1836 
1837 static int
1838 mac_mls_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
1839     struct label *label, acl_type_t type)
1840 {
1841 	struct mac_mls *subj, *obj;
1842 
1843 	if (!mac_mls_enabled)
1844 		return (0);
1845 
1846 	subj = SLOT(&cred->cr_label);
1847 	obj = SLOT(label);
1848 
1849 	if (!mac_mls_dominate_single(obj, subj))
1850 		return (EACCES);
1851 
1852 	return (0);
1853 }
1854 
1855 static int
1856 mac_mls_check_vnode_exec(struct ucred *cred, struct vnode *vp,
1857     struct label *label, struct image_params *imgp,
1858     struct label *execlabel)
1859 {
1860 	struct mac_mls *subj, *obj, *exec;
1861 	int error;
1862 
1863 	if (execlabel != NULL) {
1864 		/*
1865 		 * We currently don't permit labels to be changed at
1866 		 * exec-time as part of MLS, so disallow non-NULL
1867 		 * MLS label elements in the execlabel.
1868 		 */
1869 		exec = SLOT(execlabel);
1870 		error = mls_atmostflags(exec, 0);
1871 		if (error)
1872 			return (error);
1873 	}
1874 
1875 	if (!mac_mls_enabled)
1876 		return (0);
1877 
1878 	subj = SLOT(&cred->cr_label);
1879 	obj = SLOT(label);
1880 
1881 	if (!mac_mls_dominate_single(subj, obj))
1882 		return (EACCES);
1883 
1884 	return (0);
1885 }
1886 
1887 static int
1888 mac_mls_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
1889     struct label *label, acl_type_t type)
1890 {
1891 	struct mac_mls *subj, *obj;
1892 
1893 	if (!mac_mls_enabled)
1894 		return (0);
1895 
1896 	subj = SLOT(&cred->cr_label);
1897 	obj = SLOT(label);
1898 
1899 	if (!mac_mls_dominate_single(subj, obj))
1900 		return (EACCES);
1901 
1902 	return (0);
1903 }
1904 
1905 static int
1906 mac_mls_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
1907     struct label *label, int attrnamespace, const char *name, struct uio *uio)
1908 {
1909 	struct mac_mls *subj, *obj;
1910 
1911 	if (!mac_mls_enabled)
1912 		return (0);
1913 
1914 	subj = SLOT(&cred->cr_label);
1915 	obj = SLOT(label);
1916 
1917 	if (!mac_mls_dominate_single(subj, obj))
1918 		return (EACCES);
1919 
1920 	return (0);
1921 }
1922 
1923 static int
1924 mac_mls_check_vnode_link(struct ucred *cred, struct vnode *dvp,
1925     struct label *dlabel, struct vnode *vp, struct label *label,
1926     struct componentname *cnp)
1927 {
1928 	struct mac_mls *subj, *obj;
1929 
1930 	if (!mac_mls_enabled)
1931 		return (0);
1932 
1933 	subj = SLOT(&cred->cr_label);
1934 	obj = SLOT(dlabel);
1935 
1936 	if (!mac_mls_dominate_single(obj, subj))
1937 		return (EACCES);
1938 
1939 	obj = SLOT(dlabel);
1940 	if (!mac_mls_dominate_single(obj, subj))
1941 		return (EACCES);
1942 
1943 	return (0);
1944 }
1945 
1946 static int
1947 mac_mls_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
1948     struct label *dlabel, struct componentname *cnp)
1949 {
1950 	struct mac_mls *subj, *obj;
1951 
1952 	if (!mac_mls_enabled)
1953 		return (0);
1954 
1955 	subj = SLOT(&cred->cr_label);
1956 	obj = SLOT(dlabel);
1957 
1958 	if (!mac_mls_dominate_single(subj, obj))
1959 		return (EACCES);
1960 
1961 	return (0);
1962 }
1963 
1964 static int
1965 mac_mls_check_vnode_mmap(struct ucred *cred, struct vnode *vp,
1966     struct label *label, int prot)
1967 {
1968 	struct mac_mls *subj, *obj;
1969 
1970 	/*
1971 	 * Rely on the use of open()-time protections to handle
1972 	 * non-revocation cases.
1973 	 */
1974 	if (!mac_mls_enabled || !revocation_enabled)
1975 		return (0);
1976 
1977 	subj = SLOT(&cred->cr_label);
1978 	obj = SLOT(label);
1979 
1980 	if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
1981 		if (!mac_mls_dominate_single(subj, obj))
1982 			return (EACCES);
1983 	}
1984 	if (prot & VM_PROT_WRITE) {
1985 		if (!mac_mls_dominate_single(obj, subj))
1986 			return (EACCES);
1987 	}
1988 
1989 	return (0);
1990 }
1991 
1992 static int
1993 mac_mls_check_vnode_open(struct ucred *cred, struct vnode *vp,
1994     struct label *vnodelabel, int acc_mode)
1995 {
1996 	struct mac_mls *subj, *obj;
1997 
1998 	if (!mac_mls_enabled)
1999 		return (0);
2000 
2001 	subj = SLOT(&cred->cr_label);
2002 	obj = SLOT(vnodelabel);
2003 
2004 	/* XXX privilege override for admin? */
2005 	if (acc_mode & (VREAD | VEXEC | VSTAT)) {
2006 		if (!mac_mls_dominate_single(subj, obj))
2007 			return (EACCES);
2008 	}
2009 	if (acc_mode & (VWRITE | VAPPEND | VADMIN)) {
2010 		if (!mac_mls_dominate_single(obj, subj))
2011 			return (EACCES);
2012 	}
2013 
2014 	return (0);
2015 }
2016 
2017 static int
2018 mac_mls_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred,
2019     struct vnode *vp, struct label *label)
2020 {
2021 	struct mac_mls *subj, *obj;
2022 
2023 	if (!mac_mls_enabled || !revocation_enabled)
2024 		return (0);
2025 
2026 	subj = SLOT(&active_cred->cr_label);
2027 	obj = SLOT(label);
2028 
2029 	if (!mac_mls_dominate_single(subj, obj))
2030 		return (EACCES);
2031 
2032 	return (0);
2033 }
2034 
2035 static int
2036 mac_mls_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred,
2037     struct vnode *vp, struct label *label)
2038 {
2039 	struct mac_mls *subj, *obj;
2040 
2041 	if (!mac_mls_enabled || !revocation_enabled)
2042 		return (0);
2043 
2044 	subj = SLOT(&active_cred->cr_label);
2045 	obj = SLOT(label);
2046 
2047 	if (!mac_mls_dominate_single(subj, obj))
2048 		return (EACCES);
2049 
2050 	return (0);
2051 }
2052 
2053 static int
2054 mac_mls_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
2055     struct label *dlabel)
2056 {
2057 	struct mac_mls *subj, *obj;
2058 
2059 	if (!mac_mls_enabled)
2060 		return (0);
2061 
2062 	subj = SLOT(&cred->cr_label);
2063 	obj = SLOT(dlabel);
2064 
2065 	if (!mac_mls_dominate_single(subj, obj))
2066 		return (EACCES);
2067 
2068 	return (0);
2069 }
2070 
2071 static int
2072 mac_mls_check_vnode_readlink(struct ucred *cred, struct vnode *vp,
2073     struct label *vnodelabel)
2074 {
2075 	struct mac_mls *subj, *obj;
2076 
2077 	if (!mac_mls_enabled)
2078 		return (0);
2079 
2080 	subj = SLOT(&cred->cr_label);
2081 	obj = SLOT(vnodelabel);
2082 
2083 	if (!mac_mls_dominate_single(subj, obj))
2084 		return (EACCES);
2085 
2086 	return (0);
2087 }
2088 
2089 static int
2090 mac_mls_check_vnode_relabel(struct ucred *cred, struct vnode *vp,
2091     struct label *vnodelabel, struct label *newlabel)
2092 {
2093 	struct mac_mls *old, *new, *subj;
2094 	int error;
2095 
2096 	old = SLOT(vnodelabel);
2097 	new = SLOT(newlabel);
2098 	subj = SLOT(&cred->cr_label);
2099 
2100 	/*
2101 	 * If there is an MLS label update for the vnode, it must be a
2102 	 * single label.
2103 	 */
2104 	error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE);
2105 	if (error)
2106 		return (error);
2107 
2108 	/*
2109 	 * To perform a relabel of the vnode (MLS label or not), MLS must
2110 	 * authorize the relabel.
2111 	 */
2112 	if (!mac_mls_single_in_range(old, subj))
2113 		return (EPERM);
2114 
2115 	/*
2116 	 * If the MLS label is to be changed, authorize as appropriate.
2117 	 */
2118 	if (new->mm_flags & MAC_MLS_FLAG_SINGLE) {
2119 		/*
2120 		 * To change the MLS label on a vnode, the new vnode label
2121 		 * must be in the subject range.
2122 		 */
2123 		if (!mac_mls_single_in_range(new, subj))
2124 			return (EPERM);
2125 
2126 		/*
2127 		 * To change the MLS label on the vnode to be EQUAL,
2128 		 * the subject must have appropriate privilege.
2129 		 */
2130 		if (mac_mls_contains_equal(new)) {
2131 			error = mac_mls_subject_equal_ok(subj);
2132 			if (error)
2133 				return (error);
2134 		}
2135 	}
2136 
2137 	return (0);
2138 }
2139 
2140 
2141 static int
2142 mac_mls_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
2143     struct label *dlabel, struct vnode *vp, struct label *label,
2144     struct componentname *cnp)
2145 {
2146 	struct mac_mls *subj, *obj;
2147 
2148 	if (!mac_mls_enabled)
2149 		return (0);
2150 
2151 	subj = SLOT(&cred->cr_label);
2152 	obj = SLOT(dlabel);
2153 
2154 	if (!mac_mls_dominate_single(obj, subj))
2155 		return (EACCES);
2156 
2157 	obj = SLOT(label);
2158 
2159 	if (!mac_mls_dominate_single(obj, subj))
2160 		return (EACCES);
2161 
2162 	return (0);
2163 }
2164 
2165 static int
2166 mac_mls_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
2167     struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
2168     struct componentname *cnp)
2169 {
2170 	struct mac_mls *subj, *obj;
2171 
2172 	if (!mac_mls_enabled)
2173 		return (0);
2174 
2175 	subj = SLOT(&cred->cr_label);
2176 	obj = SLOT(dlabel);
2177 
2178 	if (!mac_mls_dominate_single(obj, subj))
2179 		return (EACCES);
2180 
2181 	if (vp != NULL) {
2182 		obj = SLOT(label);
2183 
2184 		if (!mac_mls_dominate_single(obj, subj))
2185 			return (EACCES);
2186 	}
2187 
2188 	return (0);
2189 }
2190 
2191 static int
2192 mac_mls_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
2193     struct label *label)
2194 {
2195 	struct mac_mls *subj, *obj;
2196 
2197 	if (!mac_mls_enabled)
2198 		return (0);
2199 
2200 	subj = SLOT(&cred->cr_label);
2201 	obj = SLOT(label);
2202 
2203 	if (!mac_mls_dominate_single(obj, subj))
2204 		return (EACCES);
2205 
2206 	return (0);
2207 }
2208 
2209 static int
2210 mac_mls_check_vnode_setacl(struct ucred *cred, struct vnode *vp,
2211     struct label *label, acl_type_t type, struct acl *acl)
2212 {
2213 	struct mac_mls *subj, *obj;
2214 
2215 	if (!mac_mls_enabled)
2216 		return (0);
2217 
2218 	subj = SLOT(&cred->cr_label);
2219 	obj = SLOT(label);
2220 
2221 	if (!mac_mls_dominate_single(obj, subj))
2222 		return (EACCES);
2223 
2224 	return (0);
2225 }
2226 
2227 static int
2228 mac_mls_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
2229     struct label *vnodelabel, int attrnamespace, const char *name,
2230     struct uio *uio)
2231 {
2232 	struct mac_mls *subj, *obj;
2233 
2234 	if (!mac_mls_enabled)
2235 		return (0);
2236 
2237 	subj = SLOT(&cred->cr_label);
2238 	obj = SLOT(vnodelabel);
2239 
2240 	if (!mac_mls_dominate_single(obj, subj))
2241 		return (EACCES);
2242 
2243 	/* XXX: protect the MAC EA in a special way? */
2244 
2245 	return (0);
2246 }
2247 
2248 static int
2249 mac_mls_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
2250     struct label *vnodelabel, u_long flags)
2251 {
2252 	struct mac_mls *subj, *obj;
2253 
2254 	if (!mac_mls_enabled)
2255 		return (0);
2256 
2257 	subj = SLOT(&cred->cr_label);
2258 	obj = SLOT(vnodelabel);
2259 
2260 	if (!mac_mls_dominate_single(obj, subj))
2261 		return (EACCES);
2262 
2263 	return (0);
2264 }
2265 
2266 static int
2267 mac_mls_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
2268     struct label *vnodelabel, mode_t mode)
2269 {
2270 	struct mac_mls *subj, *obj;
2271 
2272 	if (!mac_mls_enabled)
2273 		return (0);
2274 
2275 	subj = SLOT(&cred->cr_label);
2276 	obj = SLOT(vnodelabel);
2277 
2278 	if (!mac_mls_dominate_single(obj, subj))
2279 		return (EACCES);
2280 
2281 	return (0);
2282 }
2283 
2284 static int
2285 mac_mls_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
2286     struct label *vnodelabel, uid_t uid, gid_t gid)
2287 {
2288 	struct mac_mls *subj, *obj;
2289 
2290 	if (!mac_mls_enabled)
2291 		return (0);
2292 
2293 	subj = SLOT(&cred->cr_label);
2294 	obj = SLOT(vnodelabel);
2295 
2296 	if (!mac_mls_dominate_single(obj, subj))
2297 		return (EACCES);
2298 
2299 	return (0);
2300 }
2301 
2302 static int
2303 mac_mls_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
2304     struct label *vnodelabel, struct timespec atime, struct timespec mtime)
2305 {
2306 	struct mac_mls *subj, *obj;
2307 
2308 	if (!mac_mls_enabled)
2309 		return (0);
2310 
2311 	subj = SLOT(&cred->cr_label);
2312 	obj = SLOT(vnodelabel);
2313 
2314 	if (!mac_mls_dominate_single(obj, subj))
2315 		return (EACCES);
2316 
2317 	return (0);
2318 }
2319 
2320 static int
2321 mac_mls_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred,
2322     struct vnode *vp, struct label *vnodelabel)
2323 {
2324 	struct mac_mls *subj, *obj;
2325 
2326 	if (!mac_mls_enabled)
2327 		return (0);
2328 
2329 	subj = SLOT(&active_cred->cr_label);
2330 	obj = SLOT(vnodelabel);
2331 
2332 	if (!mac_mls_dominate_single(subj, obj))
2333 		return (EACCES);
2334 
2335 	return (0);
2336 }
2337 
2338 static int
2339 mac_mls_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred,
2340     struct vnode *vp, struct label *label)
2341 {
2342 	struct mac_mls *subj, *obj;
2343 
2344 	if (!mac_mls_enabled || !revocation_enabled)
2345 		return (0);
2346 
2347 	subj = SLOT(&active_cred->cr_label);
2348 	obj = SLOT(label);
2349 
2350 	if (!mac_mls_dominate_single(obj, subj))
2351 		return (EACCES);
2352 
2353 	return (0);
2354 }
2355 
2356 static struct mac_policy_ops mac_mls_ops =
2357 {
2358 	.mpo_destroy = mac_mls_destroy,
2359 	.mpo_init = mac_mls_init,
2360 	.mpo_init_bpfdesc_label = mac_mls_init_label,
2361 	.mpo_init_cred_label = mac_mls_init_label,
2362 	.mpo_init_devfsdirent_label = mac_mls_init_label,
2363 	.mpo_init_ifnet_label = mac_mls_init_label,
2364 	.mpo_init_ipq_label = mac_mls_init_label_waitcheck,
2365 	.mpo_init_mbuf_label = mac_mls_init_label_waitcheck,
2366 	.mpo_init_mount_label = mac_mls_init_label,
2367 	.mpo_init_mount_fs_label = mac_mls_init_label,
2368 	.mpo_init_pipe_label = mac_mls_init_label,
2369 	.mpo_init_socket_label = mac_mls_init_label_waitcheck,
2370 	.mpo_init_socket_peer_label = mac_mls_init_label_waitcheck,
2371 	.mpo_init_vnode_label = mac_mls_init_label,
2372 	.mpo_destroy_bpfdesc_label = mac_mls_destroy_label,
2373 	.mpo_destroy_cred_label = mac_mls_destroy_label,
2374 	.mpo_destroy_devfsdirent_label = mac_mls_destroy_label,
2375 	.mpo_destroy_ifnet_label = mac_mls_destroy_label,
2376 	.mpo_destroy_ipq_label = mac_mls_destroy_label,
2377 	.mpo_destroy_mbuf_label = mac_mls_destroy_label,
2378 	.mpo_destroy_mount_label = mac_mls_destroy_label,
2379 	.mpo_destroy_mount_fs_label = mac_mls_destroy_label,
2380 	.mpo_destroy_pipe_label = mac_mls_destroy_label,
2381 	.mpo_destroy_socket_label = mac_mls_destroy_label,
2382 	.mpo_destroy_socket_peer_label = mac_mls_destroy_label,
2383 	.mpo_destroy_vnode_label = mac_mls_destroy_label,
2384 	.mpo_copy_mbuf_label = mac_mls_copy_label,
2385 	.mpo_copy_pipe_label = mac_mls_copy_label,
2386 	.mpo_copy_vnode_label = mac_mls_copy_label,
2387 	.mpo_externalize_cred_label = mac_mls_externalize_label,
2388 	.mpo_externalize_ifnet_label = mac_mls_externalize_label,
2389 	.mpo_externalize_pipe_label = mac_mls_externalize_label,
2390 	.mpo_externalize_socket_label = mac_mls_externalize_label,
2391 	.mpo_externalize_socket_peer_label = mac_mls_externalize_label,
2392 	.mpo_externalize_vnode_label = mac_mls_externalize_label,
2393 	.mpo_internalize_cred_label = mac_mls_internalize_label,
2394 	.mpo_internalize_ifnet_label = mac_mls_internalize_label,
2395 	.mpo_internalize_pipe_label = mac_mls_internalize_label,
2396 	.mpo_internalize_socket_label = mac_mls_internalize_label,
2397 	.mpo_internalize_vnode_label = mac_mls_internalize_label,
2398 	.mpo_create_devfs_device = mac_mls_create_devfs_device,
2399 	.mpo_create_devfs_directory = mac_mls_create_devfs_directory,
2400 	.mpo_create_devfs_symlink = mac_mls_create_devfs_symlink,
2401 	.mpo_create_mount = mac_mls_create_mount,
2402 	.mpo_create_root_mount = mac_mls_create_root_mount,
2403 	.mpo_relabel_vnode = mac_mls_relabel_vnode,
2404 	.mpo_update_devfsdirent = mac_mls_update_devfsdirent,
2405 	.mpo_associate_vnode_devfs = mac_mls_associate_vnode_devfs,
2406 	.mpo_associate_vnode_extattr = mac_mls_associate_vnode_extattr,
2407 	.mpo_associate_vnode_singlelabel = mac_mls_associate_vnode_singlelabel,
2408 	.mpo_create_vnode_extattr = mac_mls_create_vnode_extattr,
2409 	.mpo_setlabel_vnode_extattr = mac_mls_setlabel_vnode_extattr,
2410 	.mpo_create_mbuf_from_socket = mac_mls_create_mbuf_from_socket,
2411 	.mpo_create_pipe = mac_mls_create_pipe,
2412 	.mpo_create_socket = mac_mls_create_socket,
2413 	.mpo_create_socket_from_socket = mac_mls_create_socket_from_socket,
2414 	.mpo_relabel_pipe = mac_mls_relabel_pipe,
2415 	.mpo_relabel_socket = mac_mls_relabel_socket,
2416 	.mpo_set_socket_peer_from_mbuf = mac_mls_set_socket_peer_from_mbuf,
2417 	.mpo_set_socket_peer_from_socket = mac_mls_set_socket_peer_from_socket,
2418 	.mpo_create_bpfdesc = mac_mls_create_bpfdesc,
2419 	.mpo_create_datagram_from_ipq = mac_mls_create_datagram_from_ipq,
2420 	.mpo_create_fragment = mac_mls_create_fragment,
2421 	.mpo_create_ifnet = mac_mls_create_ifnet,
2422 	.mpo_create_ipq = mac_mls_create_ipq,
2423 	.mpo_create_mbuf_from_mbuf = mac_mls_create_mbuf_from_mbuf,
2424 	.mpo_create_mbuf_linklayer = mac_mls_create_mbuf_linklayer,
2425 	.mpo_create_mbuf_from_bpfdesc = mac_mls_create_mbuf_from_bpfdesc,
2426 	.mpo_create_mbuf_from_ifnet = mac_mls_create_mbuf_from_ifnet,
2427 	.mpo_create_mbuf_multicast_encap = mac_mls_create_mbuf_multicast_encap,
2428 	.mpo_create_mbuf_netlayer = mac_mls_create_mbuf_netlayer,
2429 	.mpo_fragment_match = mac_mls_fragment_match,
2430 	.mpo_relabel_ifnet = mac_mls_relabel_ifnet,
2431 	.mpo_update_ipq = mac_mls_update_ipq,
2432 	.mpo_create_cred = mac_mls_create_cred,
2433 	.mpo_create_proc0 = mac_mls_create_proc0,
2434 	.mpo_create_proc1 = mac_mls_create_proc1,
2435 	.mpo_relabel_cred = mac_mls_relabel_cred,
2436 	.mpo_check_bpfdesc_receive = mac_mls_check_bpfdesc_receive,
2437 	.mpo_check_cred_relabel = mac_mls_check_cred_relabel,
2438 	.mpo_check_cred_visible = mac_mls_check_cred_visible,
2439 	.mpo_check_ifnet_relabel = mac_mls_check_ifnet_relabel,
2440 	.mpo_check_ifnet_transmit = mac_mls_check_ifnet_transmit,
2441 	.mpo_check_mount_stat = mac_mls_check_mount_stat,
2442 	.mpo_check_pipe_ioctl = mac_mls_check_pipe_ioctl,
2443 	.mpo_check_pipe_poll = mac_mls_check_pipe_poll,
2444 	.mpo_check_pipe_read = mac_mls_check_pipe_read,
2445 	.mpo_check_pipe_relabel = mac_mls_check_pipe_relabel,
2446 	.mpo_check_pipe_stat = mac_mls_check_pipe_stat,
2447 	.mpo_check_pipe_write = mac_mls_check_pipe_write,
2448 	.mpo_check_proc_debug = mac_mls_check_proc_debug,
2449 	.mpo_check_proc_sched = mac_mls_check_proc_sched,
2450 	.mpo_check_proc_signal = mac_mls_check_proc_signal,
2451 	.mpo_check_socket_deliver = mac_mls_check_socket_deliver,
2452 	.mpo_check_socket_relabel = mac_mls_check_socket_relabel,
2453 	.mpo_check_socket_visible = mac_mls_check_socket_visible,
2454 	.mpo_check_system_swapon = mac_mls_check_system_swapon,
2455 	.mpo_check_vnode_access = mac_mls_check_vnode_open,
2456 	.mpo_check_vnode_chdir = mac_mls_check_vnode_chdir,
2457 	.mpo_check_vnode_chroot = mac_mls_check_vnode_chroot,
2458 	.mpo_check_vnode_create = mac_mls_check_vnode_create,
2459 	.mpo_check_vnode_delete = mac_mls_check_vnode_delete,
2460 	.mpo_check_vnode_deleteacl = mac_mls_check_vnode_deleteacl,
2461 	.mpo_check_vnode_exec = mac_mls_check_vnode_exec,
2462 	.mpo_check_vnode_getacl = mac_mls_check_vnode_getacl,
2463 	.mpo_check_vnode_getextattr = mac_mls_check_vnode_getextattr,
2464 	.mpo_check_vnode_link = mac_mls_check_vnode_link,
2465 	.mpo_check_vnode_lookup = mac_mls_check_vnode_lookup,
2466 	.mpo_check_vnode_mmap = mac_mls_check_vnode_mmap,
2467 	.mpo_check_vnode_mprotect = mac_mls_check_vnode_mmap,
2468 	.mpo_check_vnode_open = mac_mls_check_vnode_open,
2469 	.mpo_check_vnode_poll = mac_mls_check_vnode_poll,
2470 	.mpo_check_vnode_read = mac_mls_check_vnode_read,
2471 	.mpo_check_vnode_readdir = mac_mls_check_vnode_readdir,
2472 	.mpo_check_vnode_readlink = mac_mls_check_vnode_readlink,
2473 	.mpo_check_vnode_relabel = mac_mls_check_vnode_relabel,
2474 	.mpo_check_vnode_rename_from = mac_mls_check_vnode_rename_from,
2475 	.mpo_check_vnode_rename_to = mac_mls_check_vnode_rename_to,
2476 	.mpo_check_vnode_revoke = mac_mls_check_vnode_revoke,
2477 	.mpo_check_vnode_setacl = mac_mls_check_vnode_setacl,
2478 	.mpo_check_vnode_setextattr = mac_mls_check_vnode_setextattr,
2479 	.mpo_check_vnode_setflags = mac_mls_check_vnode_setflags,
2480 	.mpo_check_vnode_setmode = mac_mls_check_vnode_setmode,
2481 	.mpo_check_vnode_setowner = mac_mls_check_vnode_setowner,
2482 	.mpo_check_vnode_setutimes = mac_mls_check_vnode_setutimes,
2483 	.mpo_check_vnode_stat = mac_mls_check_vnode_stat,
2484 	.mpo_check_vnode_write = mac_mls_check_vnode_write,
2485 };
2486 
2487 MAC_POLICY_SET(&mac_mls_ops, mac_mls, "TrustedBSD MAC/MLS",
2488     MPC_LOADTIME_FLAG_NOTLATE | MPC_LOADTIME_FLAG_LABELMBUFS, &mac_mls_slot);
2489