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