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