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