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