xref: /freebsd/sys/security/mac_mls/mac_mls.c (revision 729362425c09cf6b362366aabc6fb547eee8035a)
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 = 1;
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(struct mount *mp, dev_t dev,
770     struct devfs_dirent *devfs_dirent, 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(struct mount *mp, char *dirname,
795     int dirnamelen, 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 mount *mp,
805     struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
806     struct label *delabel)
807 {
808 	struct mac_mls *source, *dest;
809 
810 	source = SLOT(&cred->cr_label);
811 	dest = SLOT(delabel);
812 
813 	mac_mls_copy_single(source, dest);
814 }
815 
816 static void
817 mac_mls_create_mount(struct ucred *cred, struct mount *mp,
818     struct label *mntlabel, struct label *fslabel)
819 {
820 	struct mac_mls *source, *dest;
821 
822 	source = SLOT(&cred->cr_label);
823 	dest = SLOT(mntlabel);
824 	mac_mls_copy_single(source, dest);
825 	dest = SLOT(fslabel);
826 	mac_mls_copy_single(source, dest);
827 }
828 
829 static void
830 mac_mls_create_root_mount(struct ucred *cred, struct mount *mp,
831     struct label *mntlabel, struct label *fslabel)
832 {
833 	struct mac_mls *mac_mls;
834 
835 	/* Always mount root as high integrity. */
836 	mac_mls = SLOT(fslabel);
837 	mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL);
838 	mac_mls = SLOT(mntlabel);
839 	mac_mls_set_single(mac_mls, MAC_MLS_TYPE_LOW, 0, NULL);
840 }
841 
842 static void
843 mac_mls_relabel_vnode(struct ucred *cred, struct vnode *vp,
844     struct label *vnodelabel, struct label *label)
845 {
846 	struct mac_mls *source, *dest;
847 
848 	source = SLOT(label);
849 	dest = SLOT(vnodelabel);
850 
851 	mac_mls_copy(source, dest);
852 }
853 
854 static void
855 mac_mls_update_devfsdirent(struct mount *mp,
856     struct devfs_dirent *devfs_dirent, struct label *direntlabel,
857     struct vnode *vp, struct label *vnodelabel)
858 {
859 	struct mac_mls *source, *dest;
860 
861 	source = SLOT(vnodelabel);
862 	dest = SLOT(direntlabel);
863 
864 	mac_mls_copy_single(source, dest);
865 }
866 
867 static void
868 mac_mls_associate_vnode_devfs(struct mount *mp, struct label *fslabel,
869     struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
870     struct label *vlabel)
871 {
872 	struct mac_mls *source, *dest;
873 
874 	source = SLOT(delabel);
875 	dest = SLOT(vlabel);
876 
877 	mac_mls_copy_single(source, dest);
878 }
879 
880 static int
881 mac_mls_associate_vnode_extattr(struct mount *mp, struct label *fslabel,
882     struct vnode *vp, struct label *vlabel)
883 {
884 	struct mac_mls temp, *source, *dest;
885 	int buflen, error;
886 
887 	source = SLOT(fslabel);
888 	dest = SLOT(vlabel);
889 
890 	buflen = sizeof(temp);
891 	bzero(&temp, buflen);
892 
893 	error = vn_extattr_get(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
894 	    MAC_MLS_EXTATTR_NAME, &buflen, (char *) &temp, curthread);
895 	if (error == ENOATTR || error == EOPNOTSUPP) {
896 		/* Fall back to the fslabel. */
897 		mac_mls_copy_single(source, dest);
898 		return (0);
899 	} else if (error)
900 		return (error);
901 
902 	if (buflen != sizeof(temp)) {
903 		printf("mac_mls_associate_vnode_extattr: bad size %d\n",
904 		    buflen);
905 		return (EPERM);
906 	}
907 	if (mac_mls_valid(&temp) != 0) {
908 		printf("mac_mls_associate_vnode_extattr: invalid\n");
909 		return (EPERM);
910 	}
911 	if ((temp.mm_flags & MAC_MLS_FLAGS_BOTH) != MAC_MLS_FLAG_SINGLE) {
912 		printf("mac_mls_associated_vnode_extattr: not single\n");
913 		return (EPERM);
914 	}
915 
916 	mac_mls_copy_single(&temp, dest);
917 	return (0);
918 }
919 
920 static void
921 mac_mls_associate_vnode_singlelabel(struct mount *mp,
922     struct label *fslabel, struct vnode *vp, struct label *vlabel)
923 {
924 	struct mac_mls *source, *dest;
925 
926 	source = SLOT(fslabel);
927 	dest = SLOT(vlabel);
928 
929 	mac_mls_copy_single(source, dest);
930 }
931 
932 static int
933 mac_mls_create_vnode_extattr(struct ucred *cred, struct mount *mp,
934     struct label *fslabel, struct vnode *dvp, struct label *dlabel,
935     struct vnode *vp, struct label *vlabel, struct componentname *cnp)
936 {
937 	struct mac_mls *source, *dest, temp;
938 	size_t buflen;
939 	int error;
940 
941 	buflen = sizeof(temp);
942 	bzero(&temp, buflen);
943 
944 	source = SLOT(&cred->cr_label);
945 	dest = SLOT(vlabel);
946 	mac_mls_copy_single(source, &temp);
947 
948 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
949 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &temp, curthread);
950 	if (error == 0)
951 		mac_mls_copy_single(source, dest);
952 	return (error);
953 }
954 
955 static int
956 mac_mls_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp,
957     struct label *vlabel, struct label *intlabel)
958 {
959 	struct mac_mls *source, temp;
960 	size_t buflen;
961 	int error;
962 
963 	buflen = sizeof(temp);
964 	bzero(&temp, buflen);
965 
966 	source = SLOT(intlabel);
967 	if ((source->mm_flags & MAC_MLS_FLAG_SINGLE) == 0)
968 		return (0);
969 
970 	mac_mls_copy_single(source, &temp);
971 
972 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
973 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &temp, curthread);
974 	return (error);
975 }
976 
977 /*
978  * Labeling event operations: IPC object.
979  */
980 static void
981 mac_mls_create_mbuf_from_socket(struct socket *so, struct label *socketlabel,
982     struct mbuf *m, struct label *mbuflabel)
983 {
984 	struct mac_mls *source, *dest;
985 
986 	source = SLOT(socketlabel);
987 	dest = SLOT(mbuflabel);
988 
989 	mac_mls_copy_single(source, dest);
990 }
991 
992 static void
993 mac_mls_create_socket(struct ucred *cred, struct socket *socket,
994     struct label *socketlabel)
995 {
996 	struct mac_mls *source, *dest;
997 
998 	source = SLOT(&cred->cr_label);
999 	dest = SLOT(socketlabel);
1000 
1001 	mac_mls_copy_single(source, dest);
1002 }
1003 
1004 static void
1005 mac_mls_create_pipe(struct ucred *cred, struct pipe *pipe,
1006     struct label *pipelabel)
1007 {
1008 	struct mac_mls *source, *dest;
1009 
1010 	source = SLOT(&cred->cr_label);
1011 	dest = SLOT(pipelabel);
1012 
1013 	mac_mls_copy_single(source, dest);
1014 }
1015 
1016 static void
1017 mac_mls_create_socket_from_socket(struct socket *oldsocket,
1018     struct label *oldsocketlabel, struct socket *newsocket,
1019     struct label *newsocketlabel)
1020 {
1021 	struct mac_mls *source, *dest;
1022 
1023 	source = SLOT(oldsocketlabel);
1024 	dest = SLOT(newsocketlabel);
1025 
1026 	mac_mls_copy_single(source, dest);
1027 }
1028 
1029 static void
1030 mac_mls_relabel_socket(struct ucred *cred, struct socket *socket,
1031     struct label *socketlabel, struct label *newlabel)
1032 {
1033 	struct mac_mls *source, *dest;
1034 
1035 	source = SLOT(newlabel);
1036 	dest = SLOT(socketlabel);
1037 
1038 	mac_mls_copy(source, dest);
1039 }
1040 
1041 static void
1042 mac_mls_relabel_pipe(struct ucred *cred, struct pipe *pipe,
1043     struct label *pipelabel, struct label *newlabel)
1044 {
1045 	struct mac_mls *source, *dest;
1046 
1047 	source = SLOT(newlabel);
1048 	dest = SLOT(pipelabel);
1049 
1050 	mac_mls_copy(source, dest);
1051 }
1052 
1053 static void
1054 mac_mls_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct label *mbuflabel,
1055     struct socket *socket, struct label *socketpeerlabel)
1056 {
1057 	struct mac_mls *source, *dest;
1058 
1059 	source = SLOT(mbuflabel);
1060 	dest = SLOT(socketpeerlabel);
1061 
1062 	mac_mls_copy_single(source, dest);
1063 }
1064 
1065 /*
1066  * Labeling event operations: network objects.
1067  */
1068 static void
1069 mac_mls_set_socket_peer_from_socket(struct socket *oldsocket,
1070     struct label *oldsocketlabel, struct socket *newsocket,
1071     struct label *newsocketpeerlabel)
1072 {
1073 	struct mac_mls *source, *dest;
1074 
1075 	source = SLOT(oldsocketlabel);
1076 	dest = SLOT(newsocketpeerlabel);
1077 
1078 	mac_mls_copy_single(source, dest);
1079 }
1080 
1081 static void
1082 mac_mls_create_bpfdesc(struct ucred *cred, struct bpf_d *bpf_d,
1083     struct label *bpflabel)
1084 {
1085 	struct mac_mls *source, *dest;
1086 
1087 	source = SLOT(&cred->cr_label);
1088 	dest = SLOT(bpflabel);
1089 
1090 	mac_mls_copy_single(source, dest);
1091 }
1092 
1093 static void
1094 mac_mls_create_ifnet(struct ifnet *ifnet, struct label *ifnetlabel)
1095 {
1096 	struct mac_mls *dest;
1097 	int type;
1098 
1099 	dest = SLOT(ifnetlabel);
1100 
1101 	if (ifnet->if_type == IFT_LOOP)
1102 		type = MAC_MLS_TYPE_EQUAL;
1103 	else
1104 		type = MAC_MLS_TYPE_LOW;
1105 
1106 	mac_mls_set_single(dest, type, 0, NULL);
1107 	mac_mls_set_range(dest, type, 0, NULL, type, 0, NULL);
1108 }
1109 
1110 static void
1111 mac_mls_create_ipq(struct mbuf *fragment, struct label *fragmentlabel,
1112     struct ipq *ipq, struct label *ipqlabel)
1113 {
1114 	struct mac_mls *source, *dest;
1115 
1116 	source = SLOT(fragmentlabel);
1117 	dest = SLOT(ipqlabel);
1118 
1119 	mac_mls_copy_single(source, dest);
1120 }
1121 
1122 static void
1123 mac_mls_create_datagram_from_ipq(struct ipq *ipq, struct label *ipqlabel,
1124     struct mbuf *datagram, struct label *datagramlabel)
1125 {
1126 	struct mac_mls *source, *dest;
1127 
1128 	source = SLOT(ipqlabel);
1129 	dest = SLOT(datagramlabel);
1130 
1131 	/* Just use the head, since we require them all to match. */
1132 	mac_mls_copy_single(source, dest);
1133 }
1134 
1135 static void
1136 mac_mls_create_fragment(struct mbuf *datagram, struct label *datagramlabel,
1137     struct mbuf *fragment, struct label *fragmentlabel)
1138 {
1139 	struct mac_mls *source, *dest;
1140 
1141 	source = SLOT(datagramlabel);
1142 	dest = SLOT(fragmentlabel);
1143 
1144 	mac_mls_copy_single(source, dest);
1145 }
1146 
1147 static void
1148 mac_mls_create_mbuf_from_mbuf(struct mbuf *oldmbuf,
1149     struct label *oldmbuflabel, struct mbuf *newmbuf,
1150     struct label *newmbuflabel)
1151 {
1152 	struct mac_mls *source, *dest;
1153 
1154 	source = SLOT(oldmbuflabel);
1155 	dest = SLOT(newmbuflabel);
1156 
1157 	/*
1158 	 * Because the source mbuf may not yet have been "created",
1159 	 * just initialized, we do a conditional copy.  Since we don't
1160 	 * allow mbufs to have ranges, do a KASSERT to make sure that
1161 	 * doesn't happen.
1162 	 */
1163 	KASSERT((source->mm_flags & MAC_MLS_FLAG_RANGE) == 0,
1164 	    ("mac_mls_create_mbuf_from_mbuf: source mbuf has range"));
1165 	mac_mls_copy(source, dest);
1166 }
1167 
1168 static void
1169 mac_mls_create_mbuf_linklayer(struct ifnet *ifnet, struct label *ifnetlabel,
1170     struct mbuf *mbuf, struct label *mbuflabel)
1171 {
1172 	struct mac_mls *dest;
1173 
1174 	dest = SLOT(mbuflabel);
1175 
1176 	mac_mls_set_single(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1177 }
1178 
1179 static void
1180 mac_mls_create_mbuf_from_bpfdesc(struct bpf_d *bpf_d, struct label *bpflabel,
1181     struct mbuf *mbuf, struct label *mbuflabel)
1182 {
1183 	struct mac_mls *source, *dest;
1184 
1185 	source = SLOT(bpflabel);
1186 	dest = SLOT(mbuflabel);
1187 
1188 	mac_mls_copy_single(source, dest);
1189 }
1190 
1191 static void
1192 mac_mls_create_mbuf_from_ifnet(struct ifnet *ifnet, struct label *ifnetlabel,
1193     struct mbuf *m, struct label *mbuflabel)
1194 {
1195 	struct mac_mls *source, *dest;
1196 
1197 	source = SLOT(ifnetlabel);
1198 	dest = SLOT(mbuflabel);
1199 
1200 	mac_mls_copy_single(source, dest);
1201 }
1202 
1203 static void
1204 mac_mls_create_mbuf_multicast_encap(struct mbuf *oldmbuf,
1205     struct label *oldmbuflabel, struct ifnet *ifnet, struct label *ifnetlabel,
1206     struct mbuf *newmbuf, struct label *newmbuflabel)
1207 {
1208 	struct mac_mls *source, *dest;
1209 
1210 	source = SLOT(oldmbuflabel);
1211 	dest = SLOT(newmbuflabel);
1212 
1213 	mac_mls_copy_single(source, dest);
1214 }
1215 
1216 static void
1217 mac_mls_create_mbuf_netlayer(struct mbuf *oldmbuf, struct label *oldmbuflabel,
1218     struct mbuf *newmbuf, struct label *newmbuflabel)
1219 {
1220 	struct mac_mls *source, *dest;
1221 
1222 	source = SLOT(oldmbuflabel);
1223 	dest = SLOT(newmbuflabel);
1224 
1225 	mac_mls_copy_single(source, dest);
1226 }
1227 
1228 static int
1229 mac_mls_fragment_match(struct mbuf *fragment, struct label *fragmentlabel,
1230     struct ipq *ipq, struct label *ipqlabel)
1231 {
1232 	struct mac_mls *a, *b;
1233 
1234 	a = SLOT(ipqlabel);
1235 	b = SLOT(fragmentlabel);
1236 
1237 	return (mac_mls_equal_single(a, b));
1238 }
1239 
1240 static void
1241 mac_mls_relabel_ifnet(struct ucred *cred, struct ifnet *ifnet,
1242     struct label *ifnetlabel, struct label *newlabel)
1243 {
1244 	struct mac_mls *source, *dest;
1245 
1246 	source = SLOT(newlabel);
1247 	dest = SLOT(ifnetlabel);
1248 
1249 	mac_mls_copy(source, dest);
1250 }
1251 
1252 static void
1253 mac_mls_update_ipq(struct mbuf *fragment, struct label *fragmentlabel,
1254     struct ipq *ipq, struct label *ipqlabel)
1255 {
1256 
1257 	/* NOOP: we only accept matching labels, so no need to update */
1258 }
1259 
1260 /*
1261  * Labeling event operations: processes.
1262  */
1263 static void
1264 mac_mls_create_cred(struct ucred *cred_parent, struct ucred *cred_child)
1265 {
1266 	struct mac_mls *source, *dest;
1267 
1268 	source = SLOT(&cred_parent->cr_label);
1269 	dest = SLOT(&cred_child->cr_label);
1270 
1271 	mac_mls_copy_single(source, dest);
1272 	mac_mls_copy_range(source, dest);
1273 }
1274 
1275 static void
1276 mac_mls_create_proc0(struct ucred *cred)
1277 {
1278 	struct mac_mls *dest;
1279 
1280 	dest = SLOT(&cred->cr_label);
1281 
1282 	mac_mls_set_single(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1283 	mac_mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH,
1284 	    0, NULL);
1285 }
1286 
1287 static void
1288 mac_mls_create_proc1(struct ucred *cred)
1289 {
1290 	struct mac_mls *dest;
1291 
1292 	dest = SLOT(&cred->cr_label);
1293 
1294 	mac_mls_set_single(dest, MAC_MLS_TYPE_LOW, 0, NULL);
1295 	mac_mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH,
1296 	    0, NULL);
1297 }
1298 
1299 static void
1300 mac_mls_relabel_cred(struct ucred *cred, struct label *newlabel)
1301 {
1302 	struct mac_mls *source, *dest;
1303 
1304 	source = SLOT(newlabel);
1305 	dest = SLOT(&cred->cr_label);
1306 
1307 	mac_mls_copy(source, dest);
1308 }
1309 
1310 /*
1311  * Access control checks.
1312  */
1313 static int
1314 mac_mls_check_bpfdesc_receive(struct bpf_d *bpf_d, struct label *bpflabel,
1315      struct ifnet *ifnet, struct label *ifnetlabel)
1316 {
1317 	struct mac_mls *a, *b;
1318 
1319 	if (!mac_mls_enabled)
1320 		return (0);
1321 
1322 	a = SLOT(bpflabel);
1323 	b = SLOT(ifnetlabel);
1324 
1325 	if (mac_mls_equal_single(a, b))
1326 		return (0);
1327 	return (EACCES);
1328 }
1329 
1330 static int
1331 mac_mls_check_cred_relabel(struct ucred *cred, struct label *newlabel)
1332 {
1333 	struct mac_mls *subj, *new;
1334 	int error;
1335 
1336 	subj = SLOT(&cred->cr_label);
1337 	new = SLOT(newlabel);
1338 
1339 	/*
1340 	 * If there is an MLS label update for the credential, it may be
1341 	 * an update of single, range, or both.
1342 	 */
1343 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
1344 	if (error)
1345 		return (error);
1346 
1347 	/*
1348 	 * If the MLS label is to be changed, authorize as appropriate.
1349 	 */
1350 	if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
1351 		/*
1352 		 * If the change request modifies both the MLS label single
1353 		 * and range, check that the new single will be in the
1354 		 * new range.
1355 		 */
1356 		if ((new->mm_flags & MAC_MLS_FLAGS_BOTH) ==
1357 		    MAC_MLS_FLAGS_BOTH &&
1358 		    !mac_mls_single_in_range(new, new))
1359 			return (EINVAL);
1360 
1361 		/*
1362 		 * To change the MLS single label on a credential, the
1363 		 * new single label must be in the current range.
1364 		 */
1365 		if (new->mm_flags & MAC_MLS_FLAG_SINGLE &&
1366 		    !mac_mls_single_in_range(new, subj))
1367 			return (EPERM);
1368 
1369 		/*
1370 		 * To change the MLS range label on a credential, the
1371 		 * new range must be in the current range.
1372 		 */
1373 		if (new->mm_flags & MAC_MLS_FLAG_RANGE &&
1374 		    !mac_mls_range_in_range(new, subj))
1375 			return (EPERM);
1376 
1377 		/*
1378 		 * To have EQUAL in any component of the new credential
1379 		 * MLS label, the subject must already have EQUAL in
1380 		 * their label.
1381 		 */
1382 		if (mac_mls_contains_equal(new)) {
1383 			error = mac_mls_subject_equal_ok(subj);
1384 			if (error)
1385 				return (error);
1386 		}
1387 	}
1388 
1389 	return (0);
1390 }
1391 
1392 static int
1393 mac_mls_check_cred_visible(struct ucred *u1, struct ucred *u2)
1394 {
1395 	struct mac_mls *subj, *obj;
1396 
1397 	if (!mac_mls_enabled)
1398 		return (0);
1399 
1400 	subj = SLOT(&u1->cr_label);
1401 	obj = SLOT(&u2->cr_label);
1402 
1403 	/* XXX: range */
1404 	if (!mac_mls_dominate_single(subj, obj))
1405 		return (ESRCH);
1406 
1407 	return (0);
1408 }
1409 
1410 static int
1411 mac_mls_check_ifnet_relabel(struct ucred *cred, struct ifnet *ifnet,
1412     struct label *ifnetlabel, struct label *newlabel)
1413 {
1414 	struct mac_mls *subj, *new;
1415 	int error;
1416 
1417 	subj = SLOT(&cred->cr_label);
1418 	new = SLOT(newlabel);
1419 
1420 	/*
1421 	 * If there is an MLS label update for the interface, it may
1422 	 * be an update of single, range, or both.
1423 	 */
1424 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
1425 	if (error)
1426 		return (error);
1427 
1428 	/*
1429 	 * If the MLS label is to be changed, authorize as appropriate.
1430 	 */
1431 	if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
1432 		/*
1433 		 * Rely on traditional superuser status for the MLS
1434 		 * interface relabel requirements.  XXX: This will go
1435 		 * away.
1436 		 */
1437 		error = suser_cred(cred, 0);
1438 		if (error)
1439 			return (EPERM);
1440 
1441 		/*
1442 		 * XXXMAC: Additional consistency tests regarding the single
1443 		 * and the range of the new label might be performed here.
1444 		 */
1445 	}
1446 
1447 	return (0);
1448 }
1449 
1450 static int
1451 mac_mls_check_ifnet_transmit(struct ifnet *ifnet, struct label *ifnetlabel,
1452     struct mbuf *m, struct label *mbuflabel)
1453 {
1454 	struct mac_mls *p, *i;
1455 
1456 	if (!mac_mls_enabled)
1457 		return (0);
1458 
1459 	p = SLOT(mbuflabel);
1460 	i = SLOT(ifnetlabel);
1461 
1462 	return (mac_mls_single_in_range(p, i) ? 0 : EACCES);
1463 }
1464 
1465 static int
1466 mac_mls_check_mount_stat(struct ucred *cred, struct mount *mp,
1467     struct label *mntlabel)
1468 {
1469 	struct mac_mls *subj, *obj;
1470 
1471 	if (!mac_mls_enabled)
1472 		return (0);
1473 
1474 	subj = SLOT(&cred->cr_label);
1475 	obj = SLOT(mntlabel);
1476 
1477 	if (!mac_mls_dominate_single(subj, obj))
1478 		return (EACCES);
1479 
1480 	return (0);
1481 }
1482 
1483 static int
1484 mac_mls_check_pipe_ioctl(struct ucred *cred, struct pipe *pipe,
1485     struct label *pipelabel, unsigned long cmd, void /* caddr_t */ *data)
1486 {
1487 
1488 	if(!mac_mls_enabled)
1489 		return (0);
1490 
1491 	/* XXX: This will be implemented soon... */
1492 
1493 	return (0);
1494 }
1495 
1496 static int
1497 mac_mls_check_pipe_poll(struct ucred *cred, struct pipe *pipe,
1498     struct label *pipelabel)
1499 {
1500 	struct mac_mls *subj, *obj;
1501 
1502 	if (!mac_mls_enabled)
1503 		return (0);
1504 
1505 	subj = SLOT(&cred->cr_label);
1506 	obj = SLOT((pipelabel));
1507 
1508 	if (!mac_mls_dominate_single(subj, obj))
1509 		return (EACCES);
1510 
1511 	return (0);
1512 }
1513 
1514 static int
1515 mac_mls_check_pipe_read(struct ucred *cred, struct pipe *pipe,
1516     struct label *pipelabel)
1517 {
1518 	struct mac_mls *subj, *obj;
1519 
1520 	if (!mac_mls_enabled)
1521 		return (0);
1522 
1523 	subj = SLOT(&cred->cr_label);
1524 	obj = SLOT((pipelabel));
1525 
1526 	if (!mac_mls_dominate_single(subj, obj))
1527 		return (EACCES);
1528 
1529 	return (0);
1530 }
1531 
1532 static int
1533 mac_mls_check_pipe_relabel(struct ucred *cred, struct pipe *pipe,
1534     struct label *pipelabel, struct label *newlabel)
1535 {
1536 	struct mac_mls *subj, *obj, *new;
1537 	int error;
1538 
1539 	new = SLOT(newlabel);
1540 	subj = SLOT(&cred->cr_label);
1541 	obj = SLOT(pipelabel);
1542 
1543 	/*
1544 	 * If there is an MLS label update for a pipe, it must be a
1545 	 * single update.
1546 	 */
1547 	error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE);
1548 	if (error)
1549 		return (error);
1550 
1551 	/*
1552 	 * To perform a relabel of a pipe (MLS label or not), MLS must
1553 	 * authorize the relabel.
1554 	 */
1555 	if (!mac_mls_single_in_range(obj, subj))
1556 		return (EPERM);
1557 
1558 	/*
1559 	 * If the MLS label is to be changed, authorize as appropriate.
1560 	 */
1561 	if (new->mm_flags & MAC_MLS_FLAG_SINGLE) {
1562 		/*
1563 		 * To change the MLS label on a pipe, the new pipe label
1564 		 * must be in the subject range.
1565 		 */
1566 		if (!mac_mls_single_in_range(new, subj))
1567 			return (EPERM);
1568 
1569 		/*
1570 		 * To change the MLS label on a pipe to be EQUAL, the
1571 		 * subject must have appropriate privilege.
1572 		 */
1573 		if (mac_mls_contains_equal(new)) {
1574 			error = mac_mls_subject_equal_ok(subj);
1575 			if (error)
1576 				return (error);
1577 		}
1578 	}
1579 
1580 	return (0);
1581 }
1582 
1583 static int
1584 mac_mls_check_pipe_stat(struct ucred *cred, struct pipe *pipe,
1585     struct label *pipelabel)
1586 {
1587 	struct mac_mls *subj, *obj;
1588 
1589 	if (!mac_mls_enabled)
1590 		return (0);
1591 
1592 	subj = SLOT(&cred->cr_label);
1593 	obj = SLOT((pipelabel));
1594 
1595 	if (!mac_mls_dominate_single(subj, obj))
1596 		return (EACCES);
1597 
1598 	return (0);
1599 }
1600 
1601 static int
1602 mac_mls_check_pipe_write(struct ucred *cred, struct pipe *pipe,
1603     struct label *pipelabel)
1604 {
1605 	struct mac_mls *subj, *obj;
1606 
1607 	if (!mac_mls_enabled)
1608 		return (0);
1609 
1610 	subj = SLOT(&cred->cr_label);
1611 	obj = SLOT((pipelabel));
1612 
1613 	if (!mac_mls_dominate_single(obj, subj))
1614 		return (EACCES);
1615 
1616 	return (0);
1617 }
1618 
1619 static int
1620 mac_mls_check_proc_debug(struct ucred *cred, struct proc *proc)
1621 {
1622 	struct mac_mls *subj, *obj;
1623 
1624 	if (!mac_mls_enabled)
1625 		return (0);
1626 
1627 	subj = SLOT(&cred->cr_label);
1628 	obj = SLOT(&proc->p_ucred->cr_label);
1629 
1630 	/* XXX: range checks */
1631 	if (!mac_mls_dominate_single(subj, obj))
1632 		return (ESRCH);
1633 	if (!mac_mls_dominate_single(obj, subj))
1634 		return (EACCES);
1635 
1636 	return (0);
1637 }
1638 
1639 static int
1640 mac_mls_check_proc_sched(struct ucred *cred, struct proc *proc)
1641 {
1642 	struct mac_mls *subj, *obj;
1643 
1644 	if (!mac_mls_enabled)
1645 		return (0);
1646 
1647 	subj = SLOT(&cred->cr_label);
1648 	obj = SLOT(&proc->p_ucred->cr_label);
1649 
1650 	/* XXX: range checks */
1651 	if (!mac_mls_dominate_single(subj, obj))
1652 		return (ESRCH);
1653 	if (!mac_mls_dominate_single(obj, subj))
1654 		return (EACCES);
1655 
1656 	return (0);
1657 }
1658 
1659 static int
1660 mac_mls_check_proc_signal(struct ucred *cred, struct proc *proc, int signum)
1661 {
1662 	struct mac_mls *subj, *obj;
1663 
1664 	if (!mac_mls_enabled)
1665 		return (0);
1666 
1667 	subj = SLOT(&cred->cr_label);
1668 	obj = SLOT(&proc->p_ucred->cr_label);
1669 
1670 	/* XXX: range checks */
1671 	if (!mac_mls_dominate_single(subj, obj))
1672 		return (ESRCH);
1673 	if (!mac_mls_dominate_single(obj, subj))
1674 		return (EACCES);
1675 
1676 	return (0);
1677 }
1678 
1679 static int
1680 mac_mls_check_socket_deliver(struct socket *so, struct label *socketlabel,
1681     struct mbuf *m, struct label *mbuflabel)
1682 {
1683 	struct mac_mls *p, *s;
1684 
1685 	if (!mac_mls_enabled)
1686 		return (0);
1687 
1688 	p = SLOT(mbuflabel);
1689 	s = SLOT(socketlabel);
1690 
1691 	return (mac_mls_equal_single(p, s) ? 0 : EACCES);
1692 }
1693 
1694 static int
1695 mac_mls_check_socket_relabel(struct ucred *cred, struct socket *socket,
1696     struct label *socketlabel, struct label *newlabel)
1697 {
1698 	struct mac_mls *subj, *obj, *new;
1699 	int error;
1700 
1701 	new = SLOT(newlabel);
1702 	subj = SLOT(&cred->cr_label);
1703 	obj = SLOT(socketlabel);
1704 
1705 	/*
1706 	 * If there is an MLS label update for the socket, it may be
1707 	 * an update of single.
1708 	 */
1709 	error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE);
1710 	if (error)
1711 		return (error);
1712 
1713 	/*
1714 	 * To relabel a socket, the old socket single must be in the subject
1715 	 * range.
1716 	 */
1717 	if (!mac_mls_single_in_range(obj, subj))
1718 		return (EPERM);
1719 
1720 	/*
1721 	 * If the MLS label is to be changed, authorize as appropriate.
1722 	 */
1723 	if (new->mm_flags & MAC_MLS_FLAG_SINGLE) {
1724 		/*
1725 		 * To relabel a socket, the new socket single must be in
1726 		 * the subject range.
1727 		 */
1728 		if (!mac_mls_single_in_range(new, subj))
1729 			return (EPERM);
1730 
1731 		/*
1732 		 * To change the MLS label on the socket to contain EQUAL,
1733 		 * the subject must have appropriate privilege.
1734 		 */
1735 		if (mac_mls_contains_equal(new)) {
1736 			error = mac_mls_subject_equal_ok(subj);
1737 			if (error)
1738 				return (error);
1739 		}
1740 	}
1741 
1742 	return (0);
1743 }
1744 
1745 static int
1746 mac_mls_check_socket_visible(struct ucred *cred, struct socket *socket,
1747     struct label *socketlabel)
1748 {
1749 	struct mac_mls *subj, *obj;
1750 
1751 	if (!mac_mls_enabled)
1752 		return (0);
1753 
1754 	subj = SLOT(&cred->cr_label);
1755 	obj = SLOT(socketlabel);
1756 
1757 	if (!mac_mls_dominate_single(subj, obj))
1758 		return (ENOENT);
1759 
1760 	return (0);
1761 }
1762 
1763 static int
1764 mac_mls_check_system_swapon(struct ucred *cred, struct vnode *vp,
1765     struct label *label)
1766 {
1767 	struct mac_mls *subj, *obj;
1768 
1769 	if (!mac_mls_enabled)
1770 		return (0);
1771 
1772 	subj = SLOT(&cred->cr_label);
1773 	obj = SLOT(label);
1774 
1775 	if (!mac_mls_dominate_single(obj, subj) ||
1776 	    !mac_mls_dominate_single(subj, obj))
1777 		return (EACCES);
1778 
1779 	return (0);
1780 }
1781 
1782 static int
1783 mac_mls_check_vnode_chdir(struct ucred *cred, struct vnode *dvp,
1784     struct label *dlabel)
1785 {
1786 	struct mac_mls *subj, *obj;
1787 
1788 	if (!mac_mls_enabled)
1789 		return (0);
1790 
1791 	subj = SLOT(&cred->cr_label);
1792 	obj = SLOT(dlabel);
1793 
1794 	if (!mac_mls_dominate_single(subj, obj))
1795 		return (EACCES);
1796 
1797 	return (0);
1798 }
1799 
1800 static int
1801 mac_mls_check_vnode_chroot(struct ucred *cred, struct vnode *dvp,
1802     struct label *dlabel)
1803 {
1804 	struct mac_mls *subj, *obj;
1805 
1806 	if (!mac_mls_enabled)
1807 		return (0);
1808 
1809 	subj = SLOT(&cred->cr_label);
1810 	obj = SLOT(dlabel);
1811 
1812 	if (!mac_mls_dominate_single(subj, obj))
1813 		return (EACCES);
1814 
1815 	return (0);
1816 }
1817 
1818 static int
1819 mac_mls_check_vnode_create(struct ucred *cred, struct vnode *dvp,
1820     struct label *dlabel, struct componentname *cnp, struct vattr *vap)
1821 {
1822 	struct mac_mls *subj, *obj;
1823 
1824 	if (!mac_mls_enabled)
1825 		return (0);
1826 
1827 	subj = SLOT(&cred->cr_label);
1828 	obj = SLOT(dlabel);
1829 
1830 	if (!mac_mls_dominate_single(obj, subj))
1831 		return (EACCES);
1832 
1833 	return (0);
1834 }
1835 
1836 static int
1837 mac_mls_check_vnode_delete(struct ucred *cred, struct vnode *dvp,
1838     struct label *dlabel, struct vnode *vp, struct label *label,
1839     struct componentname *cnp)
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(dlabel);
1848 
1849 	if (!mac_mls_dominate_single(obj, subj))
1850 		return (EACCES);
1851 
1852 	obj = SLOT(label);
1853 
1854 	if (!mac_mls_dominate_single(obj, subj))
1855 		return (EACCES);
1856 
1857 	return (0);
1858 }
1859 
1860 static int
1861 mac_mls_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
1862     struct label *label, acl_type_t type)
1863 {
1864 	struct mac_mls *subj, *obj;
1865 
1866 	if (!mac_mls_enabled)
1867 		return (0);
1868 
1869 	subj = SLOT(&cred->cr_label);
1870 	obj = SLOT(label);
1871 
1872 	if (!mac_mls_dominate_single(obj, subj))
1873 		return (EACCES);
1874 
1875 	return (0);
1876 }
1877 
1878 static int
1879 mac_mls_check_vnode_exec(struct ucred *cred, struct vnode *vp,
1880     struct label *label, struct image_params *imgp,
1881     struct label *execlabel)
1882 {
1883 	struct mac_mls *subj, *obj, *exec;
1884 	int error;
1885 
1886 	if (execlabel != NULL) {
1887 		/*
1888 		 * We currently don't permit labels to be changed at
1889 		 * exec-time as part of MLS, so disallow non-NULL
1890 		 * MLS label elements in the execlabel.
1891 		 */
1892 		exec = SLOT(execlabel);
1893 		error = mls_atmostflags(exec, 0);
1894 		if (error)
1895 			return (error);
1896 	}
1897 
1898 	if (!mac_mls_enabled)
1899 		return (0);
1900 
1901 	subj = SLOT(&cred->cr_label);
1902 	obj = SLOT(label);
1903 
1904 	if (!mac_mls_dominate_single(subj, obj))
1905 		return (EACCES);
1906 
1907 	return (0);
1908 }
1909 
1910 static int
1911 mac_mls_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
1912     struct label *label, acl_type_t type)
1913 {
1914 	struct mac_mls *subj, *obj;
1915 
1916 	if (!mac_mls_enabled)
1917 		return (0);
1918 
1919 	subj = SLOT(&cred->cr_label);
1920 	obj = SLOT(label);
1921 
1922 	if (!mac_mls_dominate_single(subj, obj))
1923 		return (EACCES);
1924 
1925 	return (0);
1926 }
1927 
1928 static int
1929 mac_mls_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
1930     struct label *label, int attrnamespace, const char *name, struct uio *uio)
1931 {
1932 	struct mac_mls *subj, *obj;
1933 
1934 	if (!mac_mls_enabled)
1935 		return (0);
1936 
1937 	subj = SLOT(&cred->cr_label);
1938 	obj = SLOT(label);
1939 
1940 	if (!mac_mls_dominate_single(subj, obj))
1941 		return (EACCES);
1942 
1943 	return (0);
1944 }
1945 
1946 static int
1947 mac_mls_check_vnode_link(struct ucred *cred, struct vnode *dvp,
1948     struct label *dlabel, struct vnode *vp, struct label *label,
1949     struct componentname *cnp)
1950 {
1951 	struct mac_mls *subj, *obj;
1952 
1953 	if (!mac_mls_enabled)
1954 		return (0);
1955 
1956 	subj = SLOT(&cred->cr_label);
1957 	obj = SLOT(dlabel);
1958 
1959 	if (!mac_mls_dominate_single(obj, subj))
1960 		return (EACCES);
1961 
1962 	obj = SLOT(dlabel);
1963 	if (!mac_mls_dominate_single(obj, subj))
1964 		return (EACCES);
1965 
1966 	return (0);
1967 }
1968 
1969 static int
1970 mac_mls_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
1971     struct label *dlabel, struct componentname *cnp)
1972 {
1973 	struct mac_mls *subj, *obj;
1974 
1975 	if (!mac_mls_enabled)
1976 		return (0);
1977 
1978 	subj = SLOT(&cred->cr_label);
1979 	obj = SLOT(dlabel);
1980 
1981 	if (!mac_mls_dominate_single(subj, obj))
1982 		return (EACCES);
1983 
1984 	return (0);
1985 }
1986 
1987 static int
1988 mac_mls_check_vnode_mmap(struct ucred *cred, struct vnode *vp,
1989     struct label *label, int prot)
1990 {
1991 	struct mac_mls *subj, *obj;
1992 
1993 	/*
1994 	 * Rely on the use of open()-time protections to handle
1995 	 * non-revocation cases.
1996 	 */
1997 	if (!mac_mls_enabled || !revocation_enabled)
1998 		return (0);
1999 
2000 	subj = SLOT(&cred->cr_label);
2001 	obj = SLOT(label);
2002 
2003 	if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
2004 		if (!mac_mls_dominate_single(subj, obj))
2005 			return (EACCES);
2006 	}
2007 	if (prot & VM_PROT_WRITE) {
2008 		if (!mac_mls_dominate_single(obj, subj))
2009 			return (EACCES);
2010 	}
2011 
2012 	return (0);
2013 }
2014 
2015 static int
2016 mac_mls_check_vnode_open(struct ucred *cred, struct vnode *vp,
2017     struct label *vnodelabel, int acc_mode)
2018 {
2019 	struct mac_mls *subj, *obj;
2020 
2021 	if (!mac_mls_enabled)
2022 		return (0);
2023 
2024 	subj = SLOT(&cred->cr_label);
2025 	obj = SLOT(vnodelabel);
2026 
2027 	/* XXX privilege override for admin? */
2028 	if (acc_mode & (VREAD | VEXEC | VSTAT)) {
2029 		if (!mac_mls_dominate_single(subj, obj))
2030 			return (EACCES);
2031 	}
2032 	if (acc_mode & (VWRITE | VAPPEND | VADMIN)) {
2033 		if (!mac_mls_dominate_single(obj, subj))
2034 			return (EACCES);
2035 	}
2036 
2037 	return (0);
2038 }
2039 
2040 static int
2041 mac_mls_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred,
2042     struct vnode *vp, struct label *label)
2043 {
2044 	struct mac_mls *subj, *obj;
2045 
2046 	if (!mac_mls_enabled || !revocation_enabled)
2047 		return (0);
2048 
2049 	subj = SLOT(&active_cred->cr_label);
2050 	obj = SLOT(label);
2051 
2052 	if (!mac_mls_dominate_single(subj, obj))
2053 		return (EACCES);
2054 
2055 	return (0);
2056 }
2057 
2058 static int
2059 mac_mls_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred,
2060     struct vnode *vp, struct label *label)
2061 {
2062 	struct mac_mls *subj, *obj;
2063 
2064 	if (!mac_mls_enabled || !revocation_enabled)
2065 		return (0);
2066 
2067 	subj = SLOT(&active_cred->cr_label);
2068 	obj = SLOT(label);
2069 
2070 	if (!mac_mls_dominate_single(subj, obj))
2071 		return (EACCES);
2072 
2073 	return (0);
2074 }
2075 
2076 static int
2077 mac_mls_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
2078     struct label *dlabel)
2079 {
2080 	struct mac_mls *subj, *obj;
2081 
2082 	if (!mac_mls_enabled)
2083 		return (0);
2084 
2085 	subj = SLOT(&cred->cr_label);
2086 	obj = SLOT(dlabel);
2087 
2088 	if (!mac_mls_dominate_single(subj, obj))
2089 		return (EACCES);
2090 
2091 	return (0);
2092 }
2093 
2094 static int
2095 mac_mls_check_vnode_readlink(struct ucred *cred, struct vnode *vp,
2096     struct label *vnodelabel)
2097 {
2098 	struct mac_mls *subj, *obj;
2099 
2100 	if (!mac_mls_enabled)
2101 		return (0);
2102 
2103 	subj = SLOT(&cred->cr_label);
2104 	obj = SLOT(vnodelabel);
2105 
2106 	if (!mac_mls_dominate_single(subj, obj))
2107 		return (EACCES);
2108 
2109 	return (0);
2110 }
2111 
2112 static int
2113 mac_mls_check_vnode_relabel(struct ucred *cred, struct vnode *vp,
2114     struct label *vnodelabel, struct label *newlabel)
2115 {
2116 	struct mac_mls *old, *new, *subj;
2117 	int error;
2118 
2119 	old = SLOT(vnodelabel);
2120 	new = SLOT(newlabel);
2121 	subj = SLOT(&cred->cr_label);
2122 
2123 	/*
2124 	 * If there is an MLS label update for the vnode, it must be a
2125 	 * single label.
2126 	 */
2127 	error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE);
2128 	if (error)
2129 		return (error);
2130 
2131 	/*
2132 	 * To perform a relabel of the vnode (MLS label or not), MLS must
2133 	 * authorize the relabel.
2134 	 */
2135 	if (!mac_mls_single_in_range(old, subj))
2136 		return (EPERM);
2137 
2138 	/*
2139 	 * If the MLS label is to be changed, authorize as appropriate.
2140 	 */
2141 	if (new->mm_flags & MAC_MLS_FLAG_SINGLE) {
2142 		/*
2143 		 * To change the MLS label on a vnode, the new vnode label
2144 		 * must be in the subject range.
2145 		 */
2146 		if (!mac_mls_single_in_range(new, subj))
2147 			return (EPERM);
2148 
2149 		/*
2150 		 * To change the MLS label on the vnode to be EQUAL,
2151 		 * the subject must have appropriate privilege.
2152 		 */
2153 		if (mac_mls_contains_equal(new)) {
2154 			error = mac_mls_subject_equal_ok(subj);
2155 			if (error)
2156 				return (error);
2157 		}
2158 	}
2159 
2160 	return (0);
2161 }
2162 
2163 
2164 static int
2165 mac_mls_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
2166     struct label *dlabel, struct vnode *vp, struct label *label,
2167     struct componentname *cnp)
2168 {
2169 	struct mac_mls *subj, *obj;
2170 
2171 	if (!mac_mls_enabled)
2172 		return (0);
2173 
2174 	subj = SLOT(&cred->cr_label);
2175 	obj = SLOT(dlabel);
2176 
2177 	if (!mac_mls_dominate_single(obj, subj))
2178 		return (EACCES);
2179 
2180 	obj = SLOT(label);
2181 
2182 	if (!mac_mls_dominate_single(obj, subj))
2183 		return (EACCES);
2184 
2185 	return (0);
2186 }
2187 
2188 static int
2189 mac_mls_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
2190     struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
2191     struct componentname *cnp)
2192 {
2193 	struct mac_mls *subj, *obj;
2194 
2195 	if (!mac_mls_enabled)
2196 		return (0);
2197 
2198 	subj = SLOT(&cred->cr_label);
2199 	obj = SLOT(dlabel);
2200 
2201 	if (!mac_mls_dominate_single(obj, subj))
2202 		return (EACCES);
2203 
2204 	if (vp != NULL) {
2205 		obj = SLOT(label);
2206 
2207 		if (!mac_mls_dominate_single(obj, subj))
2208 			return (EACCES);
2209 	}
2210 
2211 	return (0);
2212 }
2213 
2214 static int
2215 mac_mls_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
2216     struct label *label)
2217 {
2218 	struct mac_mls *subj, *obj;
2219 
2220 	if (!mac_mls_enabled)
2221 		return (0);
2222 
2223 	subj = SLOT(&cred->cr_label);
2224 	obj = SLOT(label);
2225 
2226 	if (!mac_mls_dominate_single(obj, subj))
2227 		return (EACCES);
2228 
2229 	return (0);
2230 }
2231 
2232 static int
2233 mac_mls_check_vnode_setacl(struct ucred *cred, struct vnode *vp,
2234     struct label *label, acl_type_t type, struct acl *acl)
2235 {
2236 	struct mac_mls *subj, *obj;
2237 
2238 	if (!mac_mls_enabled)
2239 		return (0);
2240 
2241 	subj = SLOT(&cred->cr_label);
2242 	obj = SLOT(label);
2243 
2244 	if (!mac_mls_dominate_single(obj, subj))
2245 		return (EACCES);
2246 
2247 	return (0);
2248 }
2249 
2250 static int
2251 mac_mls_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
2252     struct label *vnodelabel, int attrnamespace, const char *name,
2253     struct uio *uio)
2254 {
2255 	struct mac_mls *subj, *obj;
2256 
2257 	if (!mac_mls_enabled)
2258 		return (0);
2259 
2260 	subj = SLOT(&cred->cr_label);
2261 	obj = SLOT(vnodelabel);
2262 
2263 	if (!mac_mls_dominate_single(obj, subj))
2264 		return (EACCES);
2265 
2266 	/* XXX: protect the MAC EA in a special way? */
2267 
2268 	return (0);
2269 }
2270 
2271 static int
2272 mac_mls_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
2273     struct label *vnodelabel, u_long flags)
2274 {
2275 	struct mac_mls *subj, *obj;
2276 
2277 	if (!mac_mls_enabled)
2278 		return (0);
2279 
2280 	subj = SLOT(&cred->cr_label);
2281 	obj = SLOT(vnodelabel);
2282 
2283 	if (!mac_mls_dominate_single(obj, subj))
2284 		return (EACCES);
2285 
2286 	return (0);
2287 }
2288 
2289 static int
2290 mac_mls_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
2291     struct label *vnodelabel, mode_t mode)
2292 {
2293 	struct mac_mls *subj, *obj;
2294 
2295 	if (!mac_mls_enabled)
2296 		return (0);
2297 
2298 	subj = SLOT(&cred->cr_label);
2299 	obj = SLOT(vnodelabel);
2300 
2301 	if (!mac_mls_dominate_single(obj, subj))
2302 		return (EACCES);
2303 
2304 	return (0);
2305 }
2306 
2307 static int
2308 mac_mls_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
2309     struct label *vnodelabel, uid_t uid, gid_t gid)
2310 {
2311 	struct mac_mls *subj, *obj;
2312 
2313 	if (!mac_mls_enabled)
2314 		return (0);
2315 
2316 	subj = SLOT(&cred->cr_label);
2317 	obj = SLOT(vnodelabel);
2318 
2319 	if (!mac_mls_dominate_single(obj, subj))
2320 		return (EACCES);
2321 
2322 	return (0);
2323 }
2324 
2325 static int
2326 mac_mls_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
2327     struct label *vnodelabel, struct timespec atime, struct timespec mtime)
2328 {
2329 	struct mac_mls *subj, *obj;
2330 
2331 	if (!mac_mls_enabled)
2332 		return (0);
2333 
2334 	subj = SLOT(&cred->cr_label);
2335 	obj = SLOT(vnodelabel);
2336 
2337 	if (!mac_mls_dominate_single(obj, subj))
2338 		return (EACCES);
2339 
2340 	return (0);
2341 }
2342 
2343 static int
2344 mac_mls_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred,
2345     struct vnode *vp, struct label *vnodelabel)
2346 {
2347 	struct mac_mls *subj, *obj;
2348 
2349 	if (!mac_mls_enabled)
2350 		return (0);
2351 
2352 	subj = SLOT(&active_cred->cr_label);
2353 	obj = SLOT(vnodelabel);
2354 
2355 	if (!mac_mls_dominate_single(subj, obj))
2356 		return (EACCES);
2357 
2358 	return (0);
2359 }
2360 
2361 static int
2362 mac_mls_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred,
2363     struct vnode *vp, struct label *label)
2364 {
2365 	struct mac_mls *subj, *obj;
2366 
2367 	if (!mac_mls_enabled || !revocation_enabled)
2368 		return (0);
2369 
2370 	subj = SLOT(&active_cred->cr_label);
2371 	obj = SLOT(label);
2372 
2373 	if (!mac_mls_dominate_single(obj, subj))
2374 		return (EACCES);
2375 
2376 	return (0);
2377 }
2378 
2379 static struct mac_policy_ops mac_mls_ops =
2380 {
2381 	.mpo_destroy = mac_mls_destroy,
2382 	.mpo_init = mac_mls_init,
2383 	.mpo_init_bpfdesc_label = mac_mls_init_label,
2384 	.mpo_init_cred_label = mac_mls_init_label,
2385 	.mpo_init_devfsdirent_label = mac_mls_init_label,
2386 	.mpo_init_ifnet_label = mac_mls_init_label,
2387 	.mpo_init_ipq_label = mac_mls_init_label_waitcheck,
2388 	.mpo_init_mbuf_label = mac_mls_init_label_waitcheck,
2389 	.mpo_init_mount_label = mac_mls_init_label,
2390 	.mpo_init_mount_fs_label = mac_mls_init_label,
2391 	.mpo_init_pipe_label = mac_mls_init_label,
2392 	.mpo_init_socket_label = mac_mls_init_label_waitcheck,
2393 	.mpo_init_socket_peer_label = mac_mls_init_label_waitcheck,
2394 	.mpo_init_vnode_label = mac_mls_init_label,
2395 	.mpo_destroy_bpfdesc_label = mac_mls_destroy_label,
2396 	.mpo_destroy_cred_label = mac_mls_destroy_label,
2397 	.mpo_destroy_devfsdirent_label = mac_mls_destroy_label,
2398 	.mpo_destroy_ifnet_label = mac_mls_destroy_label,
2399 	.mpo_destroy_ipq_label = mac_mls_destroy_label,
2400 	.mpo_destroy_mbuf_label = mac_mls_destroy_label,
2401 	.mpo_destroy_mount_label = mac_mls_destroy_label,
2402 	.mpo_destroy_mount_fs_label = mac_mls_destroy_label,
2403 	.mpo_destroy_pipe_label = mac_mls_destroy_label,
2404 	.mpo_destroy_socket_label = mac_mls_destroy_label,
2405 	.mpo_destroy_socket_peer_label = mac_mls_destroy_label,
2406 	.mpo_destroy_vnode_label = mac_mls_destroy_label,
2407 	.mpo_copy_pipe_label = mac_mls_copy_label,
2408 	.mpo_copy_vnode_label = mac_mls_copy_label,
2409 	.mpo_externalize_cred_label = mac_mls_externalize_label,
2410 	.mpo_externalize_ifnet_label = mac_mls_externalize_label,
2411 	.mpo_externalize_pipe_label = mac_mls_externalize_label,
2412 	.mpo_externalize_socket_label = mac_mls_externalize_label,
2413 	.mpo_externalize_socket_peer_label = mac_mls_externalize_label,
2414 	.mpo_externalize_vnode_label = mac_mls_externalize_label,
2415 	.mpo_internalize_cred_label = mac_mls_internalize_label,
2416 	.mpo_internalize_ifnet_label = mac_mls_internalize_label,
2417 	.mpo_internalize_pipe_label = mac_mls_internalize_label,
2418 	.mpo_internalize_socket_label = mac_mls_internalize_label,
2419 	.mpo_internalize_vnode_label = mac_mls_internalize_label,
2420 	.mpo_create_devfs_device = mac_mls_create_devfs_device,
2421 	.mpo_create_devfs_directory = mac_mls_create_devfs_directory,
2422 	.mpo_create_devfs_symlink = mac_mls_create_devfs_symlink,
2423 	.mpo_create_mount = mac_mls_create_mount,
2424 	.mpo_create_root_mount = mac_mls_create_root_mount,
2425 	.mpo_relabel_vnode = mac_mls_relabel_vnode,
2426 	.mpo_update_devfsdirent = mac_mls_update_devfsdirent,
2427 	.mpo_associate_vnode_devfs = mac_mls_associate_vnode_devfs,
2428 	.mpo_associate_vnode_extattr = mac_mls_associate_vnode_extattr,
2429 	.mpo_associate_vnode_singlelabel = mac_mls_associate_vnode_singlelabel,
2430 	.mpo_create_vnode_extattr = mac_mls_create_vnode_extattr,
2431 	.mpo_setlabel_vnode_extattr = mac_mls_setlabel_vnode_extattr,
2432 	.mpo_create_mbuf_from_socket = mac_mls_create_mbuf_from_socket,
2433 	.mpo_create_pipe = mac_mls_create_pipe,
2434 	.mpo_create_socket = mac_mls_create_socket,
2435 	.mpo_create_socket_from_socket = mac_mls_create_socket_from_socket,
2436 	.mpo_relabel_pipe = mac_mls_relabel_pipe,
2437 	.mpo_relabel_socket = mac_mls_relabel_socket,
2438 	.mpo_set_socket_peer_from_mbuf = mac_mls_set_socket_peer_from_mbuf,
2439 	.mpo_set_socket_peer_from_socket = mac_mls_set_socket_peer_from_socket,
2440 	.mpo_create_bpfdesc = mac_mls_create_bpfdesc,
2441 	.mpo_create_datagram_from_ipq = mac_mls_create_datagram_from_ipq,
2442 	.mpo_create_fragment = mac_mls_create_fragment,
2443 	.mpo_create_ifnet = mac_mls_create_ifnet,
2444 	.mpo_create_ipq = mac_mls_create_ipq,
2445 	.mpo_create_mbuf_from_mbuf = mac_mls_create_mbuf_from_mbuf,
2446 	.mpo_create_mbuf_linklayer = mac_mls_create_mbuf_linklayer,
2447 	.mpo_create_mbuf_from_bpfdesc = mac_mls_create_mbuf_from_bpfdesc,
2448 	.mpo_create_mbuf_from_ifnet = mac_mls_create_mbuf_from_ifnet,
2449 	.mpo_create_mbuf_multicast_encap = mac_mls_create_mbuf_multicast_encap,
2450 	.mpo_create_mbuf_netlayer = mac_mls_create_mbuf_netlayer,
2451 	.mpo_fragment_match = mac_mls_fragment_match,
2452 	.mpo_relabel_ifnet = mac_mls_relabel_ifnet,
2453 	.mpo_update_ipq = mac_mls_update_ipq,
2454 	.mpo_create_cred = mac_mls_create_cred,
2455 	.mpo_create_proc0 = mac_mls_create_proc0,
2456 	.mpo_create_proc1 = mac_mls_create_proc1,
2457 	.mpo_relabel_cred = mac_mls_relabel_cred,
2458 	.mpo_check_bpfdesc_receive = mac_mls_check_bpfdesc_receive,
2459 	.mpo_check_cred_relabel = mac_mls_check_cred_relabel,
2460 	.mpo_check_cred_visible = mac_mls_check_cred_visible,
2461 	.mpo_check_ifnet_relabel = mac_mls_check_ifnet_relabel,
2462 	.mpo_check_ifnet_transmit = mac_mls_check_ifnet_transmit,
2463 	.mpo_check_mount_stat = mac_mls_check_mount_stat,
2464 	.mpo_check_pipe_ioctl = mac_mls_check_pipe_ioctl,
2465 	.mpo_check_pipe_poll = mac_mls_check_pipe_poll,
2466 	.mpo_check_pipe_read = mac_mls_check_pipe_read,
2467 	.mpo_check_pipe_relabel = mac_mls_check_pipe_relabel,
2468 	.mpo_check_pipe_stat = mac_mls_check_pipe_stat,
2469 	.mpo_check_pipe_write = mac_mls_check_pipe_write,
2470 	.mpo_check_proc_debug = mac_mls_check_proc_debug,
2471 	.mpo_check_proc_sched = mac_mls_check_proc_sched,
2472 	.mpo_check_proc_signal = mac_mls_check_proc_signal,
2473 	.mpo_check_socket_deliver = mac_mls_check_socket_deliver,
2474 	.mpo_check_socket_relabel = mac_mls_check_socket_relabel,
2475 	.mpo_check_socket_visible = mac_mls_check_socket_visible,
2476 	.mpo_check_system_swapon = mac_mls_check_system_swapon,
2477 	.mpo_check_vnode_access = mac_mls_check_vnode_open,
2478 	.mpo_check_vnode_chdir = mac_mls_check_vnode_chdir,
2479 	.mpo_check_vnode_chroot = mac_mls_check_vnode_chroot,
2480 	.mpo_check_vnode_create = mac_mls_check_vnode_create,
2481 	.mpo_check_vnode_delete = mac_mls_check_vnode_delete,
2482 	.mpo_check_vnode_deleteacl = mac_mls_check_vnode_deleteacl,
2483 	.mpo_check_vnode_exec = mac_mls_check_vnode_exec,
2484 	.mpo_check_vnode_getacl = mac_mls_check_vnode_getacl,
2485 	.mpo_check_vnode_getextattr = mac_mls_check_vnode_getextattr,
2486 	.mpo_check_vnode_link = mac_mls_check_vnode_link,
2487 	.mpo_check_vnode_lookup = mac_mls_check_vnode_lookup,
2488 	.mpo_check_vnode_mmap = mac_mls_check_vnode_mmap,
2489 	.mpo_check_vnode_mprotect = mac_mls_check_vnode_mmap,
2490 	.mpo_check_vnode_open = mac_mls_check_vnode_open,
2491 	.mpo_check_vnode_poll = mac_mls_check_vnode_poll,
2492 	.mpo_check_vnode_read = mac_mls_check_vnode_read,
2493 	.mpo_check_vnode_readdir = mac_mls_check_vnode_readdir,
2494 	.mpo_check_vnode_readlink = mac_mls_check_vnode_readlink,
2495 	.mpo_check_vnode_relabel = mac_mls_check_vnode_relabel,
2496 	.mpo_check_vnode_rename_from = mac_mls_check_vnode_rename_from,
2497 	.mpo_check_vnode_rename_to = mac_mls_check_vnode_rename_to,
2498 	.mpo_check_vnode_revoke = mac_mls_check_vnode_revoke,
2499 	.mpo_check_vnode_setacl = mac_mls_check_vnode_setacl,
2500 	.mpo_check_vnode_setextattr = mac_mls_check_vnode_setextattr,
2501 	.mpo_check_vnode_setflags = mac_mls_check_vnode_setflags,
2502 	.mpo_check_vnode_setmode = mac_mls_check_vnode_setmode,
2503 	.mpo_check_vnode_setowner = mac_mls_check_vnode_setowner,
2504 	.mpo_check_vnode_setutimes = mac_mls_check_vnode_setutimes,
2505 	.mpo_check_vnode_stat = mac_mls_check_vnode_stat,
2506 	.mpo_check_vnode_write = mac_mls_check_vnode_write,
2507 };
2508 
2509 MAC_POLICY_SET(&mac_mls_ops, mac_mls, "TrustedBSD MAC/MLS",
2510     MPC_LOADTIME_FLAG_NOTLATE, &mac_mls_slot);
2511