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