mac_mls.c revision 118274
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 118274 2003-07-31 20:00:06Z 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_exec(struct ucred *cred, struct vnode *vp,
1844    struct label *label, struct image_params *imgp,
1845    struct label *execlabel)
1846{
1847	struct mac_mls *subj, *obj, *exec;
1848	int error;
1849
1850	if (execlabel != NULL) {
1851		/*
1852		 * We currently don't permit labels to be changed at
1853		 * exec-time as part of MLS, so disallow non-NULL
1854		 * MLS label elements in the execlabel.
1855		 */
1856		exec = SLOT(execlabel);
1857		error = mls_atmostflags(exec, 0);
1858		if (error)
1859			return (error);
1860	}
1861
1862	if (!mac_mls_enabled)
1863		return (0);
1864
1865	subj = SLOT(&cred->cr_label);
1866	obj = SLOT(label);
1867
1868	if (!mac_mls_dominate_single(subj, obj))
1869		return (EACCES);
1870
1871	return (0);
1872}
1873
1874static int
1875mac_mls_check_vnode_getacl(struct ucred *cred, struct vnode *vp,
1876    struct label *label, acl_type_t type)
1877{
1878	struct mac_mls *subj, *obj;
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_getextattr(struct ucred *cred, struct vnode *vp,
1894    struct label *label, int attrnamespace, const char *name, struct uio *uio)
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_link(struct ucred *cred, struct vnode *dvp,
1912    struct label *dlabel, struct vnode *vp, struct label *label,
1913    struct componentname *cnp)
1914{
1915	struct mac_mls *subj, *obj;
1916
1917	if (!mac_mls_enabled)
1918		return (0);
1919
1920	subj = SLOT(&cred->cr_label);
1921	obj = SLOT(dlabel);
1922
1923	if (!mac_mls_dominate_single(obj, subj))
1924		return (EACCES);
1925
1926	obj = SLOT(dlabel);
1927	if (!mac_mls_dominate_single(obj, subj))
1928		return (EACCES);
1929
1930	return (0);
1931}
1932
1933static int
1934mac_mls_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
1935    struct label *dlabel, struct componentname *cnp)
1936{
1937	struct mac_mls *subj, *obj;
1938
1939	if (!mac_mls_enabled)
1940		return (0);
1941
1942	subj = SLOT(&cred->cr_label);
1943	obj = SLOT(dlabel);
1944
1945	if (!mac_mls_dominate_single(subj, obj))
1946		return (EACCES);
1947
1948	return (0);
1949}
1950
1951static int
1952mac_mls_check_vnode_mmap(struct ucred *cred, struct vnode *vp,
1953    struct label *label, int prot)
1954{
1955	struct mac_mls *subj, *obj;
1956
1957	/*
1958	 * Rely on the use of open()-time protections to handle
1959	 * non-revocation cases.
1960	 */
1961	if (!mac_mls_enabled || !revocation_enabled)
1962		return (0);
1963
1964	subj = SLOT(&cred->cr_label);
1965	obj = SLOT(label);
1966
1967	if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
1968		if (!mac_mls_dominate_single(subj, obj))
1969			return (EACCES);
1970	}
1971	if (prot & VM_PROT_WRITE) {
1972		if (!mac_mls_dominate_single(obj, subj))
1973			return (EACCES);
1974	}
1975
1976	return (0);
1977}
1978
1979static int
1980mac_mls_check_vnode_open(struct ucred *cred, struct vnode *vp,
1981    struct label *vnodelabel, int acc_mode)
1982{
1983	struct mac_mls *subj, *obj;
1984
1985	if (!mac_mls_enabled)
1986		return (0);
1987
1988	subj = SLOT(&cred->cr_label);
1989	obj = SLOT(vnodelabel);
1990
1991	/* XXX privilege override for admin? */
1992	if (acc_mode & (VREAD | VEXEC | VSTAT)) {
1993		if (!mac_mls_dominate_single(subj, obj))
1994			return (EACCES);
1995	}
1996	if (acc_mode & (VWRITE | VAPPEND | VADMIN)) {
1997		if (!mac_mls_dominate_single(obj, subj))
1998			return (EACCES);
1999	}
2000
2001	return (0);
2002}
2003
2004static int
2005mac_mls_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred,
2006    struct vnode *vp, struct label *label)
2007{
2008	struct mac_mls *subj, *obj;
2009
2010	if (!mac_mls_enabled || !revocation_enabled)
2011		return (0);
2012
2013	subj = SLOT(&active_cred->cr_label);
2014	obj = SLOT(label);
2015
2016	if (!mac_mls_dominate_single(subj, obj))
2017		return (EACCES);
2018
2019	return (0);
2020}
2021
2022static int
2023mac_mls_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred,
2024    struct vnode *vp, struct label *label)
2025{
2026	struct mac_mls *subj, *obj;
2027
2028	if (!mac_mls_enabled || !revocation_enabled)
2029		return (0);
2030
2031	subj = SLOT(&active_cred->cr_label);
2032	obj = SLOT(label);
2033
2034	if (!mac_mls_dominate_single(subj, obj))
2035		return (EACCES);
2036
2037	return (0);
2038}
2039
2040static int
2041mac_mls_check_vnode_readdir(struct ucred *cred, struct vnode *dvp,
2042    struct label *dlabel)
2043{
2044	struct mac_mls *subj, *obj;
2045
2046	if (!mac_mls_enabled)
2047		return (0);
2048
2049	subj = SLOT(&cred->cr_label);
2050	obj = SLOT(dlabel);
2051
2052	if (!mac_mls_dominate_single(subj, obj))
2053		return (EACCES);
2054
2055	return (0);
2056}
2057
2058static int
2059mac_mls_check_vnode_readlink(struct ucred *cred, struct vnode *vp,
2060    struct label *vnodelabel)
2061{
2062	struct mac_mls *subj, *obj;
2063
2064	if (!mac_mls_enabled)
2065		return (0);
2066
2067	subj = SLOT(&cred->cr_label);
2068	obj = SLOT(vnodelabel);
2069
2070	if (!mac_mls_dominate_single(subj, obj))
2071		return (EACCES);
2072
2073	return (0);
2074}
2075
2076static int
2077mac_mls_check_vnode_relabel(struct ucred *cred, struct vnode *vp,
2078    struct label *vnodelabel, struct label *newlabel)
2079{
2080	struct mac_mls *old, *new, *subj;
2081	int error;
2082
2083	old = SLOT(vnodelabel);
2084	new = SLOT(newlabel);
2085	subj = SLOT(&cred->cr_label);
2086
2087	/*
2088	 * If there is an MLS label update for the vnode, it must be a
2089	 * single label.
2090	 */
2091	error = mls_atmostflags(new, MAC_MLS_FLAG_SINGLE);
2092	if (error)
2093		return (error);
2094
2095	/*
2096	 * To perform a relabel of the vnode (MLS label or not), MLS must
2097	 * authorize the relabel.
2098	 */
2099	if (!mac_mls_single_in_range(old, subj))
2100		return (EPERM);
2101
2102	/*
2103	 * If the MLS label is to be changed, authorize as appropriate.
2104	 */
2105	if (new->mm_flags & MAC_MLS_FLAG_SINGLE) {
2106		/*
2107		 * To change the MLS label on a vnode, the new vnode label
2108		 * must be in the subject range.
2109		 */
2110		if (!mac_mls_single_in_range(new, subj))
2111			return (EPERM);
2112
2113		/*
2114		 * To change the MLS label on the vnode to be EQUAL,
2115		 * the subject must have appropriate privilege.
2116		 */
2117		if (mac_mls_contains_equal(new)) {
2118			error = mac_mls_subject_privileged(subj);
2119			if (error)
2120				return (error);
2121		}
2122	}
2123
2124	return (0);
2125}
2126
2127
2128static int
2129mac_mls_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
2130    struct label *dlabel, struct vnode *vp, struct label *label,
2131    struct componentname *cnp)
2132{
2133	struct mac_mls *subj, *obj;
2134
2135	if (!mac_mls_enabled)
2136		return (0);
2137
2138	subj = SLOT(&cred->cr_label);
2139	obj = SLOT(dlabel);
2140
2141	if (!mac_mls_dominate_single(obj, subj))
2142		return (EACCES);
2143
2144	obj = SLOT(label);
2145
2146	if (!mac_mls_dominate_single(obj, subj))
2147		return (EACCES);
2148
2149	return (0);
2150}
2151
2152static int
2153mac_mls_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
2154    struct label *dlabel, struct vnode *vp, struct label *label, int samedir,
2155    struct componentname *cnp)
2156{
2157	struct mac_mls *subj, *obj;
2158
2159	if (!mac_mls_enabled)
2160		return (0);
2161
2162	subj = SLOT(&cred->cr_label);
2163	obj = SLOT(dlabel);
2164
2165	if (!mac_mls_dominate_single(obj, subj))
2166		return (EACCES);
2167
2168	if (vp != NULL) {
2169		obj = SLOT(label);
2170
2171		if (!mac_mls_dominate_single(obj, subj))
2172			return (EACCES);
2173	}
2174
2175	return (0);
2176}
2177
2178static int
2179mac_mls_check_vnode_revoke(struct ucred *cred, struct vnode *vp,
2180    struct label *label)
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(label);
2189
2190	if (!mac_mls_dominate_single(obj, subj))
2191		return (EACCES);
2192
2193	return (0);
2194}
2195
2196static int
2197mac_mls_check_vnode_setacl(struct ucred *cred, struct vnode *vp,
2198    struct label *label, acl_type_t type, struct acl *acl)
2199{
2200	struct mac_mls *subj, *obj;
2201
2202	if (!mac_mls_enabled)
2203		return (0);
2204
2205	subj = SLOT(&cred->cr_label);
2206	obj = SLOT(label);
2207
2208	if (!mac_mls_dominate_single(obj, subj))
2209		return (EACCES);
2210
2211	return (0);
2212}
2213
2214static int
2215mac_mls_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
2216    struct label *vnodelabel, int attrnamespace, const char *name,
2217    struct uio *uio)
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(vnodelabel);
2226
2227	if (!mac_mls_dominate_single(obj, subj))
2228		return (EACCES);
2229
2230	/* XXX: protect the MAC EA in a special way? */
2231
2232	return (0);
2233}
2234
2235static int
2236mac_mls_check_vnode_setflags(struct ucred *cred, struct vnode *vp,
2237    struct label *vnodelabel, u_long flags)
2238{
2239	struct mac_mls *subj, *obj;
2240
2241	if (!mac_mls_enabled)
2242		return (0);
2243
2244	subj = SLOT(&cred->cr_label);
2245	obj = SLOT(vnodelabel);
2246
2247	if (!mac_mls_dominate_single(obj, subj))
2248		return (EACCES);
2249
2250	return (0);
2251}
2252
2253static int
2254mac_mls_check_vnode_setmode(struct ucred *cred, struct vnode *vp,
2255    struct label *vnodelabel, mode_t mode)
2256{
2257	struct mac_mls *subj, *obj;
2258
2259	if (!mac_mls_enabled)
2260		return (0);
2261
2262	subj = SLOT(&cred->cr_label);
2263	obj = SLOT(vnodelabel);
2264
2265	if (!mac_mls_dominate_single(obj, subj))
2266		return (EACCES);
2267
2268	return (0);
2269}
2270
2271static int
2272mac_mls_check_vnode_setowner(struct ucred *cred, struct vnode *vp,
2273    struct label *vnodelabel, uid_t uid, gid_t gid)
2274{
2275	struct mac_mls *subj, *obj;
2276
2277	if (!mac_mls_enabled)
2278		return (0);
2279
2280	subj = SLOT(&cred->cr_label);
2281	obj = SLOT(vnodelabel);
2282
2283	if (!mac_mls_dominate_single(obj, subj))
2284		return (EACCES);
2285
2286	return (0);
2287}
2288
2289static int
2290mac_mls_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
2291    struct label *vnodelabel, struct timespec atime, struct timespec mtime)
2292{
2293	struct mac_mls *subj, *obj;
2294
2295	if (!mac_mls_enabled)
2296		return (0);
2297
2298	subj = SLOT(&cred->cr_label);
2299	obj = SLOT(vnodelabel);
2300
2301	if (!mac_mls_dominate_single(obj, subj))
2302		return (EACCES);
2303
2304	return (0);
2305}
2306
2307static int
2308mac_mls_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred,
2309    struct vnode *vp, struct label *vnodelabel)
2310{
2311	struct mac_mls *subj, *obj;
2312
2313	if (!mac_mls_enabled)
2314		return (0);
2315
2316	subj = SLOT(&active_cred->cr_label);
2317	obj = SLOT(vnodelabel);
2318
2319	if (!mac_mls_dominate_single(subj, obj))
2320		return (EACCES);
2321
2322	return (0);
2323}
2324
2325static int
2326mac_mls_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred,
2327    struct vnode *vp, struct label *label)
2328{
2329	struct mac_mls *subj, *obj;
2330
2331	if (!mac_mls_enabled || !revocation_enabled)
2332		return (0);
2333
2334	subj = SLOT(&active_cred->cr_label);
2335	obj = SLOT(label);
2336
2337	if (!mac_mls_dominate_single(obj, subj))
2338		return (EACCES);
2339
2340	return (0);
2341}
2342
2343static struct mac_policy_ops mac_mls_ops =
2344{
2345	.mpo_destroy = mac_mls_destroy,
2346	.mpo_init = mac_mls_init,
2347	.mpo_init_bpfdesc_label = mac_mls_init_label,
2348	.mpo_init_cred_label = mac_mls_init_label,
2349	.mpo_init_devfsdirent_label = mac_mls_init_label,
2350	.mpo_init_ifnet_label = mac_mls_init_label,
2351	.mpo_init_ipq_label = mac_mls_init_label_waitcheck,
2352	.mpo_init_mbuf_label = mac_mls_init_label_waitcheck,
2353	.mpo_init_mount_label = mac_mls_init_label,
2354	.mpo_init_mount_fs_label = mac_mls_init_label,
2355	.mpo_init_pipe_label = mac_mls_init_label,
2356	.mpo_init_socket_label = mac_mls_init_label_waitcheck,
2357	.mpo_init_socket_peer_label = mac_mls_init_label_waitcheck,
2358	.mpo_init_vnode_label = mac_mls_init_label,
2359	.mpo_destroy_bpfdesc_label = mac_mls_destroy_label,
2360	.mpo_destroy_cred_label = mac_mls_destroy_label,
2361	.mpo_destroy_devfsdirent_label = mac_mls_destroy_label,
2362	.mpo_destroy_ifnet_label = mac_mls_destroy_label,
2363	.mpo_destroy_ipq_label = mac_mls_destroy_label,
2364	.mpo_destroy_mbuf_label = mac_mls_destroy_label,
2365	.mpo_destroy_mount_label = mac_mls_destroy_label,
2366	.mpo_destroy_mount_fs_label = mac_mls_destroy_label,
2367	.mpo_destroy_pipe_label = mac_mls_destroy_label,
2368	.mpo_destroy_socket_label = mac_mls_destroy_label,
2369	.mpo_destroy_socket_peer_label = mac_mls_destroy_label,
2370	.mpo_destroy_vnode_label = mac_mls_destroy_label,
2371	.mpo_copy_mbuf_label = mac_mls_copy_label,
2372	.mpo_copy_pipe_label = mac_mls_copy_label,
2373	.mpo_copy_vnode_label = mac_mls_copy_label,
2374	.mpo_externalize_cred_label = mac_mls_externalize_label,
2375	.mpo_externalize_ifnet_label = mac_mls_externalize_label,
2376	.mpo_externalize_pipe_label = mac_mls_externalize_label,
2377	.mpo_externalize_socket_label = mac_mls_externalize_label,
2378	.mpo_externalize_socket_peer_label = mac_mls_externalize_label,
2379	.mpo_externalize_vnode_label = mac_mls_externalize_label,
2380	.mpo_internalize_cred_label = mac_mls_internalize_label,
2381	.mpo_internalize_ifnet_label = mac_mls_internalize_label,
2382	.mpo_internalize_pipe_label = mac_mls_internalize_label,
2383	.mpo_internalize_socket_label = mac_mls_internalize_label,
2384	.mpo_internalize_vnode_label = mac_mls_internalize_label,
2385	.mpo_create_devfs_device = mac_mls_create_devfs_device,
2386	.mpo_create_devfs_directory = mac_mls_create_devfs_directory,
2387	.mpo_create_devfs_symlink = mac_mls_create_devfs_symlink,
2388	.mpo_create_mount = mac_mls_create_mount,
2389	.mpo_create_root_mount = mac_mls_create_root_mount,
2390	.mpo_relabel_vnode = mac_mls_relabel_vnode,
2391	.mpo_update_devfsdirent = mac_mls_update_devfsdirent,
2392	.mpo_associate_vnode_devfs = mac_mls_associate_vnode_devfs,
2393	.mpo_associate_vnode_extattr = mac_mls_associate_vnode_extattr,
2394	.mpo_associate_vnode_singlelabel = mac_mls_associate_vnode_singlelabel,
2395	.mpo_create_vnode_extattr = mac_mls_create_vnode_extattr,
2396	.mpo_setlabel_vnode_extattr = mac_mls_setlabel_vnode_extattr,
2397	.mpo_create_mbuf_from_socket = mac_mls_create_mbuf_from_socket,
2398	.mpo_create_pipe = mac_mls_create_pipe,
2399	.mpo_create_socket = mac_mls_create_socket,
2400	.mpo_create_socket_from_socket = mac_mls_create_socket_from_socket,
2401	.mpo_relabel_pipe = mac_mls_relabel_pipe,
2402	.mpo_relabel_socket = mac_mls_relabel_socket,
2403	.mpo_set_socket_peer_from_mbuf = mac_mls_set_socket_peer_from_mbuf,
2404	.mpo_set_socket_peer_from_socket = mac_mls_set_socket_peer_from_socket,
2405	.mpo_create_bpfdesc = mac_mls_create_bpfdesc,
2406	.mpo_create_datagram_from_ipq = mac_mls_create_datagram_from_ipq,
2407	.mpo_create_fragment = mac_mls_create_fragment,
2408	.mpo_create_ifnet = mac_mls_create_ifnet,
2409	.mpo_create_ipq = mac_mls_create_ipq,
2410	.mpo_create_mbuf_from_mbuf = mac_mls_create_mbuf_from_mbuf,
2411	.mpo_create_mbuf_linklayer = mac_mls_create_mbuf_linklayer,
2412	.mpo_create_mbuf_from_bpfdesc = mac_mls_create_mbuf_from_bpfdesc,
2413	.mpo_create_mbuf_from_ifnet = mac_mls_create_mbuf_from_ifnet,
2414	.mpo_create_mbuf_multicast_encap = mac_mls_create_mbuf_multicast_encap,
2415	.mpo_create_mbuf_netlayer = mac_mls_create_mbuf_netlayer,
2416	.mpo_fragment_match = mac_mls_fragment_match,
2417	.mpo_relabel_ifnet = mac_mls_relabel_ifnet,
2418	.mpo_update_ipq = mac_mls_update_ipq,
2419	.mpo_create_cred = mac_mls_create_cred,
2420	.mpo_create_proc0 = mac_mls_create_proc0,
2421	.mpo_create_proc1 = mac_mls_create_proc1,
2422	.mpo_relabel_cred = mac_mls_relabel_cred,
2423	.mpo_check_bpfdesc_receive = mac_mls_check_bpfdesc_receive,
2424	.mpo_check_cred_relabel = mac_mls_check_cred_relabel,
2425	.mpo_check_cred_visible = mac_mls_check_cred_visible,
2426	.mpo_check_ifnet_relabel = mac_mls_check_ifnet_relabel,
2427	.mpo_check_ifnet_transmit = mac_mls_check_ifnet_transmit,
2428	.mpo_check_mount_stat = mac_mls_check_mount_stat,
2429	.mpo_check_pipe_ioctl = mac_mls_check_pipe_ioctl,
2430	.mpo_check_pipe_poll = mac_mls_check_pipe_poll,
2431	.mpo_check_pipe_read = mac_mls_check_pipe_read,
2432	.mpo_check_pipe_relabel = mac_mls_check_pipe_relabel,
2433	.mpo_check_pipe_stat = mac_mls_check_pipe_stat,
2434	.mpo_check_pipe_write = mac_mls_check_pipe_write,
2435	.mpo_check_proc_debug = mac_mls_check_proc_debug,
2436	.mpo_check_proc_sched = mac_mls_check_proc_sched,
2437	.mpo_check_proc_signal = mac_mls_check_proc_signal,
2438	.mpo_check_socket_deliver = mac_mls_check_socket_deliver,
2439	.mpo_check_socket_relabel = mac_mls_check_socket_relabel,
2440	.mpo_check_socket_visible = mac_mls_check_socket_visible,
2441	.mpo_check_system_swapon = mac_mls_check_system_swapon,
2442	.mpo_check_vnode_access = mac_mls_check_vnode_open,
2443	.mpo_check_vnode_chdir = mac_mls_check_vnode_chdir,
2444	.mpo_check_vnode_chroot = mac_mls_check_vnode_chroot,
2445	.mpo_check_vnode_create = mac_mls_check_vnode_create,
2446	.mpo_check_vnode_delete = mac_mls_check_vnode_delete,
2447	.mpo_check_vnode_deleteacl = mac_mls_check_vnode_deleteacl,
2448	.mpo_check_vnode_exec = mac_mls_check_vnode_exec,
2449	.mpo_check_vnode_getacl = mac_mls_check_vnode_getacl,
2450	.mpo_check_vnode_getextattr = mac_mls_check_vnode_getextattr,
2451	.mpo_check_vnode_link = mac_mls_check_vnode_link,
2452	.mpo_check_vnode_lookup = mac_mls_check_vnode_lookup,
2453	.mpo_check_vnode_mmap = mac_mls_check_vnode_mmap,
2454	.mpo_check_vnode_mprotect = mac_mls_check_vnode_mmap,
2455	.mpo_check_vnode_open = mac_mls_check_vnode_open,
2456	.mpo_check_vnode_poll = mac_mls_check_vnode_poll,
2457	.mpo_check_vnode_read = mac_mls_check_vnode_read,
2458	.mpo_check_vnode_readdir = mac_mls_check_vnode_readdir,
2459	.mpo_check_vnode_readlink = mac_mls_check_vnode_readlink,
2460	.mpo_check_vnode_relabel = mac_mls_check_vnode_relabel,
2461	.mpo_check_vnode_rename_from = mac_mls_check_vnode_rename_from,
2462	.mpo_check_vnode_rename_to = mac_mls_check_vnode_rename_to,
2463	.mpo_check_vnode_revoke = mac_mls_check_vnode_revoke,
2464	.mpo_check_vnode_setacl = mac_mls_check_vnode_setacl,
2465	.mpo_check_vnode_setextattr = mac_mls_check_vnode_setextattr,
2466	.mpo_check_vnode_setflags = mac_mls_check_vnode_setflags,
2467	.mpo_check_vnode_setmode = mac_mls_check_vnode_setmode,
2468	.mpo_check_vnode_setowner = mac_mls_check_vnode_setowner,
2469	.mpo_check_vnode_setutimes = mac_mls_check_vnode_setutimes,
2470	.mpo_check_vnode_stat = mac_mls_check_vnode_stat,
2471	.mpo_check_vnode_write = mac_mls_check_vnode_write,
2472};
2473
2474MAC_POLICY_SET(&mac_mls_ops, mac_mls, "TrustedBSD MAC/MLS",
2475    MPC_LOADTIME_FLAG_NOTLATE | MPC_LOADTIME_FLAG_LABELMBUFS, &mac_mls_slot);
2476