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