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