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