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