xref: /freebsd/sys/security/mac_mls/mac_mls.c (revision b1879975794772ee51f0b4865753364c7d7626c3)
1 /*-
2  * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson
3  * Copyright (c) 2001-2005 McAfee, Inc.
4  * Copyright (c) 2006 SPARTA, Inc.
5  * All rights reserved.
6  *
7  * This software was developed by Robert Watson for the TrustedBSD Project.
8  *
9  * This software was developed for the FreeBSD Project in part by McAfee
10  * Research, the Security Research Division of McAfee, Inc. under
11  * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
12  * CHATS research program.
13  *
14  * This software was enhanced by SPARTA ISSO under SPAWAR contract
15  * N66001-04-C-6019 ("SEFOS").
16  *
17  * This software was developed at the University of Cambridge Computer
18  * Laboratory with support from a grant from Google, Inc.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  */
41 
42 /*
43  * Developed by the TrustedBSD Project.
44  *
45  * MLS fixed label mandatory confidentiality policy.
46  */
47 
48 #include <sys/types.h>
49 #include <sys/param.h>
50 #include <sys/acl.h>
51 #include <sys/conf.h>
52 #include <sys/extattr.h>
53 #include <sys/kernel.h>
54 #include <sys/ksem.h>
55 #include <sys/mman.h>
56 #include <sys/malloc.h>
57 #include <sys/mount.h>
58 #include <sys/proc.h>
59 #include <sys/sbuf.h>
60 #include <sys/systm.h>
61 #include <sys/sysproto.h>
62 #include <sys/sysent.h>
63 #include <sys/systm.h>
64 #include <sys/vnode.h>
65 #include <sys/file.h>
66 #include <sys/socket.h>
67 #include <sys/socketvar.h>
68 #include <sys/pipe.h>
69 #include <sys/sx.h>
70 #include <sys/sysctl.h>
71 #include <sys/msg.h>
72 #include <sys/sem.h>
73 #include <sys/shm.h>
74 
75 #include <fs/devfs/devfs.h>
76 
77 #include <net/bpfdesc.h>
78 #include <net/if.h>
79 #include <net/if_types.h>
80 #include <net/if_var.h>
81 
82 #include <netinet/in.h>
83 #include <netinet/in_pcb.h>
84 #include <netinet/ip_var.h>
85 
86 #include <vm/uma.h>
87 #include <vm/vm.h>
88 
89 #include <security/mac/mac_policy.h>
90 #include <security/mac_mls/mac_mls.h>
91 
92 static SYSCTL_NODE(_security_mac, OID_AUTO, mls,
93     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
94     "TrustedBSD mac_mls policy controls");
95 
96 static int	mls_label_size = sizeof(struct mac_mls);
97 SYSCTL_INT(_security_mac_mls, OID_AUTO, label_size, CTLFLAG_RD,
98     &mls_label_size, 0, "Size of struct mac_mls");
99 
100 static int	mls_enabled = 1;
101 SYSCTL_INT(_security_mac_mls, OID_AUTO, enabled, CTLFLAG_RWTUN, &mls_enabled, 0,
102     "Enforce MAC/MLS policy");
103 
104 static int	destroyed_not_inited;
105 SYSCTL_INT(_security_mac_mls, OID_AUTO, destroyed_not_inited, CTLFLAG_RD,
106     &destroyed_not_inited, 0, "Count of labels destroyed but not inited");
107 
108 static int	ptys_equal = 0;
109 SYSCTL_INT(_security_mac_mls, OID_AUTO, ptys_equal, CTLFLAG_RWTUN,
110     &ptys_equal, 0, "Label pty devices as mls/equal on create");
111 
112 static int	revocation_enabled = 0;
113 SYSCTL_INT(_security_mac_mls, OID_AUTO, revocation_enabled, CTLFLAG_RWTUN,
114     &revocation_enabled, 0, "Revoke access to objects on relabel");
115 
116 static int	max_compartments = MAC_MLS_MAX_COMPARTMENTS;
117 SYSCTL_INT(_security_mac_mls, OID_AUTO, max_compartments, CTLFLAG_RD,
118     &max_compartments, 0, "Maximum compartments the policy supports");
119 
120 static int	mls_slot;
121 #define	SLOT(l)	((struct mac_mls *)mac_label_get((l), mls_slot))
122 #define	SLOT_SET(l, val) mac_label_set((l), mls_slot, (uintptr_t)(val))
123 
124 static uma_zone_t	zone_mls;
125 
126 static __inline int
127 mls_bit_set_empty(u_char *set) {
128 	int i;
129 
130 	for (i = 0; i < MAC_MLS_MAX_COMPARTMENTS >> 3; i++)
131 		if (set[i] != 0)
132 			return (0);
133 	return (1);
134 }
135 
136 static struct mac_mls *
137 mls_alloc(int flag)
138 {
139 
140 	return (uma_zalloc(zone_mls, flag | M_ZERO));
141 }
142 
143 static void
144 mls_free(struct mac_mls *mm)
145 {
146 
147 	if (mm != NULL)
148 		uma_zfree(zone_mls, mm);
149 	else
150 		atomic_add_int(&destroyed_not_inited, 1);
151 }
152 
153 static int
154 mls_atmostflags(struct mac_mls *mm, int flags)
155 {
156 
157 	if ((mm->mm_flags & flags) != mm->mm_flags)
158 		return (EINVAL);
159 	return (0);
160 }
161 
162 static int
163 mls_dominate_element(struct mac_mls_element *a, struct mac_mls_element *b)
164 {
165 	int bit;
166 
167 	switch (a->mme_type) {
168 	case MAC_MLS_TYPE_EQUAL:
169 	case MAC_MLS_TYPE_HIGH:
170 		return (1);
171 
172 	case MAC_MLS_TYPE_LOW:
173 		switch (b->mme_type) {
174 		case MAC_MLS_TYPE_LEVEL:
175 		case MAC_MLS_TYPE_HIGH:
176 			return (0);
177 
178 		case MAC_MLS_TYPE_EQUAL:
179 		case MAC_MLS_TYPE_LOW:
180 			return (1);
181 
182 		default:
183 			panic("mls_dominate_element: b->mme_type invalid");
184 		}
185 
186 	case MAC_MLS_TYPE_LEVEL:
187 		switch (b->mme_type) {
188 		case MAC_MLS_TYPE_EQUAL:
189 		case MAC_MLS_TYPE_LOW:
190 			return (1);
191 
192 		case MAC_MLS_TYPE_HIGH:
193 			return (0);
194 
195 		case MAC_MLS_TYPE_LEVEL:
196 			for (bit = 1; bit <= MAC_MLS_MAX_COMPARTMENTS; bit++)
197 				if (!MAC_MLS_BIT_TEST(bit,
198 				    a->mme_compartments) &&
199 				    MAC_MLS_BIT_TEST(bit, b->mme_compartments))
200 					return (0);
201 			return (a->mme_level >= b->mme_level);
202 
203 		default:
204 			panic("mls_dominate_element: b->mme_type invalid");
205 		}
206 
207 	default:
208 		panic("mls_dominate_element: a->mme_type invalid");
209 	}
210 
211 	return (0);
212 }
213 
214 static int
215 mls_range_in_range(struct mac_mls *rangea, struct mac_mls *rangeb)
216 {
217 
218 	return (mls_dominate_element(&rangeb->mm_rangehigh,
219 	    &rangea->mm_rangehigh) &&
220 	    mls_dominate_element(&rangea->mm_rangelow,
221 	    &rangeb->mm_rangelow));
222 }
223 
224 static int
225 mls_effective_in_range(struct mac_mls *effective, struct mac_mls *range)
226 {
227 
228 	KASSERT((effective->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
229 	    ("mls_effective_in_range: a not effective"));
230 	KASSERT((range->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
231 	    ("mls_effective_in_range: b not range"));
232 
233 	return (mls_dominate_element(&range->mm_rangehigh,
234 	    &effective->mm_effective) &&
235 	    mls_dominate_element(&effective->mm_effective,
236 	    &range->mm_rangelow));
237 
238 	return (1);
239 }
240 
241 static int
242 mls_dominate_effective(struct mac_mls *a, struct mac_mls *b)
243 {
244 	KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
245 	    ("mls_dominate_effective: a not effective"));
246 	KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
247 	    ("mls_dominate_effective: b not effective"));
248 
249 	return (mls_dominate_element(&a->mm_effective, &b->mm_effective));
250 }
251 
252 static int
253 mls_equal_element(struct mac_mls_element *a, struct mac_mls_element *b)
254 {
255 
256 	if (a->mme_type == MAC_MLS_TYPE_EQUAL ||
257 	    b->mme_type == MAC_MLS_TYPE_EQUAL)
258 		return (1);
259 
260 	return (a->mme_type == b->mme_type && a->mme_level == b->mme_level);
261 }
262 
263 static int
264 mls_equal_effective(struct mac_mls *a, struct mac_mls *b)
265 {
266 
267 	KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
268 	    ("mls_equal_effective: a not effective"));
269 	KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
270 	    ("mls_equal_effective: b not effective"));
271 
272 	return (mls_equal_element(&a->mm_effective, &b->mm_effective));
273 }
274 
275 static int
276 mls_contains_equal(struct mac_mls *mm)
277 {
278 
279 	if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
280 		if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
281 			return (1);
282 
283 	if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
284 		if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL)
285 			return (1);
286 		if (mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
287 			return (1);
288 	}
289 
290 	return (0);
291 }
292 
293 static int
294 mls_subject_privileged(struct mac_mls *mm)
295 {
296 
297 	KASSERT((mm->mm_flags & MAC_MLS_FLAGS_BOTH) == MAC_MLS_FLAGS_BOTH,
298 	    ("mls_subject_privileged: subject doesn't have both labels"));
299 
300 	/* If the effective is EQUAL, it's ok. */
301 	if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
302 		return (0);
303 
304 	/* If either range endpoint is EQUAL, it's ok. */
305 	if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL ||
306 	    mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
307 		return (0);
308 
309 	/* If the range is low-high, it's ok. */
310 	if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_LOW &&
311 	    mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_HIGH)
312 		return (0);
313 
314 	/* It's not ok. */
315 	return (EPERM);
316 }
317 
318 static int
319 mls_valid(struct mac_mls *mm)
320 {
321 
322 	if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
323 		switch (mm->mm_effective.mme_type) {
324 		case MAC_MLS_TYPE_LEVEL:
325 			break;
326 
327 		case MAC_MLS_TYPE_EQUAL:
328 		case MAC_MLS_TYPE_HIGH:
329 		case MAC_MLS_TYPE_LOW:
330 			if (mm->mm_effective.mme_level != 0 ||
331 			    !MAC_MLS_BIT_SET_EMPTY(
332 			    mm->mm_effective.mme_compartments))
333 				return (EINVAL);
334 			break;
335 
336 		default:
337 			return (EINVAL);
338 		}
339 	} else {
340 		if (mm->mm_effective.mme_type != MAC_MLS_TYPE_UNDEF)
341 			return (EINVAL);
342 	}
343 
344 	if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
345 		switch (mm->mm_rangelow.mme_type) {
346 		case MAC_MLS_TYPE_LEVEL:
347 			break;
348 
349 		case MAC_MLS_TYPE_EQUAL:
350 		case MAC_MLS_TYPE_HIGH:
351 		case MAC_MLS_TYPE_LOW:
352 			if (mm->mm_rangelow.mme_level != 0 ||
353 			    !MAC_MLS_BIT_SET_EMPTY(
354 			    mm->mm_rangelow.mme_compartments))
355 				return (EINVAL);
356 			break;
357 
358 		default:
359 			return (EINVAL);
360 		}
361 
362 		switch (mm->mm_rangehigh.mme_type) {
363 		case MAC_MLS_TYPE_LEVEL:
364 			break;
365 
366 		case MAC_MLS_TYPE_EQUAL:
367 		case MAC_MLS_TYPE_HIGH:
368 		case MAC_MLS_TYPE_LOW:
369 			if (mm->mm_rangehigh.mme_level != 0 ||
370 			    !MAC_MLS_BIT_SET_EMPTY(
371 			    mm->mm_rangehigh.mme_compartments))
372 				return (EINVAL);
373 			break;
374 
375 		default:
376 			return (EINVAL);
377 		}
378 		if (!mls_dominate_element(&mm->mm_rangehigh,
379 		    &mm->mm_rangelow))
380 			return (EINVAL);
381 	} else {
382 		if (mm->mm_rangelow.mme_type != MAC_MLS_TYPE_UNDEF ||
383 		    mm->mm_rangehigh.mme_type != MAC_MLS_TYPE_UNDEF)
384 			return (EINVAL);
385 	}
386 
387 	return (0);
388 }
389 
390 static void
391 mls_set_range(struct mac_mls *mm, u_short typelow, u_short levellow,
392     u_char *compartmentslow, u_short typehigh, u_short levelhigh,
393     u_char *compartmentshigh)
394 {
395 
396 	mm->mm_rangelow.mme_type = typelow;
397 	mm->mm_rangelow.mme_level = levellow;
398 	if (compartmentslow != NULL)
399 		memcpy(mm->mm_rangelow.mme_compartments, compartmentslow,
400 		    sizeof(mm->mm_rangelow.mme_compartments));
401 	mm->mm_rangehigh.mme_type = typehigh;
402 	mm->mm_rangehigh.mme_level = levelhigh;
403 	if (compartmentshigh != NULL)
404 		memcpy(mm->mm_rangehigh.mme_compartments, compartmentshigh,
405 		    sizeof(mm->mm_rangehigh.mme_compartments));
406 	mm->mm_flags |= MAC_MLS_FLAG_RANGE;
407 }
408 
409 static void
410 mls_set_effective(struct mac_mls *mm, u_short type, u_short level,
411     u_char *compartments)
412 {
413 
414 	mm->mm_effective.mme_type = type;
415 	mm->mm_effective.mme_level = level;
416 	if (compartments != NULL)
417 		memcpy(mm->mm_effective.mme_compartments, compartments,
418 		    sizeof(mm->mm_effective.mme_compartments));
419 	mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
420 }
421 
422 static void
423 mls_copy_range(struct mac_mls *labelfrom, struct mac_mls *labelto)
424 {
425 
426 	KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
427 	    ("mls_copy_range: labelfrom not range"));
428 
429 	labelto->mm_rangelow = labelfrom->mm_rangelow;
430 	labelto->mm_rangehigh = labelfrom->mm_rangehigh;
431 	labelto->mm_flags |= MAC_MLS_FLAG_RANGE;
432 }
433 
434 static void
435 mls_copy_effective(struct mac_mls *labelfrom, struct mac_mls *labelto)
436 {
437 
438 	KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
439 	    ("mls_copy_effective: labelfrom not effective"));
440 
441 	labelto->mm_effective = labelfrom->mm_effective;
442 	labelto->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
443 }
444 
445 static void
446 mls_copy(struct mac_mls *source, struct mac_mls *dest)
447 {
448 
449 	if (source->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
450 		mls_copy_effective(source, dest);
451 	if (source->mm_flags & MAC_MLS_FLAG_RANGE)
452 		mls_copy_range(source, dest);
453 }
454 
455 /*
456  * Policy module operations.
457  */
458 static void
459 mls_init(struct mac_policy_conf *conf)
460 {
461 
462 	zone_mls = uma_zcreate("mac_mls", sizeof(struct mac_mls), NULL,
463 	    NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
464 }
465 
466 /*
467  * Label operations.
468  */
469 static void
470 mls_init_label(struct label *label)
471 {
472 
473 	SLOT_SET(label, mls_alloc(M_WAITOK));
474 }
475 
476 static int
477 mls_init_label_waitcheck(struct label *label, int flag)
478 {
479 
480 	SLOT_SET(label, mls_alloc(flag));
481 	if (SLOT(label) == NULL)
482 		return (ENOMEM);
483 
484 	return (0);
485 }
486 
487 static void
488 mls_destroy_label(struct label *label)
489 {
490 
491 	mls_free(SLOT(label));
492 	SLOT_SET(label, NULL);
493 }
494 
495 /*
496  * mls_element_to_string() accepts an sbuf and MLS element.  It converts the
497  * MLS element to a string and stores the result in the sbuf; if there isn't
498  * space in the sbuf, -1 is returned.
499  */
500 static int
501 mls_element_to_string(struct sbuf *sb, struct mac_mls_element *element)
502 {
503 	int i, first;
504 
505 	switch (element->mme_type) {
506 	case MAC_MLS_TYPE_HIGH:
507 		return (sbuf_printf(sb, "high"));
508 
509 	case MAC_MLS_TYPE_LOW:
510 		return (sbuf_printf(sb, "low"));
511 
512 	case MAC_MLS_TYPE_EQUAL:
513 		return (sbuf_printf(sb, "equal"));
514 
515 	case MAC_MLS_TYPE_LEVEL:
516 		if (sbuf_printf(sb, "%d", element->mme_level) == -1)
517 			return (-1);
518 
519 		first = 1;
520 		for (i = 1; i <= MAC_MLS_MAX_COMPARTMENTS; i++) {
521 			if (MAC_MLS_BIT_TEST(i, element->mme_compartments)) {
522 				if (first) {
523 					if (sbuf_putc(sb, ':') == -1)
524 						return (-1);
525 					if (sbuf_printf(sb, "%d", i) == -1)
526 						return (-1);
527 					first = 0;
528 				} else {
529 					if (sbuf_printf(sb, "+%d", i) == -1)
530 						return (-1);
531 				}
532 			}
533 		}
534 		return (0);
535 
536 	default:
537 		panic("mls_element_to_string: invalid type (%d)",
538 		    element->mme_type);
539 	}
540 }
541 
542 /*
543  * mls_to_string() converts an MLS label to a string, and places the results
544  * in the passed sbuf.  It returns 0 on success, or EINVAL if there isn't
545  * room in the sbuf.  Note: the sbuf will be modified even in a failure case,
546  * so the caller may need to revert the sbuf by restoring the offset if
547  * that's undesired.
548  */
549 static int
550 mls_to_string(struct sbuf *sb, struct mac_mls *mm)
551 {
552 
553 	if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
554 		if (mls_element_to_string(sb, &mm->mm_effective) == -1)
555 			return (EINVAL);
556 	}
557 
558 	if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
559 		if (sbuf_putc(sb, '(') == -1)
560 			return (EINVAL);
561 
562 		if (mls_element_to_string(sb, &mm->mm_rangelow) == -1)
563 			return (EINVAL);
564 
565 		if (sbuf_putc(sb, '-') == -1)
566 			return (EINVAL);
567 
568 		if (mls_element_to_string(sb, &mm->mm_rangehigh) == -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 mls_externalize_label(struct label *label, char *element_name,
580     struct sbuf *sb, int *claimed)
581 {
582 	struct mac_mls *mm;
583 
584 	if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
585 		return (0);
586 
587 	(*claimed)++;
588 
589 	mm = SLOT(label);
590 
591 	return (mls_to_string(sb, mm));
592 }
593 
594 static int
595 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 || strcmp(string, "hi") == 0) {
601 		element->mme_type = MAC_MLS_TYPE_HIGH;
602 		element->mme_level = MAC_MLS_TYPE_UNDEF;
603 	} else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) {
604 		element->mme_type = MAC_MLS_TYPE_LOW;
605 		element->mme_level = MAC_MLS_TYPE_UNDEF;
606 	} else if (strcmp(string, "equal") == 0 ||
607 	    strcmp(string, "eq") == 0) {
608 		element->mme_type = MAC_MLS_TYPE_EQUAL;
609 		element->mme_level = MAC_MLS_TYPE_UNDEF;
610 	} else {
611 		element->mme_type = MAC_MLS_TYPE_LEVEL;
612 
613 		/*
614 		 * Numeric level piece of the element.
615 		 */
616 		level = strsep(&string, ":");
617 		value = strtol(level, &end, 10);
618 		if (end == level || *end != '\0')
619 			return (EINVAL);
620 		if (value < 0 || value > 65535)
621 			return (EINVAL);
622 		element->mme_level = value;
623 
624 		/*
625 		 * Optional compartment piece of the element.  If none are
626 		 * included, we assume that the label has no compartments.
627 		 */
628 		if (string == NULL)
629 			return (0);
630 		if (*string == '\0')
631 			return (0);
632 
633 		while ((compartment = strsep(&string, "+")) != NULL) {
634 			value = strtol(compartment, &end, 10);
635 			if (compartment == end || *end != '\0')
636 				return (EINVAL);
637 			if (value < 1 || value > MAC_MLS_MAX_COMPARTMENTS)
638 				return (EINVAL);
639 			MAC_MLS_BIT_SET(value, element->mme_compartments);
640 		}
641 	}
642 
643 	return (0);
644 }
645 
646 /*
647  * Note: destructively consumes the string, make a local copy before calling
648  * if that's a problem.
649  */
650 static int
651 mls_parse(struct mac_mls *mm, char *string)
652 {
653 	char *rangehigh, *rangelow, *effective;
654 	int error;
655 
656 	effective = strsep(&string, "(");
657 	if (*effective == '\0')
658 		effective = NULL;
659 
660 	if (string != NULL) {
661 		rangelow = strsep(&string, "-");
662 		if (string == NULL)
663 			return (EINVAL);
664 		rangehigh = strsep(&string, ")");
665 		if (string == NULL)
666 			return (EINVAL);
667 		if (*string != '\0')
668 			return (EINVAL);
669 	} else {
670 		rangelow = NULL;
671 		rangehigh = NULL;
672 	}
673 
674 	KASSERT((rangelow != NULL && rangehigh != NULL) ||
675 	    (rangelow == NULL && rangehigh == NULL),
676 	    ("mls_parse: range mismatch"));
677 
678 	bzero(mm, sizeof(*mm));
679 	if (effective != NULL) {
680 		error = mls_parse_element(&mm->mm_effective, effective);
681 		if (error)
682 			return (error);
683 		mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
684 	}
685 
686 	if (rangelow != NULL) {
687 		error = mls_parse_element(&mm->mm_rangelow, rangelow);
688 		if (error)
689 			return (error);
690 		error = mls_parse_element(&mm->mm_rangehigh, rangehigh);
691 		if (error)
692 			return (error);
693 		mm->mm_flags |= MAC_MLS_FLAG_RANGE;
694 	}
695 
696 	error = mls_valid(mm);
697 	if (error)
698 		return (error);
699 
700 	return (0);
701 }
702 
703 static int
704 mls_internalize_label(struct label *label, char *element_name,
705     char *element_data, int *claimed)
706 {
707 	struct mac_mls *mm, mm_temp;
708 	int error;
709 
710 	if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
711 		return (0);
712 
713 	(*claimed)++;
714 
715 	error = mls_parse(&mm_temp, element_data);
716 	if (error)
717 		return (error);
718 
719 	mm = SLOT(label);
720 	*mm = mm_temp;
721 
722 	return (0);
723 }
724 
725 static void
726 mls_copy_label(struct label *src, struct label *dest)
727 {
728 
729 	*SLOT(dest) = *SLOT(src);
730 }
731 
732 /*
733  * Object-specific entry point implementations are sorted alphabetically by
734  * object type name and then by operation.
735  */
736 static int
737 mls_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
738      struct ifnet *ifp, struct label *ifplabel)
739 {
740 	struct mac_mls *a, *b;
741 
742 	if (!mls_enabled)
743 		return (0);
744 
745 	a = SLOT(dlabel);
746 	b = SLOT(ifplabel);
747 
748 	if (mls_equal_effective(a, b))
749 		return (0);
750 	return (EACCES);
751 }
752 
753 static void
754 mls_bpfdesc_create(struct ucred *cred, struct bpf_d *d, struct label *dlabel)
755 {
756 	struct mac_mls *source, *dest;
757 
758 	source = SLOT(cred->cr_label);
759 	dest = SLOT(dlabel);
760 
761 	mls_copy_effective(source, dest);
762 }
763 
764 static void
765 mls_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
766     struct mbuf *m, struct label *mlabel)
767 {
768 	struct mac_mls *source, *dest;
769 
770 	source = SLOT(dlabel);
771 	dest = SLOT(mlabel);
772 
773 	mls_copy_effective(source, dest);
774 }
775 
776 static void
777 mls_cred_associate_nfsd(struct ucred *cred)
778 {
779 	struct mac_mls *label;
780 
781 	label = SLOT(cred->cr_label);
782 	mls_set_effective(label, MAC_MLS_TYPE_LOW, 0, NULL);
783 	mls_set_range(label, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
784 	    NULL);
785 }
786 
787 static int
788 mls_cred_check_relabel(struct ucred *cred, struct label *newlabel)
789 {
790 	struct mac_mls *subj, *new;
791 	int error;
792 
793 	subj = SLOT(cred->cr_label);
794 	new = SLOT(newlabel);
795 
796 	/*
797 	 * If there is an MLS label update for the credential, it may be an
798 	 * update of effective, range, or both.
799 	 */
800 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
801 	if (error)
802 		return (error);
803 
804 	/*
805 	 * If the MLS label is to be changed, authorize as appropriate.
806 	 */
807 	if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
808 		/*
809 		 * If the change request modifies both the MLS label
810 		 * effective and range, check that the new effective will be
811 		 * in the new range.
812 		 */
813 		if ((new->mm_flags & MAC_MLS_FLAGS_BOTH) ==
814 		    MAC_MLS_FLAGS_BOTH && !mls_effective_in_range(new, new))
815 			return (EINVAL);
816 
817 		/*
818 		 * To change the MLS effective label on a credential, the new
819 		 * effective label must be in the current range.
820 		 */
821 		if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE &&
822 		    !mls_effective_in_range(new, subj))
823 			return (EPERM);
824 
825 		/*
826 		 * To change the MLS range label on a credential, the new
827 		 * range must be in the current range.
828 		 */
829 		if (new->mm_flags & MAC_MLS_FLAG_RANGE &&
830 		    !mls_range_in_range(new, subj))
831 			return (EPERM);
832 
833 		/*
834 		 * To have EQUAL in any component of the new credential MLS
835 		 * label, the subject must already have EQUAL in their label.
836 		 */
837 		if (mls_contains_equal(new)) {
838 			error = mls_subject_privileged(subj);
839 			if (error)
840 				return (error);
841 		}
842 	}
843 
844 	return (0);
845 }
846 
847 static int
848 mls_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
849 {
850 	struct mac_mls *subj, *obj;
851 
852 	if (!mls_enabled)
853 		return (0);
854 
855 	subj = SLOT(cr1->cr_label);
856 	obj = SLOT(cr2->cr_label);
857 
858 	/* XXX: range */
859 	if (!mls_dominate_effective(subj, obj))
860 		return (ESRCH);
861 
862 	return (0);
863 }
864 
865 static void
866 mls_cred_create_init(struct ucred *cred)
867 {
868 	struct mac_mls *dest;
869 
870 	dest = SLOT(cred->cr_label);
871 
872 	mls_set_effective(dest, MAC_MLS_TYPE_LOW, 0, NULL);
873 	mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
874 	    NULL);
875 }
876 
877 static void
878 mls_cred_create_swapper(struct ucred *cred)
879 {
880 	struct mac_mls *dest;
881 
882 	dest = SLOT(cred->cr_label);
883 
884 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
885 	mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
886 	    NULL);
887 }
888 
889 static void
890 mls_cred_relabel(struct ucred *cred, struct label *newlabel)
891 {
892 	struct mac_mls *source, *dest;
893 
894 	source = SLOT(newlabel);
895 	dest = SLOT(cred->cr_label);
896 
897 	mls_copy(source, dest);
898 }
899 
900 static void
901 mls_devfs_create_device(struct ucred *cred, struct mount *mp,
902     struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
903 {
904 	struct mac_mls *mm;
905 	const char *dn;
906 	int mls_type;
907 
908 	mm = SLOT(delabel);
909 	dn = devtoname(dev);
910 	if (strcmp(dn, "null") == 0 ||
911 	    strcmp(dn, "zero") == 0 ||
912 	    strcmp(dn, "random") == 0 ||
913 	    strncmp(dn, "fd/", strlen("fd/")) == 0)
914 		mls_type = MAC_MLS_TYPE_EQUAL;
915 	else if (strcmp(dn, "kmem") == 0 ||
916 	    strcmp(dn, "mem") == 0)
917 		mls_type = MAC_MLS_TYPE_HIGH;
918 	else if (ptys_equal &&
919 	    (strncmp(dn, "ttyp", strlen("ttyp")) == 0 ||
920 	    strncmp(dn, "pts/", strlen("pts/")) == 0 ||
921 	    strncmp(dn, "ptyp", strlen("ptyp")) == 0))
922 		mls_type = MAC_MLS_TYPE_EQUAL;
923 	else
924 		mls_type = MAC_MLS_TYPE_LOW;
925 	mls_set_effective(mm, mls_type, 0, NULL);
926 }
927 
928 static void
929 mls_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
930     struct devfs_dirent *de, struct label *delabel)
931 {
932 	struct mac_mls *mm;
933 
934 	mm = SLOT(delabel);
935 	mls_set_effective(mm, MAC_MLS_TYPE_LOW, 0, NULL);
936 }
937 
938 static void
939 mls_devfs_create_symlink(struct ucred *cred, struct mount *mp,
940     struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
941     struct label *delabel)
942 {
943 	struct mac_mls *source, *dest;
944 
945 	source = SLOT(cred->cr_label);
946 	dest = SLOT(delabel);
947 
948 	mls_copy_effective(source, dest);
949 }
950 
951 static void
952 mls_devfs_update(struct mount *mp, struct devfs_dirent *de,
953     struct label *delabel, struct vnode *vp, struct label *vplabel)
954 {
955 	struct mac_mls *source, *dest;
956 
957 	source = SLOT(vplabel);
958 	dest = SLOT(delabel);
959 
960 	mls_copy_effective(source, dest);
961 }
962 
963 static void
964 mls_devfs_vnode_associate(struct mount *mp, struct label *mplabel,
965     struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
966     struct label *vplabel)
967 {
968 	struct mac_mls *source, *dest;
969 
970 	source = SLOT(delabel);
971 	dest = SLOT(vplabel);
972 
973 	mls_copy_effective(source, dest);
974 }
975 
976 static int
977 mls_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
978     struct label *ifplabel, struct label *newlabel)
979 {
980 	struct mac_mls *subj, *new;
981 	int error;
982 
983 	subj = SLOT(cred->cr_label);
984 	new = SLOT(newlabel);
985 
986 	/*
987 	 * If there is an MLS label update for the interface, it may be an
988 	 * update of effective, range, or both.
989 	 */
990 	error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
991 	if (error)
992 		return (error);
993 
994 	/*
995 	 * Relabeling network interfaces requires MLS privilege.
996 	 */
997 	return (mls_subject_privileged(subj));
998 }
999 
1000 static int
1001 mls_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
1002     struct mbuf *m, struct label *mlabel)
1003 {
1004 	struct mac_mls *p, *i;
1005 
1006 	if (!mls_enabled)
1007 		return (0);
1008 
1009 	p = SLOT(mlabel);
1010 	i = SLOT(ifplabel);
1011 
1012 	return (mls_effective_in_range(p, i) ? 0 : EACCES);
1013 }
1014 
1015 static void
1016 mls_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
1017 {
1018 	struct mac_mls *dest;
1019 	int type;
1020 
1021 	dest = SLOT(ifplabel);
1022 
1023 	if (if_gettype(ifp) == IFT_LOOP)
1024 		type = MAC_MLS_TYPE_EQUAL;
1025 	else
1026 		type = MAC_MLS_TYPE_LOW;
1027 
1028 	mls_set_effective(dest, type, 0, NULL);
1029 	mls_set_range(dest, type, 0, NULL, type, 0, NULL);
1030 }
1031 
1032 static void
1033 mls_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
1034     struct mbuf *m, struct label *mlabel)
1035 {
1036 	struct mac_mls *source, *dest;
1037 
1038 	source = SLOT(ifplabel);
1039 	dest = SLOT(mlabel);
1040 
1041 	mls_copy_effective(source, dest);
1042 }
1043 
1044 static void
1045 mls_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
1046     struct label *ifplabel, struct label *newlabel)
1047 {
1048 	struct mac_mls *source, *dest;
1049 
1050 	source = SLOT(newlabel);
1051 	dest = SLOT(ifplabel);
1052 
1053 	mls_copy(source, dest);
1054 }
1055 
1056 static int
1057 mls_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
1058     struct mbuf *m, struct label *mlabel)
1059 {
1060 	struct mac_mls *p, *i;
1061 
1062 	if (!mls_enabled)
1063 		return (0);
1064 
1065 	p = SLOT(mlabel);
1066 	i = SLOT(inplabel);
1067 
1068 	return (mls_equal_effective(p, i) ? 0 : EACCES);
1069 }
1070 
1071 static int
1072 mls_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
1073     struct label *inplabel)
1074 {
1075 	struct mac_mls *subj, *obj;
1076 
1077 	if (!mls_enabled)
1078 		return (0);
1079 
1080 	subj = SLOT(cred->cr_label);
1081 	obj = SLOT(inplabel);
1082 
1083 	if (!mls_dominate_effective(subj, obj))
1084 		return (ENOENT);
1085 
1086 	return (0);
1087 }
1088 
1089 static void
1090 mls_inpcb_create(struct socket *so, struct label *solabel, struct inpcb *inp,
1091     struct label *inplabel)
1092 {
1093 	struct mac_mls *source, *dest;
1094 
1095 	source = SLOT(solabel);
1096 	dest = SLOT(inplabel);
1097 
1098 	mls_copy_effective(source, dest);
1099 }
1100 
1101 static void
1102 mls_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
1103     struct mbuf *m, struct label *mlabel)
1104 {
1105 	struct mac_mls *source, *dest;
1106 
1107 	source = SLOT(inplabel);
1108 	dest = SLOT(mlabel);
1109 
1110 	mls_copy_effective(source, dest);
1111 }
1112 
1113 static void
1114 mls_inpcb_sosetlabel(struct socket *so, struct label *solabel,
1115     struct inpcb *inp, struct label *inplabel)
1116 {
1117 	struct mac_mls *source, *dest;
1118 
1119 	SOCK_LOCK_ASSERT(so);
1120 
1121 	source = SLOT(solabel);
1122 	dest = SLOT(inplabel);
1123 
1124 	mls_copy(source, dest);
1125 }
1126 
1127 static void
1128 mls_ip6q_create(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1129     struct label *q6label)
1130 {
1131 	struct mac_mls *source, *dest;
1132 
1133 	source = SLOT(mlabel);
1134 	dest = SLOT(q6label);
1135 
1136 	mls_copy_effective(source, dest);
1137 }
1138 
1139 static int
1140 mls_ip6q_match(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1141     struct label *q6label)
1142 {
1143 	struct mac_mls *a, *b;
1144 
1145 	a = SLOT(q6label);
1146 	b = SLOT(mlabel);
1147 
1148 	return (mls_equal_effective(a, b));
1149 }
1150 
1151 static void
1152 mls_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
1153     struct label *mlabel)
1154 {
1155 	struct mac_mls *source, *dest;
1156 
1157 	source = SLOT(q6label);
1158 	dest = SLOT(mlabel);
1159 
1160 	/* Just use the head, since we require them all to match. */
1161 	mls_copy_effective(source, dest);
1162 }
1163 
1164 static void
1165 mls_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1166     struct label *q6label)
1167 {
1168 
1169 	/* NOOP: we only accept matching labels, so no need to update */
1170 }
1171 
1172 static void
1173 mls_ipq_create(struct mbuf *m, struct label *mlabel, struct ipq *q,
1174     struct label *qlabel)
1175 {
1176 	struct mac_mls *source, *dest;
1177 
1178 	source = SLOT(mlabel);
1179 	dest = SLOT(qlabel);
1180 
1181 	mls_copy_effective(source, dest);
1182 }
1183 
1184 static int
1185 mls_ipq_match(struct mbuf *m, struct label *mlabel, struct ipq *q,
1186     struct label *qlabel)
1187 {
1188 	struct mac_mls *a, *b;
1189 
1190 	a = SLOT(qlabel);
1191 	b = SLOT(mlabel);
1192 
1193 	return (mls_equal_effective(a, b));
1194 }
1195 
1196 static void
1197 mls_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
1198     struct label *mlabel)
1199 {
1200 	struct mac_mls *source, *dest;
1201 
1202 	source = SLOT(qlabel);
1203 	dest = SLOT(mlabel);
1204 
1205 	/* Just use the head, since we require them all to match. */
1206 	mls_copy_effective(source, dest);
1207 }
1208 
1209 static void
1210 mls_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
1211     struct label *qlabel)
1212 {
1213 
1214 	/* NOOP: we only accept matching labels, so no need to update */
1215 }
1216 
1217 static int
1218 mls_mount_check_stat(struct ucred *cred, struct mount *mp,
1219     struct label *mntlabel)
1220 {
1221 	struct mac_mls *subj, *obj;
1222 
1223 	if (!mls_enabled)
1224 		return (0);
1225 
1226 	subj = SLOT(cred->cr_label);
1227 	obj = SLOT(mntlabel);
1228 
1229 	if (!mls_dominate_effective(subj, obj))
1230 		return (EACCES);
1231 
1232 	return (0);
1233 }
1234 
1235 static void
1236 mls_mount_create(struct ucred *cred, struct mount *mp, struct label *mplabel)
1237 {
1238 	struct mac_mls *source, *dest;
1239 
1240 	source = SLOT(cred->cr_label);
1241 	dest = SLOT(mplabel);
1242 
1243 	mls_copy_effective(source, dest);
1244 }
1245 
1246 static void
1247 mls_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
1248     struct mbuf *m, struct label *mlabel)
1249 {
1250 	struct mac_mls *dest;
1251 
1252 	dest = SLOT(mlabel);
1253 
1254 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1255 }
1256 
1257 static void
1258 mls_netinet_firewall_reply(struct mbuf *mrecv, struct label *mrecvlabel,
1259     struct mbuf *msend, struct label *msendlabel)
1260 {
1261 	struct mac_mls *source, *dest;
1262 
1263 	source = SLOT(mrecvlabel);
1264 	dest = SLOT(msendlabel);
1265 
1266 	mls_copy_effective(source, dest);
1267 }
1268 
1269 static void
1270 mls_netinet_firewall_send(struct mbuf *m, struct label *mlabel)
1271 {
1272 	struct mac_mls *dest;
1273 
1274 	dest = SLOT(mlabel);
1275 
1276 	/* XXX: where is the label for the firewall really coming from? */
1277 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1278 }
1279 
1280 static void
1281 mls_netinet_fragment(struct mbuf *m, struct label *mlabel, struct mbuf *frag,
1282     struct label *fraglabel)
1283 {
1284 	struct mac_mls *source, *dest;
1285 
1286 	source = SLOT(mlabel);
1287 	dest = SLOT(fraglabel);
1288 
1289 	mls_copy_effective(source, dest);
1290 }
1291 
1292 static void
1293 mls_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
1294     struct mbuf *msend, struct label *msendlabel)
1295 {
1296 	struct mac_mls *source, *dest;
1297 
1298 	source = SLOT(mrecvlabel);
1299 	dest = SLOT(msendlabel);
1300 
1301 	mls_copy_effective(source, dest);
1302 }
1303 
1304 static void
1305 mls_netinet_igmp_send(struct ifnet *ifp, struct label *ifplabel,
1306     struct mbuf *m, struct label *mlabel)
1307 {
1308 	struct mac_mls *dest;
1309 
1310 	dest = SLOT(mlabel);
1311 
1312 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1313 }
1314 
1315 static void
1316 mls_netinet6_nd6_send(struct ifnet *ifp, struct label *ifplabel,
1317     struct mbuf *m, struct label *mlabel)
1318 {
1319 	struct mac_mls *dest;
1320 
1321 	dest = SLOT(mlabel);
1322 
1323 	mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1324 }
1325 
1326 static int
1327 mls_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
1328     struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
1329 {
1330 
1331 	if (!mls_enabled)
1332 		return (0);
1333 
1334 	/* XXX: This will be implemented soon... */
1335 
1336 	return (0);
1337 }
1338 
1339 static int
1340 mls_pipe_check_poll(struct ucred *cred, struct pipepair *pp,
1341     struct label *pplabel)
1342 {
1343 	struct mac_mls *subj, *obj;
1344 
1345 	if (!mls_enabled)
1346 		return (0);
1347 
1348 	subj = SLOT(cred->cr_label);
1349 	obj = SLOT(pplabel);
1350 
1351 	if (!mls_dominate_effective(subj, obj))
1352 		return (EACCES);
1353 
1354 	return (0);
1355 }
1356 
1357 static int
1358 mls_pipe_check_read(struct ucred *cred, struct pipepair *pp,
1359     struct label *pplabel)
1360 {
1361 	struct mac_mls *subj, *obj;
1362 
1363 	if (!mls_enabled)
1364 		return (0);
1365 
1366 	subj = SLOT(cred->cr_label);
1367 	obj = SLOT(pplabel);
1368 
1369 	if (!mls_dominate_effective(subj, obj))
1370 		return (EACCES);
1371 
1372 	return (0);
1373 }
1374 
1375 static int
1376 mls_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
1377     struct label *pplabel, struct label *newlabel)
1378 {
1379 	struct mac_mls *subj, *obj, *new;
1380 	int error;
1381 
1382 	new = SLOT(newlabel);
1383 	subj = SLOT(cred->cr_label);
1384 	obj = SLOT(pplabel);
1385 
1386 	/*
1387 	 * If there is an MLS label update for a pipe, it must be a effective
1388 	 * update.
1389 	 */
1390 	error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
1391 	if (error)
1392 		return (error);
1393 
1394 	/*
1395 	 * To perform a relabel of a pipe (MLS label or not), MLS must
1396 	 * authorize the relabel.
1397 	 */
1398 	if (!mls_effective_in_range(obj, subj))
1399 		return (EPERM);
1400 
1401 	/*
1402 	 * If the MLS label is to be changed, authorize as appropriate.
1403 	 */
1404 	if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
1405 		/*
1406 		 * To change the MLS label on a pipe, the new pipe label must
1407 		 * be in the subject range.
1408 		 */
1409 		if (!mls_effective_in_range(new, subj))
1410 			return (EPERM);
1411 
1412 		/*
1413 		 * To change the MLS label on a pipe to be EQUAL, the subject
1414 		 * must have appropriate privilege.
1415 		 */
1416 		if (mls_contains_equal(new)) {
1417 			error = mls_subject_privileged(subj);
1418 			if (error)
1419 				return (error);
1420 		}
1421 	}
1422 
1423 	return (0);
1424 }
1425 
1426 static int
1427 mls_pipe_check_stat(struct ucred *cred, struct pipepair *pp,
1428     struct label *pplabel)
1429 {
1430 	struct mac_mls *subj, *obj;
1431 
1432 	if (!mls_enabled)
1433 		return (0);
1434 
1435 	subj = SLOT(cred->cr_label);
1436 	obj = SLOT(pplabel);
1437 
1438 	if (!mls_dominate_effective(subj, obj))
1439 		return (EACCES);
1440 
1441 	return (0);
1442 }
1443 
1444 static int
1445 mls_pipe_check_write(struct ucred *cred, struct pipepair *pp,
1446     struct label *pplabel)
1447 {
1448 	struct mac_mls *subj, *obj;
1449 
1450 	if (!mls_enabled)
1451 		return (0);
1452 
1453 	subj = SLOT(cred->cr_label);
1454 	obj = SLOT(pplabel);
1455 
1456 	if (!mls_dominate_effective(obj, subj))
1457 		return (EACCES);
1458 
1459 	return (0);
1460 }
1461 
1462 static void
1463 mls_pipe_create(struct ucred *cred, struct pipepair *pp,
1464     struct label *pplabel)
1465 {
1466 	struct mac_mls *source, *dest;
1467 
1468 	source = SLOT(cred->cr_label);
1469 	dest = SLOT(pplabel);
1470 
1471 	mls_copy_effective(source, dest);
1472 }
1473 
1474 static void
1475 mls_pipe_relabel(struct ucred *cred, struct pipepair *pp,
1476     struct label *pplabel, struct label *newlabel)
1477 {
1478 	struct mac_mls *source, *dest;
1479 
1480 	source = SLOT(newlabel);
1481 	dest = SLOT(pplabel);
1482 
1483 	mls_copy(source, dest);
1484 }
1485 
1486 static int
1487 mls_posixsem_check_openunlink(struct ucred *cred, struct ksem *ks,
1488     struct label *kslabel)
1489 {
1490 	struct mac_mls *subj, *obj;
1491 
1492 	if (!mls_enabled)
1493 		return (0);
1494 
1495 	subj = SLOT(cred->cr_label);
1496 	obj = SLOT(kslabel);
1497 
1498 	if (!mls_dominate_effective(obj, subj))
1499 		return (EACCES);
1500 
1501 	return (0);
1502 }
1503 
1504 static int
1505 mls_posixsem_check_rdonly(struct ucred *active_cred, struct ucred *file_cred,
1506     struct ksem *ks, struct label *kslabel)
1507 {
1508 	struct mac_mls *subj, *obj;
1509 
1510 	if (!mls_enabled)
1511 		return (0);
1512 
1513 	subj = SLOT(active_cred->cr_label);
1514 	obj = SLOT(kslabel);
1515 
1516 	if (!mls_dominate_effective(subj, obj))
1517 		return (EACCES);
1518 
1519 	return (0);
1520 }
1521 
1522 static int
1523 mls_posixsem_check_setmode(struct ucred *cred, struct ksem *ks,
1524     struct label *shmlabel, mode_t mode)
1525 {
1526 	struct mac_mls *subj, *obj;
1527 
1528 	if (!mls_enabled)
1529 		return (0);
1530 
1531 	subj = SLOT(cred->cr_label);
1532 	obj = SLOT(shmlabel);
1533 
1534 	if (!mls_dominate_effective(obj, subj))
1535 		return (EACCES);
1536 
1537 	return (0);
1538 }
1539 
1540 static int
1541 mls_posixsem_check_setowner(struct ucred *cred, struct ksem *ks,
1542     struct label *shmlabel, uid_t uid, gid_t gid)
1543 {
1544 	struct mac_mls *subj, *obj;
1545 
1546 	if (!mls_enabled)
1547 		return (0);
1548 
1549 	subj = SLOT(cred->cr_label);
1550 	obj = SLOT(shmlabel);
1551 
1552 	if (!mls_dominate_effective(obj, subj))
1553 		return (EACCES);
1554 
1555 	return (0);
1556 }
1557 
1558 static int
1559 mls_posixsem_check_write(struct ucred *active_cred, struct ucred *file_cred,
1560     struct ksem *ks, struct label *kslabel)
1561 {
1562 	struct mac_mls *subj, *obj;
1563 
1564 	if (!mls_enabled)
1565 		return (0);
1566 
1567 	subj = SLOT(active_cred->cr_label);
1568 	obj = SLOT(kslabel);
1569 
1570 	if (!mls_dominate_effective(obj, subj))
1571 		return (EACCES);
1572 
1573 	return (0);
1574 }
1575 
1576 static void
1577 mls_posixsem_create(struct ucred *cred, struct ksem *ks,
1578     struct label *kslabel)
1579 {
1580 	struct mac_mls *source, *dest;
1581 
1582 	source = SLOT(cred->cr_label);
1583 	dest = SLOT(kslabel);
1584 
1585 	mls_copy_effective(source, dest);
1586 }
1587 
1588 static int
1589 mls_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd,
1590     struct label *shmlabel, int prot, int flags)
1591 {
1592 	struct mac_mls *subj, *obj;
1593 
1594 	if (!mls_enabled)
1595 		return (0);
1596 
1597 	subj = SLOT(cred->cr_label);
1598 	obj = SLOT(shmlabel);
1599 
1600 	if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
1601 		if (!mls_dominate_effective(subj, obj))
1602 			return (EACCES);
1603 	}
1604 	if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
1605 		if (!mls_dominate_effective(obj, subj))
1606 			return (EACCES);
1607 	}
1608 
1609 	return (0);
1610 }
1611 
1612 static int
1613 mls_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd,
1614     struct label *shmlabel, accmode_t accmode)
1615 {
1616 	struct mac_mls *subj, *obj;
1617 
1618 	if (!mls_enabled)
1619 		return (0);
1620 
1621 	subj = SLOT(cred->cr_label);
1622 	obj = SLOT(shmlabel);
1623 
1624 	if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) {
1625 		if (!mls_dominate_effective(subj, obj))
1626 			return (EACCES);
1627 	}
1628 	if (accmode & VMODIFY_PERMS) {
1629 		if (!mls_dominate_effective(obj, subj))
1630 			return (EACCES);
1631 	}
1632 
1633 	return (0);
1634 }
1635 
1636 static int
1637 mls_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred,
1638     struct shmfd *shm, struct label *shmlabel)
1639 {
1640 	struct mac_mls *subj, *obj;
1641 
1642 	if (!mls_enabled || !revocation_enabled)
1643 		return (0);
1644 
1645 	subj = SLOT(active_cred->cr_label);
1646 	obj = SLOT(shmlabel);
1647 
1648 	if (!mls_dominate_effective(subj, obj))
1649 		return (EACCES);
1650 
1651 	return (0);
1652 }
1653 
1654 static int
1655 mls_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
1656     struct label *shmlabel, mode_t mode)
1657 {
1658 	struct mac_mls *subj, *obj;
1659 
1660 	if (!mls_enabled)
1661 		return (0);
1662 
1663 	subj = SLOT(cred->cr_label);
1664 	obj = SLOT(shmlabel);
1665 
1666 	if (!mls_dominate_effective(obj, subj))
1667 		return (EACCES);
1668 
1669 	return (0);
1670 }
1671 
1672 static int
1673 mls_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd,
1674     struct label *shmlabel, uid_t uid, gid_t gid)
1675 {
1676 	struct mac_mls *subj, *obj;
1677 
1678 	if (!mls_enabled)
1679 		return (0);
1680 
1681 	subj = SLOT(cred->cr_label);
1682 	obj = SLOT(shmlabel);
1683 
1684 	if (!mls_dominate_effective(obj, subj))
1685 		return (EACCES);
1686 
1687 	return (0);
1688 }
1689 
1690 static int
1691 mls_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred,
1692     struct shmfd *shmfd, struct label *shmlabel)
1693 {
1694 	struct mac_mls *subj, *obj;
1695 
1696 	if (!mls_enabled)
1697 		return (0);
1698 
1699 	subj = SLOT(active_cred->cr_label);
1700 	obj = SLOT(shmlabel);
1701 
1702 	if (!mls_dominate_effective(subj, obj))
1703 		return (EACCES);
1704 
1705 	return (0);
1706 }
1707 
1708 static int
1709 mls_posixshm_check_truncate(struct ucred *active_cred,
1710     struct ucred *file_cred, struct shmfd *shmfd, struct label *shmlabel)
1711 {
1712 	struct mac_mls *subj, *obj;
1713 
1714 	if (!mls_enabled)
1715 		return (0);
1716 
1717 	subj = SLOT(active_cred->cr_label);
1718 	obj = SLOT(shmlabel);
1719 
1720 	if (!mls_dominate_effective(obj, subj))
1721 		return (EACCES);
1722 
1723 	return (0);
1724 }
1725 
1726 static int
1727 mls_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd,
1728     struct label *shmlabel)
1729 {
1730 	struct mac_mls *subj, *obj;
1731 
1732 	if (!mls_enabled)
1733 		return (0);
1734 
1735 	subj = SLOT(cred->cr_label);
1736 	obj = SLOT(shmlabel);
1737 
1738 	if (!mls_dominate_effective(obj, subj))
1739 		return (EACCES);
1740 
1741 	return (0);
1742 }
1743 
1744 static int
1745 mls_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred,
1746     struct shmfd *shm, struct label *shmlabel)
1747 {
1748 	struct mac_mls *subj, *obj;
1749 
1750 	if (!mls_enabled || !revocation_enabled)
1751 		return (0);
1752 
1753 	subj = SLOT(active_cred->cr_label);
1754 	obj = SLOT(shmlabel);
1755 
1756 	if (!mls_dominate_effective(subj, obj))
1757 		return (EACCES);
1758 
1759 	return (0);
1760 }
1761 
1762 static void
1763 mls_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
1764     struct label *shmlabel)
1765 {
1766 	struct mac_mls *source, *dest;
1767 
1768 	source = SLOT(cred->cr_label);
1769 	dest = SLOT(shmlabel);
1770 
1771 	mls_copy_effective(source, dest);
1772 }
1773 
1774 static int
1775 mls_proc_check_debug(struct ucred *cred, struct proc *p)
1776 {
1777 	struct mac_mls *subj, *obj;
1778 
1779 	if (!mls_enabled)
1780 		return (0);
1781 
1782 	subj = SLOT(cred->cr_label);
1783 	obj = SLOT(p->p_ucred->cr_label);
1784 
1785 	/* XXX: range checks */
1786 	if (!mls_dominate_effective(subj, obj))
1787 		return (ESRCH);
1788 	if (!mls_dominate_effective(obj, subj))
1789 		return (EACCES);
1790 
1791 	return (0);
1792 }
1793 
1794 static int
1795 mls_proc_check_sched(struct ucred *cred, struct proc *p)
1796 {
1797 	struct mac_mls *subj, *obj;
1798 
1799 	if (!mls_enabled)
1800 		return (0);
1801 
1802 	subj = SLOT(cred->cr_label);
1803 	obj = SLOT(p->p_ucred->cr_label);
1804 
1805 	/* XXX: range checks */
1806 	if (!mls_dominate_effective(subj, obj))
1807 		return (ESRCH);
1808 	if (!mls_dominate_effective(obj, subj))
1809 		return (EACCES);
1810 
1811 	return (0);
1812 }
1813 
1814 static int
1815 mls_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
1816 {
1817 	struct mac_mls *subj, *obj;
1818 
1819 	if (!mls_enabled)
1820 		return (0);
1821 
1822 	subj = SLOT(cred->cr_label);
1823 	obj = SLOT(p->p_ucred->cr_label);
1824 
1825 	/* XXX: range checks */
1826 	if (!mls_dominate_effective(subj, obj))
1827 		return (ESRCH);
1828 	if (!mls_dominate_effective(obj, subj))
1829 		return (EACCES);
1830 
1831 	return (0);
1832 }
1833 
1834 static int
1835 mls_socket_check_deliver(struct socket *so, struct label *solabel,
1836     struct mbuf *m, struct label *mlabel)
1837 {
1838 	struct mac_mls *p, *s;
1839 	int error;
1840 
1841 	if (!mls_enabled)
1842 		return (0);
1843 
1844 	p = SLOT(mlabel);
1845 	s = SLOT(solabel);
1846 
1847 	SOCK_LOCK(so);
1848 	error = mls_equal_effective(p, s) ? 0 : EACCES;
1849 	SOCK_UNLOCK(so);
1850 
1851 	return (error);
1852 }
1853 
1854 static int
1855 mls_socket_check_relabel(struct ucred *cred, struct socket *so,
1856     struct label *solabel, struct label *newlabel)
1857 {
1858 	struct mac_mls *subj, *obj, *new;
1859 	int error;
1860 
1861 	SOCK_LOCK_ASSERT(so);
1862 
1863 	new = SLOT(newlabel);
1864 	subj = SLOT(cred->cr_label);
1865 	obj = SLOT(solabel);
1866 
1867 	/*
1868 	 * If there is an MLS label update for the socket, it may be an
1869 	 * update of effective.
1870 	 */
1871 	error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
1872 	if (error)
1873 		return (error);
1874 
1875 	/*
1876 	 * To relabel a socket, the old socket effective must be in the
1877 	 * subject range.
1878 	 */
1879 	if (!mls_effective_in_range(obj, subj))
1880 		return (EPERM);
1881 
1882 	/*
1883 	 * If the MLS label is to be changed, authorize as appropriate.
1884 	 */
1885 	if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
1886 		/*
1887 		 * To relabel a socket, the new socket effective must be in
1888 		 * the subject range.
1889 		 */
1890 		if (!mls_effective_in_range(new, subj))
1891 			return (EPERM);
1892 
1893 		/*
1894 		 * To change the MLS label on the socket to contain EQUAL,
1895 		 * the subject must have appropriate privilege.
1896 		 */
1897 		if (mls_contains_equal(new)) {
1898 			error = mls_subject_privileged(subj);
1899 			if (error)
1900 				return (error);
1901 		}
1902 	}
1903 
1904 	return (0);
1905 }
1906 
1907 static int
1908 mls_socket_check_visible(struct ucred *cred, struct socket *so,
1909     struct label *solabel)
1910 {
1911 	struct mac_mls *subj, *obj;
1912 
1913 	if (!mls_enabled)
1914 		return (0);
1915 
1916 	subj = SLOT(cred->cr_label);
1917 	obj = SLOT(solabel);
1918 
1919 	SOCK_LOCK(so);
1920 	if (!mls_dominate_effective(subj, obj)) {
1921 		SOCK_UNLOCK(so);
1922 		return (ENOENT);
1923 	}
1924 	SOCK_UNLOCK(so);
1925 
1926 	return (0);
1927 }
1928 
1929 static void
1930 mls_socket_create(struct ucred *cred, struct socket *so,
1931     struct label *solabel)
1932 {
1933 	struct mac_mls *source, *dest;
1934 
1935 	source = SLOT(cred->cr_label);
1936 	dest = SLOT(solabel);
1937 
1938 	mls_copy_effective(source, dest);
1939 }
1940 
1941 static void
1942 mls_socket_create_mbuf(struct socket *so, struct label *solabel,
1943     struct mbuf *m, struct label *mlabel)
1944 {
1945 	struct mac_mls *source, *dest;
1946 
1947 	source = SLOT(solabel);
1948 	dest = SLOT(mlabel);
1949 
1950 	SOCK_LOCK(so);
1951 	mls_copy_effective(source, dest);
1952 	SOCK_UNLOCK(so);
1953 }
1954 
1955 static void
1956 mls_socket_newconn(struct socket *oldso, struct label *oldsolabel,
1957     struct socket *newso, struct label *newsolabel)
1958 {
1959 	struct mac_mls source, *dest;
1960 
1961 	SOCK_LOCK(oldso);
1962 	source = *SLOT(oldsolabel);
1963 	SOCK_UNLOCK(oldso);
1964 
1965 	dest = SLOT(newsolabel);
1966 
1967 	SOCK_LOCK(newso);
1968 	mls_copy_effective(&source, dest);
1969 	SOCK_UNLOCK(newso);
1970 }
1971 
1972 static void
1973 mls_socket_relabel(struct ucred *cred, struct socket *so,
1974     struct label *solabel, struct label *newlabel)
1975 {
1976 	struct mac_mls *source, *dest;
1977 
1978 	SOCK_LOCK_ASSERT(so);
1979 
1980 	source = SLOT(newlabel);
1981 	dest = SLOT(solabel);
1982 
1983 	mls_copy(source, dest);
1984 }
1985 
1986 static void
1987 mls_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
1988     struct socket *so, struct label *sopeerlabel)
1989 {
1990 	struct mac_mls *source, *dest;
1991 
1992 	source = SLOT(mlabel);
1993 	dest = SLOT(sopeerlabel);
1994 
1995 	SOCK_LOCK(so);
1996 	mls_copy_effective(source, dest);
1997 	SOCK_UNLOCK(so);
1998 }
1999 
2000 static void
2001 mls_socketpeer_set_from_socket(struct socket *oldso,
2002     struct label *oldsolabel, struct socket *newso,
2003     struct label *newsopeerlabel)
2004 {
2005 	struct mac_mls source, *dest;
2006 
2007 	SOCK_LOCK(oldso);
2008 	source = *SLOT(oldsolabel);
2009 	SOCK_UNLOCK(oldso);
2010 
2011 	dest = SLOT(newsopeerlabel);
2012 
2013 	SOCK_LOCK(newso);
2014 	mls_copy_effective(&source, dest);
2015 	SOCK_UNLOCK(newso);
2016 }
2017 
2018 static void
2019 mls_syncache_create(struct label *label, struct inpcb *inp)
2020 {
2021 	struct mac_mls *source, *dest;
2022 
2023 	source = SLOT(inp->inp_label);
2024 	dest = SLOT(label);
2025 
2026 	mls_copy_effective(source, dest);
2027 }
2028 
2029 static void
2030 mls_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
2031     struct label *mlabel)
2032 {
2033 	struct mac_mls *source, *dest;
2034 
2035 	source = SLOT(sc_label);
2036 	dest = SLOT(mlabel);
2037 
2038 	mls_copy_effective(source, dest);
2039 }
2040 
2041 static int
2042 mls_system_check_acct(struct ucred *cred, struct vnode *vp,
2043     struct label *vplabel)
2044 {
2045 	struct mac_mls *subj, *obj;
2046 
2047 	if (!mls_enabled)
2048 		return (0);
2049 
2050 	if (vplabel == NULL)
2051 		return (0);
2052 
2053 	subj = SLOT(cred->cr_label);
2054 	obj = SLOT(vplabel);
2055 
2056 	if (!mls_dominate_effective(obj, subj) ||
2057 	    !mls_dominate_effective(subj, obj))
2058 		return (EACCES);
2059 
2060 	return (0);
2061 }
2062 
2063 static int
2064 mls_system_check_auditctl(struct ucred *cred, struct vnode *vp,
2065     struct label *vplabel)
2066 {
2067 	struct mac_mls *subj, *obj;
2068 
2069 	if (!mls_enabled)
2070 		return (0);
2071 
2072 	subj = SLOT(cred->cr_label);
2073 	obj = SLOT(vplabel);
2074 
2075 	if (!mls_dominate_effective(obj, subj) ||
2076 	    !mls_dominate_effective(subj, obj))
2077 		return (EACCES);
2078 
2079 	return (0);
2080 }
2081 
2082 static int
2083 mls_system_check_swapon(struct ucred *cred, struct vnode *vp,
2084     struct label *vplabel)
2085 {
2086 	struct mac_mls *subj, *obj;
2087 
2088 	if (!mls_enabled)
2089 		return (0);
2090 
2091 	subj = SLOT(cred->cr_label);
2092 	obj = SLOT(vplabel);
2093 
2094 	if (!mls_dominate_effective(obj, subj) ||
2095 	    !mls_dominate_effective(subj, obj))
2096 		return (EACCES);
2097 
2098 	return (0);
2099 }
2100 
2101 static void
2102 mls_sysvmsg_cleanup(struct label *msglabel)
2103 {
2104 
2105 	bzero(SLOT(msglabel), sizeof(struct mac_mls));
2106 }
2107 
2108 static void
2109 mls_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
2110     struct label *msqlabel, struct msg *msgptr, struct label *msglabel)
2111 {
2112 	struct mac_mls *source, *dest;
2113 
2114 	/* Ignore the msgq label. */
2115 	source = SLOT(cred->cr_label);
2116 	dest = SLOT(msglabel);
2117 
2118 	mls_copy_effective(source, dest);
2119 }
2120 
2121 static int
2122 mls_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr,
2123     struct label *msglabel)
2124 {
2125 	struct mac_mls *subj, *obj;
2126 
2127 	if (!mls_enabled)
2128 		return (0);
2129 
2130 	subj = SLOT(cred->cr_label);
2131 	obj = SLOT(msglabel);
2132 
2133 	if (!mls_dominate_effective(subj, obj))
2134 		return (EACCES);
2135 
2136 	return (0);
2137 }
2138 
2139 static int
2140 mls_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr,
2141     struct label *msglabel)
2142 {
2143 	struct mac_mls *subj, *obj;
2144 
2145 	if (!mls_enabled)
2146 		return (0);
2147 
2148 	subj = SLOT(cred->cr_label);
2149 	obj = SLOT(msglabel);
2150 
2151 	if (!mls_dominate_effective(obj, subj))
2152 		return (EACCES);
2153 
2154 	return (0);
2155 }
2156 
2157 static int
2158 mls_sysvmsq_check_msqget(struct ucred *cred, struct msqid_kernel *msqkptr,
2159     struct label *msqklabel)
2160 {
2161 	struct mac_mls *subj, *obj;
2162 
2163 	if (!mls_enabled)
2164 		return (0);
2165 
2166 	subj = SLOT(cred->cr_label);
2167 	obj = SLOT(msqklabel);
2168 
2169 	if (!mls_dominate_effective(subj, obj))
2170 		return (EACCES);
2171 
2172 	return (0);
2173 }
2174 
2175 static int
2176 mls_sysvmsq_check_msqsnd(struct ucred *cred, struct msqid_kernel *msqkptr,
2177     struct label *msqklabel)
2178 {
2179 	struct mac_mls *subj, *obj;
2180 
2181 	if (!mls_enabled)
2182 		return (0);
2183 
2184 	subj = SLOT(cred->cr_label);
2185 	obj = SLOT(msqklabel);
2186 
2187 	if (!mls_dominate_effective(obj, subj))
2188 		return (EACCES);
2189 
2190 	return (0);
2191 }
2192 
2193 static int
2194 mls_sysvmsq_check_msqrcv(struct ucred *cred, struct msqid_kernel *msqkptr,
2195     struct label *msqklabel)
2196 {
2197 	struct mac_mls *subj, *obj;
2198 
2199 	if (!mls_enabled)
2200 		return (0);
2201 
2202 	subj = SLOT(cred->cr_label);
2203 	obj = SLOT(msqklabel);
2204 
2205 	if (!mls_dominate_effective(subj, obj))
2206 		return (EACCES);
2207 
2208 	return (0);
2209 }
2210 
2211 static int
2212 mls_sysvmsq_check_msqctl(struct ucred *cred, struct msqid_kernel *msqkptr,
2213     struct label *msqklabel, int cmd)
2214 {
2215 	struct mac_mls *subj, *obj;
2216 
2217 	if (!mls_enabled)
2218 		return (0);
2219 
2220 	subj = SLOT(cred->cr_label);
2221 	obj = SLOT(msqklabel);
2222 
2223 	switch(cmd) {
2224 	case IPC_RMID:
2225 	case IPC_SET:
2226 		if (!mls_dominate_effective(obj, subj))
2227 			return (EACCES);
2228 		break;
2229 
2230 	case IPC_STAT:
2231 		if (!mls_dominate_effective(subj, obj))
2232 			return (EACCES);
2233 		break;
2234 
2235 	default:
2236 		return (EACCES);
2237 	}
2238 
2239 	return (0);
2240 }
2241 
2242 static void
2243 mls_sysvmsq_cleanup(struct label *msqlabel)
2244 {
2245 
2246 	bzero(SLOT(msqlabel), sizeof(struct mac_mls));
2247 }
2248 
2249 static void
2250 mls_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr,
2251     struct label *msqlabel)
2252 {
2253 	struct mac_mls *source, *dest;
2254 
2255 	source = SLOT(cred->cr_label);
2256 	dest = SLOT(msqlabel);
2257 
2258 	mls_copy_effective(source, dest);
2259 }
2260 
2261 static int
2262 mls_sysvsem_check_semctl(struct ucred *cred, struct semid_kernel *semakptr,
2263     struct label *semaklabel, int cmd)
2264 {
2265 	struct mac_mls *subj, *obj;
2266 
2267 	if (!mls_enabled)
2268 		return (0);
2269 
2270 	subj = SLOT(cred->cr_label);
2271 	obj = SLOT(semaklabel);
2272 
2273 	switch(cmd) {
2274 	case IPC_RMID:
2275 	case IPC_SET:
2276 	case SETVAL:
2277 	case SETALL:
2278 		if (!mls_dominate_effective(obj, subj))
2279 			return (EACCES);
2280 		break;
2281 
2282 	case IPC_STAT:
2283 	case GETVAL:
2284 	case GETPID:
2285 	case GETNCNT:
2286 	case GETZCNT:
2287 	case GETALL:
2288 		if (!mls_dominate_effective(subj, obj))
2289 			return (EACCES);
2290 		break;
2291 
2292 	default:
2293 		return (EACCES);
2294 	}
2295 
2296 	return (0);
2297 }
2298 
2299 static int
2300 mls_sysvsem_check_semget(struct ucred *cred, struct semid_kernel *semakptr,
2301     struct label *semaklabel)
2302 {
2303 	struct mac_mls *subj, *obj;
2304 
2305 	if (!mls_enabled)
2306 		return (0);
2307 
2308 	subj = SLOT(cred->cr_label);
2309 	obj = SLOT(semaklabel);
2310 
2311 	if (!mls_dominate_effective(subj, obj))
2312 		return (EACCES);
2313 
2314 	return (0);
2315 }
2316 
2317 static int
2318 mls_sysvsem_check_semop(struct ucred *cred, struct semid_kernel *semakptr,
2319     struct label *semaklabel, size_t accesstype)
2320 {
2321 	struct mac_mls *subj, *obj;
2322 
2323 	if (!mls_enabled)
2324 		return (0);
2325 
2326 	subj = SLOT(cred->cr_label);
2327 	obj = SLOT(semaklabel);
2328 
2329 	if( accesstype & SEM_R )
2330 		if (!mls_dominate_effective(subj, obj))
2331 			return (EACCES);
2332 
2333 	if( accesstype & SEM_A )
2334 		if (!mls_dominate_effective(obj, subj))
2335 			return (EACCES);
2336 
2337 	return (0);
2338 }
2339 
2340 static void
2341 mls_sysvsem_cleanup(struct label *semalabel)
2342 {
2343 
2344 	bzero(SLOT(semalabel), sizeof(struct mac_mls));
2345 }
2346 
2347 static void
2348 mls_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr,
2349     struct label *semalabel)
2350 {
2351 	struct mac_mls *source, *dest;
2352 
2353 	source = SLOT(cred->cr_label);
2354 	dest = SLOT(semalabel);
2355 
2356 	mls_copy_effective(source, dest);
2357 }
2358 
2359 static int
2360 mls_sysvshm_check_shmat(struct ucred *cred, struct shmid_kernel *shmsegptr,
2361     struct label *shmseglabel, int shmflg)
2362 {
2363 	struct mac_mls *subj, *obj;
2364 
2365 	if (!mls_enabled)
2366 		return (0);
2367 
2368 	subj = SLOT(cred->cr_label);
2369 	obj = SLOT(shmseglabel);
2370 
2371 	if (!mls_dominate_effective(subj, obj))
2372 		return (EACCES);
2373 	if ((shmflg & SHM_RDONLY) == 0) {
2374 		if (!mls_dominate_effective(obj, subj))
2375 			return (EACCES);
2376 	}
2377 
2378 	return (0);
2379 }
2380 
2381 static int
2382 mls_sysvshm_check_shmctl(struct ucred *cred, struct shmid_kernel *shmsegptr,
2383     struct label *shmseglabel, int cmd)
2384 {
2385 	struct mac_mls *subj, *obj;
2386 
2387 	if (!mls_enabled)
2388 		return (0);
2389 
2390 	subj = SLOT(cred->cr_label);
2391 	obj = SLOT(shmseglabel);
2392 
2393 	switch(cmd) {
2394 	case IPC_RMID:
2395 	case IPC_SET:
2396 		if (!mls_dominate_effective(obj, subj))
2397 			return (EACCES);
2398 		break;
2399 
2400 	case IPC_STAT:
2401 	case SHM_STAT:
2402 		if (!mls_dominate_effective(subj, obj))
2403 			return (EACCES);
2404 		break;
2405 
2406 	default:
2407 		return (EACCES);
2408 	}
2409 
2410 	return (0);
2411 }
2412 
2413 static int
2414 mls_sysvshm_check_shmget(struct ucred *cred, struct shmid_kernel *shmsegptr,
2415     struct label *shmseglabel, int shmflg)
2416 {
2417 	struct mac_mls *subj, *obj;
2418 
2419 	if (!mls_enabled)
2420 		return (0);
2421 
2422 	subj = SLOT(cred->cr_label);
2423 	obj = SLOT(shmseglabel);
2424 
2425 	if (!mls_dominate_effective(obj, subj))
2426 		return (EACCES);
2427 
2428 	return (0);
2429 }
2430 
2431 static void
2432 mls_sysvshm_cleanup(struct label *shmlabel)
2433 {
2434 
2435 	bzero(SLOT(shmlabel), sizeof(struct mac_mls));
2436 }
2437 
2438 static void
2439 mls_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr,
2440     struct label *shmlabel)
2441 {
2442 	struct mac_mls *source, *dest;
2443 
2444 	source = SLOT(cred->cr_label);
2445 	dest = SLOT(shmlabel);
2446 
2447 	mls_copy_effective(source, dest);
2448 }
2449 
2450 static int
2451 mls_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
2452     struct vnode *vp, struct label *vplabel)
2453 {
2454 	struct mac_mls mm_temp, *source, *dest;
2455 	int buflen, error;
2456 
2457 	source = SLOT(mplabel);
2458 	dest = SLOT(vplabel);
2459 
2460 	buflen = sizeof(mm_temp);
2461 	bzero(&mm_temp, buflen);
2462 
2463 	error = vn_extattr_get(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
2464 	    MAC_MLS_EXTATTR_NAME, &buflen, (char *) &mm_temp, curthread);
2465 	if (error == ENOATTR || error == EOPNOTSUPP) {
2466 		/* Fall back to the mntlabel. */
2467 		mls_copy_effective(source, dest);
2468 		return (0);
2469 	} else if (error)
2470 		return (error);
2471 
2472 	if (buflen != sizeof(mm_temp)) {
2473 		printf("mls_vnode_associate_extattr: bad size %d\n", buflen);
2474 		return (EPERM);
2475 	}
2476 	if (mls_valid(&mm_temp) != 0) {
2477 		printf("mls_vnode_associate_extattr: invalid\n");
2478 		return (EPERM);
2479 	}
2480 	if ((mm_temp.mm_flags & MAC_MLS_FLAGS_BOTH) !=
2481 	    MAC_MLS_FLAG_EFFECTIVE) {
2482 		printf("mls_associated_vnode_extattr: not effective\n");
2483 		return (EPERM);
2484 	}
2485 
2486 	mls_copy_effective(&mm_temp, dest);
2487 	return (0);
2488 }
2489 
2490 static void
2491 mls_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
2492     struct vnode *vp, struct label *vplabel)
2493 {
2494 	struct mac_mls *source, *dest;
2495 
2496 	source = SLOT(mplabel);
2497 	dest = SLOT(vplabel);
2498 
2499 	mls_copy_effective(source, dest);
2500 }
2501 
2502 static int
2503 mls_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
2504     struct label *dvplabel)
2505 {
2506 	struct mac_mls *subj, *obj;
2507 
2508 	if (!mls_enabled)
2509 		return (0);
2510 
2511 	subj = SLOT(cred->cr_label);
2512 	obj = SLOT(dvplabel);
2513 
2514 	if (!mls_dominate_effective(subj, obj))
2515 		return (EACCES);
2516 
2517 	return (0);
2518 }
2519 
2520 static int
2521 mls_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
2522     struct label *dvplabel)
2523 {
2524 	struct mac_mls *subj, *obj;
2525 
2526 	if (!mls_enabled)
2527 		return (0);
2528 
2529 	subj = SLOT(cred->cr_label);
2530 	obj = SLOT(dvplabel);
2531 
2532 	if (!mls_dominate_effective(subj, obj))
2533 		return (EACCES);
2534 
2535 	return (0);
2536 }
2537 
2538 static int
2539 mls_vnode_check_create(struct ucred *cred, struct vnode *dvp,
2540     struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
2541 {
2542 	struct mac_mls *subj, *obj;
2543 
2544 	if (!mls_enabled)
2545 		return (0);
2546 
2547 	subj = SLOT(cred->cr_label);
2548 	obj = SLOT(dvplabel);
2549 
2550 	if (!mls_dominate_effective(obj, subj))
2551 		return (EACCES);
2552 
2553 	return (0);
2554 }
2555 
2556 static int
2557 mls_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
2558     struct label *vplabel, acl_type_t type)
2559 {
2560 	struct mac_mls *subj, *obj;
2561 
2562 	if (!mls_enabled)
2563 		return (0);
2564 
2565 	subj = SLOT(cred->cr_label);
2566 	obj = SLOT(vplabel);
2567 
2568 	if (!mls_dominate_effective(obj, subj))
2569 		return (EACCES);
2570 
2571 	return (0);
2572 }
2573 
2574 static int
2575 mls_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
2576     struct label *vplabel, int attrnamespace, const char *name)
2577 {
2578 	struct mac_mls *subj, *obj;
2579 
2580 	if (!mls_enabled)
2581 		return (0);
2582 
2583 	subj = SLOT(cred->cr_label);
2584 	obj = SLOT(vplabel);
2585 
2586 	if (!mls_dominate_effective(obj, subj))
2587 		return (EACCES);
2588 
2589 	return (0);
2590 }
2591 
2592 static int
2593 mls_vnode_check_exec(struct ucred *cred, struct vnode *vp,
2594     struct label *vplabel, struct image_params *imgp,
2595     struct label *execlabel)
2596 {
2597 	struct mac_mls *subj, *obj, *exec;
2598 	int error;
2599 
2600 	if (execlabel != NULL) {
2601 		/*
2602 		 * We currently don't permit labels to be changed at
2603 		 * exec-time as part of MLS, so disallow non-NULL MLS label
2604 		 * elements in the execlabel.
2605 		 */
2606 		exec = SLOT(execlabel);
2607 		error = mls_atmostflags(exec, 0);
2608 		if (error)
2609 			return (error);
2610 	}
2611 
2612 	if (!mls_enabled)
2613 		return (0);
2614 
2615 	subj = SLOT(cred->cr_label);
2616 	obj = SLOT(vplabel);
2617 
2618 	if (!mls_dominate_effective(subj, obj))
2619 		return (EACCES);
2620 
2621 	return (0);
2622 }
2623 
2624 static int
2625 mls_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
2626     struct label *vplabel, acl_type_t type)
2627 {
2628 	struct mac_mls *subj, *obj;
2629 
2630 	if (!mls_enabled)
2631 		return (0);
2632 
2633 	subj = SLOT(cred->cr_label);
2634 	obj = SLOT(vplabel);
2635 
2636 	if (!mls_dominate_effective(subj, obj))
2637 		return (EACCES);
2638 
2639 	return (0);
2640 }
2641 
2642 static int
2643 mls_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
2644     struct label *vplabel, int attrnamespace, const char *name)
2645 {
2646 	struct mac_mls *subj, *obj;
2647 
2648 	if (!mls_enabled)
2649 		return (0);
2650 
2651 	subj = SLOT(cred->cr_label);
2652 	obj = SLOT(vplabel);
2653 
2654 	if (!mls_dominate_effective(subj, obj))
2655 		return (EACCES);
2656 
2657 	return (0);
2658 }
2659 
2660 static int
2661 mls_vnode_check_link(struct ucred *cred, struct vnode *dvp,
2662     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2663     struct componentname *cnp)
2664 {
2665 	struct mac_mls *subj, *obj;
2666 
2667 	if (!mls_enabled)
2668 		return (0);
2669 
2670 	subj = SLOT(cred->cr_label);
2671 	obj = SLOT(dvplabel);
2672 
2673 	if (!mls_dominate_effective(obj, subj))
2674 		return (EACCES);
2675 
2676 	obj = SLOT(vplabel);
2677 	if (!mls_dominate_effective(obj, subj))
2678 		return (EACCES);
2679 
2680 	return (0);
2681 }
2682 
2683 static int
2684 mls_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
2685     struct label *vplabel, int attrnamespace)
2686 {
2687 
2688 	struct mac_mls *subj, *obj;
2689 
2690 	if (!mls_enabled)
2691 		return (0);
2692 
2693 	subj = SLOT(cred->cr_label);
2694 	obj = SLOT(vplabel);
2695 
2696 	if (!mls_dominate_effective(subj, obj))
2697 		return (EACCES);
2698 
2699 	return (0);
2700 }
2701 
2702 static int
2703 mls_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
2704     struct label *dvplabel, struct componentname *cnp)
2705 {
2706 	struct mac_mls *subj, *obj;
2707 
2708 	if (!mls_enabled)
2709 		return (0);
2710 
2711 	subj = SLOT(cred->cr_label);
2712 	obj = SLOT(dvplabel);
2713 
2714 	if (!mls_dominate_effective(subj, obj))
2715 		return (EACCES);
2716 
2717 	return (0);
2718 }
2719 
2720 static int
2721 mls_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
2722     struct label *vplabel, int prot, int flags)
2723 {
2724 	struct mac_mls *subj, *obj;
2725 
2726 	/*
2727 	 * Rely on the use of open()-time protections to handle
2728 	 * non-revocation cases.
2729 	 */
2730 	if (!mls_enabled || !revocation_enabled)
2731 		return (0);
2732 
2733 	subj = SLOT(cred->cr_label);
2734 	obj = SLOT(vplabel);
2735 
2736 	if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
2737 		if (!mls_dominate_effective(subj, obj))
2738 			return (EACCES);
2739 	}
2740 	if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
2741 		if (!mls_dominate_effective(obj, subj))
2742 			return (EACCES);
2743 	}
2744 
2745 	return (0);
2746 }
2747 
2748 static int
2749 mls_vnode_check_open(struct ucred *cred, struct vnode *vp,
2750     struct label *vplabel, accmode_t accmode)
2751 {
2752 	struct mac_mls *subj, *obj;
2753 
2754 	if (!mls_enabled)
2755 		return (0);
2756 
2757 	subj = SLOT(cred->cr_label);
2758 	obj = SLOT(vplabel);
2759 
2760 	/* XXX privilege override for admin? */
2761 	if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) {
2762 		if (!mls_dominate_effective(subj, obj))
2763 			return (EACCES);
2764 	}
2765 	if (accmode & VMODIFY_PERMS) {
2766 		if (!mls_dominate_effective(obj, subj))
2767 			return (EACCES);
2768 	}
2769 
2770 	return (0);
2771 }
2772 
2773 static int
2774 mls_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
2775     struct vnode *vp, struct label *vplabel)
2776 {
2777 	struct mac_mls *subj, *obj;
2778 
2779 	if (!mls_enabled || !revocation_enabled)
2780 		return (0);
2781 
2782 	subj = SLOT(active_cred->cr_label);
2783 	obj = SLOT(vplabel);
2784 
2785 	if (!mls_dominate_effective(subj, obj))
2786 		return (EACCES);
2787 
2788 	return (0);
2789 }
2790 
2791 static int
2792 mls_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
2793     struct vnode *vp, struct label *vplabel)
2794 {
2795 	struct mac_mls *subj, *obj;
2796 
2797 	if (!mls_enabled || !revocation_enabled)
2798 		return (0);
2799 
2800 	subj = SLOT(active_cred->cr_label);
2801 	obj = SLOT(vplabel);
2802 
2803 	if (!mls_dominate_effective(subj, obj))
2804 		return (EACCES);
2805 
2806 	return (0);
2807 }
2808 
2809 static int
2810 mls_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
2811     struct label *dvplabel)
2812 {
2813 	struct mac_mls *subj, *obj;
2814 
2815 	if (!mls_enabled)
2816 		return (0);
2817 
2818 	subj = SLOT(cred->cr_label);
2819 	obj = SLOT(dvplabel);
2820 
2821 	if (!mls_dominate_effective(subj, obj))
2822 		return (EACCES);
2823 
2824 	return (0);
2825 }
2826 
2827 static int
2828 mls_vnode_check_readlink(struct ucred *cred, struct vnode *vp,
2829     struct label *vplabel)
2830 {
2831 	struct mac_mls *subj, *obj;
2832 
2833 	if (!mls_enabled)
2834 		return (0);
2835 
2836 	subj = SLOT(cred->cr_label);
2837 	obj = SLOT(vplabel);
2838 
2839 	if (!mls_dominate_effective(subj, obj))
2840 		return (EACCES);
2841 
2842 	return (0);
2843 }
2844 
2845 static int
2846 mls_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
2847     struct label *vplabel, struct label *newlabel)
2848 {
2849 	struct mac_mls *old, *new, *subj;
2850 	int error;
2851 
2852 	old = SLOT(vplabel);
2853 	new = SLOT(newlabel);
2854 	subj = SLOT(cred->cr_label);
2855 
2856 	/*
2857 	 * If there is an MLS label update for the vnode, it must be a
2858 	 * effective label.
2859 	 */
2860 	error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
2861 	if (error)
2862 		return (error);
2863 
2864 	/*
2865 	 * To perform a relabel of the vnode (MLS label or not), MLS must
2866 	 * authorize the relabel.
2867 	 */
2868 	if (!mls_effective_in_range(old, subj))
2869 		return (EPERM);
2870 
2871 	/*
2872 	 * If the MLS label is to be changed, authorize as appropriate.
2873 	 */
2874 	if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
2875 		/*
2876 		 * To change the MLS label on a vnode, the new vnode label
2877 		 * must be in the subject range.
2878 		 */
2879 		if (!mls_effective_in_range(new, subj))
2880 			return (EPERM);
2881 
2882 		/*
2883 		 * To change the MLS label on the vnode to be EQUAL, the
2884 		 * subject must have appropriate privilege.
2885 		 */
2886 		if (mls_contains_equal(new)) {
2887 			error = mls_subject_privileged(subj);
2888 			if (error)
2889 				return (error);
2890 		}
2891 	}
2892 
2893 	return (0);
2894 }
2895 
2896 static int
2897 mls_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
2898     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2899     struct componentname *cnp)
2900 {
2901 	struct mac_mls *subj, *obj;
2902 
2903 	if (!mls_enabled)
2904 		return (0);
2905 
2906 	subj = SLOT(cred->cr_label);
2907 	obj = SLOT(dvplabel);
2908 
2909 	if (!mls_dominate_effective(obj, subj))
2910 		return (EACCES);
2911 
2912 	obj = SLOT(vplabel);
2913 
2914 	if (!mls_dominate_effective(obj, subj))
2915 		return (EACCES);
2916 
2917 	return (0);
2918 }
2919 
2920 static int
2921 mls_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
2922     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2923     int samedir, struct componentname *cnp)
2924 {
2925 	struct mac_mls *subj, *obj;
2926 
2927 	if (!mls_enabled)
2928 		return (0);
2929 
2930 	subj = SLOT(cred->cr_label);
2931 	obj = SLOT(dvplabel);
2932 
2933 	if (!mls_dominate_effective(obj, subj))
2934 		return (EACCES);
2935 
2936 	if (vp != NULL) {
2937 		obj = SLOT(vplabel);
2938 
2939 		if (!mls_dominate_effective(obj, subj))
2940 			return (EACCES);
2941 	}
2942 
2943 	return (0);
2944 }
2945 
2946 static int
2947 mls_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
2948     struct label *vplabel)
2949 {
2950 	struct mac_mls *subj, *obj;
2951 
2952 	if (!mls_enabled)
2953 		return (0);
2954 
2955 	subj = SLOT(cred->cr_label);
2956 	obj = SLOT(vplabel);
2957 
2958 	if (!mls_dominate_effective(obj, subj))
2959 		return (EACCES);
2960 
2961 	return (0);
2962 }
2963 
2964 static int
2965 mls_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
2966     struct label *vplabel, acl_type_t type, struct acl *acl)
2967 {
2968 	struct mac_mls *subj, *obj;
2969 
2970 	if (!mls_enabled)
2971 		return (0);
2972 
2973 	subj = SLOT(cred->cr_label);
2974 	obj = SLOT(vplabel);
2975 
2976 	if (!mls_dominate_effective(obj, subj))
2977 		return (EACCES);
2978 
2979 	return (0);
2980 }
2981 
2982 static int
2983 mls_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
2984     struct label *vplabel, int attrnamespace, const char *name)
2985 {
2986 	struct mac_mls *subj, *obj;
2987 
2988 	if (!mls_enabled)
2989 		return (0);
2990 
2991 	subj = SLOT(cred->cr_label);
2992 	obj = SLOT(vplabel);
2993 
2994 	if (!mls_dominate_effective(obj, subj))
2995 		return (EACCES);
2996 
2997 	/* XXX: protect the MAC EA in a special way? */
2998 
2999 	return (0);
3000 }
3001 
3002 static int
3003 mls_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
3004     struct label *vplabel, u_long flags)
3005 {
3006 	struct mac_mls *subj, *obj;
3007 
3008 	if (!mls_enabled)
3009 		return (0);
3010 
3011 	subj = SLOT(cred->cr_label);
3012 	obj = SLOT(vplabel);
3013 
3014 	if (!mls_dominate_effective(obj, subj))
3015 		return (EACCES);
3016 
3017 	return (0);
3018 }
3019 
3020 static int
3021 mls_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
3022     struct label *vplabel, mode_t mode)
3023 {
3024 	struct mac_mls *subj, *obj;
3025 
3026 	if (!mls_enabled)
3027 		return (0);
3028 
3029 	subj = SLOT(cred->cr_label);
3030 	obj = SLOT(vplabel);
3031 
3032 	if (!mls_dominate_effective(obj, subj))
3033 		return (EACCES);
3034 
3035 	return (0);
3036 }
3037 
3038 static int
3039 mls_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
3040     struct label *vplabel, uid_t uid, gid_t gid)
3041 {
3042 	struct mac_mls *subj, *obj;
3043 
3044 	if (!mls_enabled)
3045 		return (0);
3046 
3047 	subj = SLOT(cred->cr_label);
3048 	obj = SLOT(vplabel);
3049 
3050 	if (!mls_dominate_effective(obj, subj))
3051 		return (EACCES);
3052 
3053 	return (0);
3054 }
3055 
3056 static int
3057 mls_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
3058     struct label *vplabel, struct timespec atime, struct timespec mtime)
3059 {
3060 	struct mac_mls *subj, *obj;
3061 
3062 	if (!mls_enabled)
3063 		return (0);
3064 
3065 	subj = SLOT(cred->cr_label);
3066 	obj = SLOT(vplabel);
3067 
3068 	if (!mls_dominate_effective(obj, subj))
3069 		return (EACCES);
3070 
3071 	return (0);
3072 }
3073 
3074 static int
3075 mls_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
3076     struct vnode *vp, struct label *vplabel)
3077 {
3078 	struct mac_mls *subj, *obj;
3079 
3080 	if (!mls_enabled)
3081 		return (0);
3082 
3083 	subj = SLOT(active_cred->cr_label);
3084 	obj = SLOT(vplabel);
3085 
3086 	if (!mls_dominate_effective(subj, obj))
3087 		return (EACCES);
3088 
3089 	return (0);
3090 }
3091 
3092 static int
3093 mls_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
3094     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
3095     struct componentname *cnp)
3096 {
3097 	struct mac_mls *subj, *obj;
3098 
3099 	if (!mls_enabled)
3100 		return (0);
3101 
3102 	subj = SLOT(cred->cr_label);
3103 	obj = SLOT(dvplabel);
3104 
3105 	if (!mls_dominate_effective(obj, subj))
3106 		return (EACCES);
3107 
3108 	obj = SLOT(vplabel);
3109 
3110 	if (!mls_dominate_effective(obj, subj))
3111 		return (EACCES);
3112 
3113 	return (0);
3114 }
3115 
3116 static int
3117 mls_vnode_check_write(struct ucred *active_cred, struct ucred *file_cred,
3118     struct vnode *vp, struct label *vplabel)
3119 {
3120 	struct mac_mls *subj, *obj;
3121 
3122 	if (!mls_enabled || !revocation_enabled)
3123 		return (0);
3124 
3125 	subj = SLOT(active_cred->cr_label);
3126 	obj = SLOT(vplabel);
3127 
3128 	if (!mls_dominate_effective(obj, subj))
3129 		return (EACCES);
3130 
3131 	return (0);
3132 }
3133 
3134 static int
3135 mls_vnode_create_extattr(struct ucred *cred, struct mount *mp,
3136     struct label *mplabel, struct vnode *dvp, struct label *dvplabel,
3137     struct vnode *vp, struct label *vplabel, struct componentname *cnp)
3138 {
3139 	struct mac_mls *source, *dest, mm_temp;
3140 	size_t buflen;
3141 	int error;
3142 
3143 	buflen = sizeof(mm_temp);
3144 	bzero(&mm_temp, buflen);
3145 
3146 	source = SLOT(cred->cr_label);
3147 	dest = SLOT(vplabel);
3148 	mls_copy_effective(source, &mm_temp);
3149 
3150 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
3151 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
3152 	if (error == 0)
3153 		mls_copy_effective(source, dest);
3154 	return (error);
3155 }
3156 
3157 static void
3158 mls_vnode_relabel(struct ucred *cred, struct vnode *vp,
3159     struct label *vplabel, struct label *label)
3160 {
3161 	struct mac_mls *source, *dest;
3162 
3163 	source = SLOT(label);
3164 	dest = SLOT(vplabel);
3165 
3166 	mls_copy(source, dest);
3167 }
3168 
3169 static int
3170 mls_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
3171     struct label *vplabel, struct label *intlabel)
3172 {
3173 	struct mac_mls *source, mm_temp;
3174 	size_t buflen;
3175 	int error;
3176 
3177 	buflen = sizeof(mm_temp);
3178 	bzero(&mm_temp, buflen);
3179 
3180 	source = SLOT(intlabel);
3181 	if ((source->mm_flags & MAC_MLS_FLAG_EFFECTIVE) == 0)
3182 		return (0);
3183 
3184 	mls_copy_effective(source, &mm_temp);
3185 
3186 	error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
3187 	    MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
3188 	return (error);
3189 }
3190 
3191 static struct mac_policy_ops mls_ops =
3192 {
3193 	.mpo_init = mls_init,
3194 
3195 	.mpo_bpfdesc_check_receive = mls_bpfdesc_check_receive,
3196 	.mpo_bpfdesc_create = mls_bpfdesc_create,
3197 	.mpo_bpfdesc_create_mbuf = mls_bpfdesc_create_mbuf,
3198 	.mpo_bpfdesc_destroy_label = mls_destroy_label,
3199 	.mpo_bpfdesc_init_label = mls_init_label,
3200 
3201 	.mpo_cred_associate_nfsd = mls_cred_associate_nfsd,
3202 	.mpo_cred_check_relabel = mls_cred_check_relabel,
3203 	.mpo_cred_check_visible = mls_cred_check_visible,
3204 	.mpo_cred_copy_label = mls_copy_label,
3205 	.mpo_cred_create_init = mls_cred_create_init,
3206 	.mpo_cred_create_swapper = mls_cred_create_swapper,
3207 	.mpo_cred_destroy_label = mls_destroy_label,
3208 	.mpo_cred_externalize_label = mls_externalize_label,
3209 	.mpo_cred_init_label = mls_init_label,
3210 	.mpo_cred_internalize_label = mls_internalize_label,
3211 	.mpo_cred_relabel = mls_cred_relabel,
3212 
3213 	.mpo_devfs_create_device = mls_devfs_create_device,
3214 	.mpo_devfs_create_directory = mls_devfs_create_directory,
3215 	.mpo_devfs_create_symlink = mls_devfs_create_symlink,
3216 	.mpo_devfs_destroy_label = mls_destroy_label,
3217 	.mpo_devfs_init_label = mls_init_label,
3218 	.mpo_devfs_update = mls_devfs_update,
3219 	.mpo_devfs_vnode_associate = mls_devfs_vnode_associate,
3220 
3221 	.mpo_ifnet_check_relabel = mls_ifnet_check_relabel,
3222 	.mpo_ifnet_check_transmit = mls_ifnet_check_transmit,
3223 	.mpo_ifnet_copy_label = mls_copy_label,
3224 	.mpo_ifnet_create = mls_ifnet_create,
3225 	.mpo_ifnet_create_mbuf = mls_ifnet_create_mbuf,
3226 	.mpo_ifnet_destroy_label = mls_destroy_label,
3227 	.mpo_ifnet_externalize_label = mls_externalize_label,
3228 	.mpo_ifnet_init_label = mls_init_label,
3229 	.mpo_ifnet_internalize_label = mls_internalize_label,
3230 	.mpo_ifnet_relabel = mls_ifnet_relabel,
3231 
3232 	.mpo_inpcb_check_deliver = mls_inpcb_check_deliver,
3233 	.mpo_inpcb_check_visible = mls_inpcb_check_visible,
3234 	.mpo_inpcb_create = mls_inpcb_create,
3235 	.mpo_inpcb_create_mbuf = mls_inpcb_create_mbuf,
3236 	.mpo_inpcb_destroy_label = mls_destroy_label,
3237 	.mpo_inpcb_init_label = mls_init_label_waitcheck,
3238 	.mpo_inpcb_sosetlabel = mls_inpcb_sosetlabel,
3239 
3240 	.mpo_ip6q_create = mls_ip6q_create,
3241 	.mpo_ip6q_destroy_label = mls_destroy_label,
3242 	.mpo_ip6q_init_label = mls_init_label_waitcheck,
3243 	.mpo_ip6q_match = mls_ip6q_match,
3244 	.mpo_ip6q_reassemble = mls_ip6q_reassemble,
3245 	.mpo_ip6q_update = mls_ip6q_update,
3246 
3247 	.mpo_ipq_create = mls_ipq_create,
3248 	.mpo_ipq_destroy_label = mls_destroy_label,
3249 	.mpo_ipq_init_label = mls_init_label_waitcheck,
3250 	.mpo_ipq_match = mls_ipq_match,
3251 	.mpo_ipq_reassemble = mls_ipq_reassemble,
3252 	.mpo_ipq_update = mls_ipq_update,
3253 
3254 	.mpo_mbuf_copy_label = mls_copy_label,
3255 	.mpo_mbuf_destroy_label = mls_destroy_label,
3256 	.mpo_mbuf_init_label = mls_init_label_waitcheck,
3257 
3258 	.mpo_mount_check_stat = mls_mount_check_stat,
3259 	.mpo_mount_create = mls_mount_create,
3260 	.mpo_mount_destroy_label = mls_destroy_label,
3261 	.mpo_mount_init_label = mls_init_label,
3262 
3263 	.mpo_netinet_arp_send = mls_netinet_arp_send,
3264 	.mpo_netinet_firewall_reply = mls_netinet_firewall_reply,
3265 	.mpo_netinet_firewall_send = mls_netinet_firewall_send,
3266 	.mpo_netinet_fragment = mls_netinet_fragment,
3267 	.mpo_netinet_icmp_reply = mls_netinet_icmp_reply,
3268 	.mpo_netinet_igmp_send = mls_netinet_igmp_send,
3269 
3270 	.mpo_netinet6_nd6_send = mls_netinet6_nd6_send,
3271 
3272 	.mpo_pipe_check_ioctl = mls_pipe_check_ioctl,
3273 	.mpo_pipe_check_poll = mls_pipe_check_poll,
3274 	.mpo_pipe_check_read = mls_pipe_check_read,
3275 	.mpo_pipe_check_relabel = mls_pipe_check_relabel,
3276 	.mpo_pipe_check_stat = mls_pipe_check_stat,
3277 	.mpo_pipe_check_write = mls_pipe_check_write,
3278 	.mpo_pipe_copy_label = mls_copy_label,
3279 	.mpo_pipe_create = mls_pipe_create,
3280 	.mpo_pipe_destroy_label = mls_destroy_label,
3281 	.mpo_pipe_externalize_label = mls_externalize_label,
3282 	.mpo_pipe_init_label = mls_init_label,
3283 	.mpo_pipe_internalize_label = mls_internalize_label,
3284 	.mpo_pipe_relabel = mls_pipe_relabel,
3285 
3286 	.mpo_posixsem_check_getvalue = mls_posixsem_check_rdonly,
3287 	.mpo_posixsem_check_open = mls_posixsem_check_openunlink,
3288 	.mpo_posixsem_check_post = mls_posixsem_check_write,
3289 	.mpo_posixsem_check_setmode = mls_posixsem_check_setmode,
3290 	.mpo_posixsem_check_setowner = mls_posixsem_check_setowner,
3291 	.mpo_posixsem_check_stat = mls_posixsem_check_rdonly,
3292 	.mpo_posixsem_check_unlink = mls_posixsem_check_openunlink,
3293 	.mpo_posixsem_check_wait = mls_posixsem_check_write,
3294 	.mpo_posixsem_create = mls_posixsem_create,
3295 	.mpo_posixsem_destroy_label = mls_destroy_label,
3296 	.mpo_posixsem_init_label = mls_init_label,
3297 
3298 	.mpo_posixshm_check_mmap = mls_posixshm_check_mmap,
3299 	.mpo_posixshm_check_open = mls_posixshm_check_open,
3300 	.mpo_posixshm_check_read = mls_posixshm_check_read,
3301 	.mpo_posixshm_check_setmode = mls_posixshm_check_setmode,
3302 	.mpo_posixshm_check_setowner = mls_posixshm_check_setowner,
3303 	.mpo_posixshm_check_stat = mls_posixshm_check_stat,
3304 	.mpo_posixshm_check_truncate = mls_posixshm_check_truncate,
3305 	.mpo_posixshm_check_unlink = mls_posixshm_check_unlink,
3306 	.mpo_posixshm_check_write = mls_posixshm_check_write,
3307 	.mpo_posixshm_create = mls_posixshm_create,
3308 	.mpo_posixshm_destroy_label = mls_destroy_label,
3309 	.mpo_posixshm_init_label = mls_init_label,
3310 
3311 	.mpo_proc_check_debug = mls_proc_check_debug,
3312 	.mpo_proc_check_sched = mls_proc_check_sched,
3313 	.mpo_proc_check_signal = mls_proc_check_signal,
3314 
3315 	.mpo_socket_check_deliver = mls_socket_check_deliver,
3316 	.mpo_socket_check_relabel = mls_socket_check_relabel,
3317 	.mpo_socket_check_visible = mls_socket_check_visible,
3318 	.mpo_socket_copy_label = mls_copy_label,
3319 	.mpo_socket_create = mls_socket_create,
3320 	.mpo_socket_create_mbuf = mls_socket_create_mbuf,
3321 	.mpo_socket_destroy_label = mls_destroy_label,
3322 	.mpo_socket_externalize_label = mls_externalize_label,
3323 	.mpo_socket_init_label = mls_init_label_waitcheck,
3324 	.mpo_socket_internalize_label = mls_internalize_label,
3325 	.mpo_socket_newconn = mls_socket_newconn,
3326 	.mpo_socket_relabel = mls_socket_relabel,
3327 
3328 	.mpo_socketpeer_destroy_label = mls_destroy_label,
3329 	.mpo_socketpeer_externalize_label = mls_externalize_label,
3330 	.mpo_socketpeer_init_label = mls_init_label_waitcheck,
3331 	.mpo_socketpeer_set_from_mbuf = mls_socketpeer_set_from_mbuf,
3332 	.mpo_socketpeer_set_from_socket = mls_socketpeer_set_from_socket,
3333 
3334 	.mpo_syncache_create = mls_syncache_create,
3335 	.mpo_syncache_create_mbuf = mls_syncache_create_mbuf,
3336 	.mpo_syncache_destroy_label = mls_destroy_label,
3337 	.mpo_syncache_init_label = mls_init_label_waitcheck,
3338 
3339 	.mpo_sysvmsg_cleanup = mls_sysvmsg_cleanup,
3340 	.mpo_sysvmsg_create = mls_sysvmsg_create,
3341 	.mpo_sysvmsg_destroy_label = mls_destroy_label,
3342 	.mpo_sysvmsg_init_label = mls_init_label,
3343 
3344 	.mpo_sysvmsq_check_msgrcv = mls_sysvmsq_check_msgrcv,
3345 	.mpo_sysvmsq_check_msgrmid = mls_sysvmsq_check_msgrmid,
3346 	.mpo_sysvmsq_check_msqget = mls_sysvmsq_check_msqget,
3347 	.mpo_sysvmsq_check_msqsnd = mls_sysvmsq_check_msqsnd,
3348 	.mpo_sysvmsq_check_msqrcv = mls_sysvmsq_check_msqrcv,
3349 	.mpo_sysvmsq_check_msqctl = mls_sysvmsq_check_msqctl,
3350 	.mpo_sysvmsq_cleanup = mls_sysvmsq_cleanup,
3351 	.mpo_sysvmsq_destroy_label = mls_destroy_label,
3352 	.mpo_sysvmsq_init_label = mls_init_label,
3353 	.mpo_sysvmsq_create = mls_sysvmsq_create,
3354 
3355 	.mpo_sysvsem_check_semctl = mls_sysvsem_check_semctl,
3356 	.mpo_sysvsem_check_semget = mls_sysvsem_check_semget,
3357 	.mpo_sysvsem_check_semop = mls_sysvsem_check_semop,
3358 	.mpo_sysvsem_cleanup = mls_sysvsem_cleanup,
3359 	.mpo_sysvsem_create = mls_sysvsem_create,
3360 	.mpo_sysvsem_destroy_label = mls_destroy_label,
3361 	.mpo_sysvsem_init_label = mls_init_label,
3362 
3363 	.mpo_sysvshm_check_shmat = mls_sysvshm_check_shmat,
3364 	.mpo_sysvshm_check_shmctl = mls_sysvshm_check_shmctl,
3365 	.mpo_sysvshm_check_shmget = mls_sysvshm_check_shmget,
3366 	.mpo_sysvshm_cleanup = mls_sysvshm_cleanup,
3367 	.mpo_sysvshm_create = mls_sysvshm_create,
3368 	.mpo_sysvshm_destroy_label = mls_destroy_label,
3369 	.mpo_sysvshm_init_label = mls_init_label,
3370 
3371 	.mpo_system_check_acct = mls_system_check_acct,
3372 	.mpo_system_check_auditctl = mls_system_check_auditctl,
3373 	.mpo_system_check_swapon = mls_system_check_swapon,
3374 
3375 	.mpo_vnode_associate_extattr = mls_vnode_associate_extattr,
3376 	.mpo_vnode_associate_singlelabel = mls_vnode_associate_singlelabel,
3377 	.mpo_vnode_check_access = mls_vnode_check_open,
3378 	.mpo_vnode_check_chdir = mls_vnode_check_chdir,
3379 	.mpo_vnode_check_chroot = mls_vnode_check_chroot,
3380 	.mpo_vnode_check_create = mls_vnode_check_create,
3381 	.mpo_vnode_check_deleteacl = mls_vnode_check_deleteacl,
3382 	.mpo_vnode_check_deleteextattr = mls_vnode_check_deleteextattr,
3383 	.mpo_vnode_check_exec = mls_vnode_check_exec,
3384 	.mpo_vnode_check_getacl = mls_vnode_check_getacl,
3385 	.mpo_vnode_check_getextattr = mls_vnode_check_getextattr,
3386 	.mpo_vnode_check_link = mls_vnode_check_link,
3387 	.mpo_vnode_check_listextattr = mls_vnode_check_listextattr,
3388 	.mpo_vnode_check_lookup = mls_vnode_check_lookup,
3389 	.mpo_vnode_check_mmap = mls_vnode_check_mmap,
3390 	.mpo_vnode_check_open = mls_vnode_check_open,
3391 	.mpo_vnode_check_poll = mls_vnode_check_poll,
3392 	.mpo_vnode_check_read = mls_vnode_check_read,
3393 	.mpo_vnode_check_readdir = mls_vnode_check_readdir,
3394 	.mpo_vnode_check_readlink = mls_vnode_check_readlink,
3395 	.mpo_vnode_check_relabel = mls_vnode_check_relabel,
3396 	.mpo_vnode_check_rename_from = mls_vnode_check_rename_from,
3397 	.mpo_vnode_check_rename_to = mls_vnode_check_rename_to,
3398 	.mpo_vnode_check_revoke = mls_vnode_check_revoke,
3399 	.mpo_vnode_check_setacl = mls_vnode_check_setacl,
3400 	.mpo_vnode_check_setextattr = mls_vnode_check_setextattr,
3401 	.mpo_vnode_check_setflags = mls_vnode_check_setflags,
3402 	.mpo_vnode_check_setmode = mls_vnode_check_setmode,
3403 	.mpo_vnode_check_setowner = mls_vnode_check_setowner,
3404 	.mpo_vnode_check_setutimes = mls_vnode_check_setutimes,
3405 	.mpo_vnode_check_stat = mls_vnode_check_stat,
3406 	.mpo_vnode_check_unlink = mls_vnode_check_unlink,
3407 	.mpo_vnode_check_write = mls_vnode_check_write,
3408 	.mpo_vnode_copy_label = mls_copy_label,
3409 	.mpo_vnode_create_extattr = mls_vnode_create_extattr,
3410 	.mpo_vnode_destroy_label = mls_destroy_label,
3411 	.mpo_vnode_externalize_label = mls_externalize_label,
3412 	.mpo_vnode_init_label = mls_init_label,
3413 	.mpo_vnode_internalize_label = mls_internalize_label,
3414 	.mpo_vnode_relabel = mls_vnode_relabel,
3415 	.mpo_vnode_setlabel_extattr = mls_vnode_setlabel_extattr,
3416 };
3417 
3418 MAC_POLICY_SET(&mls_ops, mac_mls, "TrustedBSD MAC/MLS",
3419     MPC_LOADTIME_FLAG_NOTLATE, &mls_slot);
3420