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