]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sys/security/mac_mls/mac_mls.c
Copy head to stable/9 as part of 9.0-RELEASE release cycle.
[FreeBSD/stable/9.git] / sys / security / mac_mls / mac_mls.c
1 /*-
2  * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson
3  * Copyright (c) 2001-2005 McAfee, Inc.
4  * Copyright (c) 2006 SPARTA, Inc.
5  * All rights reserved.
6  *
7  * This software was developed by Robert Watson for the TrustedBSD Project.
8  *
9  * This software was developed for the FreeBSD Project in part by McAfee
10  * Research, the Security Research Division of McAfee, Inc. under
11  * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
12  * CHATS research program.
13  *
14  * This software was enhanced by SPARTA ISSO under SPAWAR contract
15  * N66001-04-C-6019 ("SEFOS").
16  *
17  * This software was developed at the University of Cambridge Computer
18  * Laboratory with support from a grant from Google, Inc.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  * $FreeBSD$
42  */
43
44 /*
45  * Developed by the TrustedBSD Project.
46  *
47  * MLS fixed label mandatory confidentiality policy.
48  */
49
50 #include <sys/types.h>
51 #include <sys/param.h>
52 #include <sys/acl.h>
53 #include <sys/conf.h>
54 #include <sys/extattr.h>
55 #include <sys/kernel.h>
56 #include <sys/ksem.h>
57 #include <sys/mman.h>
58 #include <sys/malloc.h>
59 #include <sys/mount.h>
60 #include <sys/proc.h>
61 #include <sys/sbuf.h>
62 #include <sys/systm.h>
63 #include <sys/sysproto.h>
64 #include <sys/sysent.h>
65 #include <sys/systm.h>
66 #include <sys/vnode.h>
67 #include <sys/file.h>
68 #include <sys/socket.h>
69 #include <sys/socketvar.h>
70 #include <sys/pipe.h>
71 #include <sys/sx.h>
72 #include <sys/sysctl.h>
73 #include <sys/msg.h>
74 #include <sys/sem.h>
75 #include <sys/shm.h>
76
77 #include <fs/devfs/devfs.h>
78
79 #include <net/bpfdesc.h>
80 #include <net/if.h>
81 #include <net/if_types.h>
82 #include <net/if_var.h>
83
84 #include <netinet/in.h>
85 #include <netinet/in_pcb.h>
86 #include <netinet/ip_var.h>
87
88 #include <vm/uma.h>
89 #include <vm/vm.h>
90
91 #include <security/mac/mac_policy.h>
92 #include <security/mac_mls/mac_mls.h>
93
94 SYSCTL_DECL(_security_mac);
95
96 SYSCTL_NODE(_security_mac, OID_AUTO, mls, CTLFLAG_RW, 0,
97     "TrustedBSD mac_mls policy controls");
98
99 static int      mls_label_size = sizeof(struct mac_mls);
100 SYSCTL_INT(_security_mac_mls, OID_AUTO, label_size, CTLFLAG_RD,
101     &mls_label_size, 0, "Size of struct mac_mls");
102
103 static int      mls_enabled = 1;
104 SYSCTL_INT(_security_mac_mls, OID_AUTO, enabled, CTLFLAG_RW, &mls_enabled, 0,
105     "Enforce MAC/MLS policy");
106 TUNABLE_INT("security.mac.mls.enabled", &mls_enabled);
107
108 static int      destroyed_not_inited;
109 SYSCTL_INT(_security_mac_mls, OID_AUTO, destroyed_not_inited, CTLFLAG_RD,
110     &destroyed_not_inited, 0, "Count of labels destroyed but not inited");
111
112 static int      ptys_equal = 0;
113 SYSCTL_INT(_security_mac_mls, OID_AUTO, ptys_equal, CTLFLAG_RW,
114     &ptys_equal, 0, "Label pty devices as mls/equal on create");
115 TUNABLE_INT("security.mac.mls.ptys_equal", &ptys_equal);
116
117 static int      revocation_enabled = 0;
118 SYSCTL_INT(_security_mac_mls, OID_AUTO, revocation_enabled, CTLFLAG_RW,
119     &revocation_enabled, 0, "Revoke access to objects on relabel");
120 TUNABLE_INT("security.mac.mls.revocation_enabled", &revocation_enabled);
121
122 static int      max_compartments = MAC_MLS_MAX_COMPARTMENTS;
123 SYSCTL_INT(_security_mac_mls, OID_AUTO, max_compartments, CTLFLAG_RD,
124     &max_compartments, 0, "Maximum compartments the policy supports");
125
126 static int      mls_slot;
127 #define SLOT(l) ((struct mac_mls *)mac_label_get((l), mls_slot))
128 #define SLOT_SET(l, val) mac_label_set((l), mls_slot, (uintptr_t)(val))
129
130 static uma_zone_t       zone_mls;
131
132 static __inline int
133 mls_bit_set_empty(u_char *set) {
134         int i;
135
136         for (i = 0; i < MAC_MLS_MAX_COMPARTMENTS >> 3; i++)
137                 if (set[i] != 0)
138                         return (0);
139         return (1);
140 }
141
142 static struct mac_mls *
143 mls_alloc(int flag)
144 {
145
146         return (uma_zalloc(zone_mls, flag | M_ZERO));
147 }
148
149 static void
150 mls_free(struct mac_mls *mm)
151 {
152
153         if (mm != NULL)
154                 uma_zfree(zone_mls, mm);
155         else
156                 atomic_add_int(&destroyed_not_inited, 1);
157 }
158
159 static int
160 mls_atmostflags(struct mac_mls *mm, int flags)
161 {
162
163         if ((mm->mm_flags & flags) != mm->mm_flags)
164                 return (EINVAL);
165         return (0);
166 }
167
168 static int
169 mls_dominate_element(struct mac_mls_element *a, struct mac_mls_element *b)
170 {
171         int bit;
172
173         switch (a->mme_type) {
174         case MAC_MLS_TYPE_EQUAL:
175         case MAC_MLS_TYPE_HIGH:
176                 return (1);
177
178         case MAC_MLS_TYPE_LOW:
179                 switch (b->mme_type) {
180                 case MAC_MLS_TYPE_LEVEL:
181                 case MAC_MLS_TYPE_HIGH:
182                         return (0);
183
184                 case MAC_MLS_TYPE_EQUAL:
185                 case MAC_MLS_TYPE_LOW:
186                         return (1);
187
188                 default:
189                         panic("mls_dominate_element: b->mme_type invalid");
190                 }
191
192         case MAC_MLS_TYPE_LEVEL:
193                 switch (b->mme_type) {
194                 case MAC_MLS_TYPE_EQUAL:
195                 case MAC_MLS_TYPE_LOW:
196                         return (1);
197
198                 case MAC_MLS_TYPE_HIGH:
199                         return (0);
200
201                 case MAC_MLS_TYPE_LEVEL:
202                         for (bit = 1; bit <= MAC_MLS_MAX_COMPARTMENTS; bit++)
203                                 if (!MAC_MLS_BIT_TEST(bit,
204                                     a->mme_compartments) &&
205                                     MAC_MLS_BIT_TEST(bit, b->mme_compartments))
206                                         return (0);
207                         return (a->mme_level >= b->mme_level);
208
209                 default:
210                         panic("mls_dominate_element: b->mme_type invalid");
211                 }
212
213         default:
214                 panic("mls_dominate_element: a->mme_type invalid");
215         }
216
217         return (0);
218 }
219
220 static int
221 mls_range_in_range(struct mac_mls *rangea, struct mac_mls *rangeb)
222 {
223
224         return (mls_dominate_element(&rangeb->mm_rangehigh,
225             &rangea->mm_rangehigh) &&
226             mls_dominate_element(&rangea->mm_rangelow,
227             &rangeb->mm_rangelow));
228 }
229
230 static int
231 mls_effective_in_range(struct mac_mls *effective, struct mac_mls *range)
232 {
233
234         KASSERT((effective->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
235             ("mls_effective_in_range: a not effective"));
236         KASSERT((range->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
237             ("mls_effective_in_range: b not range"));
238
239         return (mls_dominate_element(&range->mm_rangehigh,
240             &effective->mm_effective) &&
241             mls_dominate_element(&effective->mm_effective,
242             &range->mm_rangelow));
243
244         return (1);
245 }
246
247 static int
248 mls_dominate_effective(struct mac_mls *a, struct mac_mls *b)
249 {
250         KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
251             ("mls_dominate_effective: a not effective"));
252         KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
253             ("mls_dominate_effective: b not effective"));
254
255         return (mls_dominate_element(&a->mm_effective, &b->mm_effective));
256 }
257
258 static int
259 mls_equal_element(struct mac_mls_element *a, struct mac_mls_element *b)
260 {
261
262         if (a->mme_type == MAC_MLS_TYPE_EQUAL ||
263             b->mme_type == MAC_MLS_TYPE_EQUAL)
264                 return (1);
265
266         return (a->mme_type == b->mme_type && a->mme_level == b->mme_level);
267 }
268
269 static int
270 mls_equal_effective(struct mac_mls *a, struct mac_mls *b)
271 {
272
273         KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
274             ("mls_equal_effective: a not effective"));
275         KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
276             ("mls_equal_effective: b not effective"));
277
278         return (mls_equal_element(&a->mm_effective, &b->mm_effective));
279 }
280
281 static int
282 mls_contains_equal(struct mac_mls *mm)
283 {
284
285         if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
286                 if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
287                         return (1);
288
289         if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
290                 if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL)
291                         return (1);
292                 if (mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
293                         return (1);
294         }
295
296         return (0);
297 }
298
299 static int
300 mls_subject_privileged(struct mac_mls *mm)
301 {
302
303         KASSERT((mm->mm_flags & MAC_MLS_FLAGS_BOTH) == MAC_MLS_FLAGS_BOTH,
304             ("mls_subject_privileged: subject doesn't have both labels"));
305
306         /* If the effective is EQUAL, it's ok. */
307         if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
308                 return (0);
309
310         /* If either range endpoint is EQUAL, it's ok. */
311         if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL ||
312             mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
313                 return (0);
314
315         /* If the range is low-high, it's ok. */
316         if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_LOW &&
317             mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_HIGH)
318                 return (0);
319
320         /* It's not ok. */
321         return (EPERM);
322 }
323
324 static int
325 mls_valid(struct mac_mls *mm)
326 {
327
328         if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
329                 switch (mm->mm_effective.mme_type) {
330                 case MAC_MLS_TYPE_LEVEL:
331                         break;
332
333                 case MAC_MLS_TYPE_EQUAL:
334                 case MAC_MLS_TYPE_HIGH:
335                 case MAC_MLS_TYPE_LOW:
336                         if (mm->mm_effective.mme_level != 0 ||
337                             !MAC_MLS_BIT_SET_EMPTY(
338                             mm->mm_effective.mme_compartments))
339                                 return (EINVAL);
340                         break;
341
342                 default:
343                         return (EINVAL);
344                 }
345         } else {
346                 if (mm->mm_effective.mme_type != MAC_MLS_TYPE_UNDEF)
347                         return (EINVAL);
348         }
349
350         if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
351                 switch (mm->mm_rangelow.mme_type) {
352                 case MAC_MLS_TYPE_LEVEL:
353                         break;
354
355                 case MAC_MLS_TYPE_EQUAL:
356                 case MAC_MLS_TYPE_HIGH:
357                 case MAC_MLS_TYPE_LOW:
358                         if (mm->mm_rangelow.mme_level != 0 ||
359                             !MAC_MLS_BIT_SET_EMPTY(
360                             mm->mm_rangelow.mme_compartments))
361                                 return (EINVAL);
362                         break;
363
364                 default:
365                         return (EINVAL);
366                 }
367
368                 switch (mm->mm_rangehigh.mme_type) {
369                 case MAC_MLS_TYPE_LEVEL:
370                         break;
371
372                 case MAC_MLS_TYPE_EQUAL:
373                 case MAC_MLS_TYPE_HIGH:
374                 case MAC_MLS_TYPE_LOW:
375                         if (mm->mm_rangehigh.mme_level != 0 ||
376                             !MAC_MLS_BIT_SET_EMPTY(
377                             mm->mm_rangehigh.mme_compartments))
378                                 return (EINVAL);
379                         break;
380
381                 default:
382                         return (EINVAL);
383                 }
384                 if (!mls_dominate_element(&mm->mm_rangehigh,
385                     &mm->mm_rangelow))
386                         return (EINVAL);
387         } else {
388                 if (mm->mm_rangelow.mme_type != MAC_MLS_TYPE_UNDEF ||
389                     mm->mm_rangehigh.mme_type != MAC_MLS_TYPE_UNDEF)
390                         return (EINVAL);
391         }
392
393         return (0);
394 }
395
396 static void
397 mls_set_range(struct mac_mls *mm, u_short typelow, u_short levellow,
398     u_char *compartmentslow, u_short typehigh, u_short levelhigh,
399     u_char *compartmentshigh)
400 {
401
402         mm->mm_rangelow.mme_type = typelow;
403         mm->mm_rangelow.mme_level = levellow;
404         if (compartmentslow != NULL)
405                 memcpy(mm->mm_rangelow.mme_compartments, compartmentslow,
406                     sizeof(mm->mm_rangelow.mme_compartments));
407         mm->mm_rangehigh.mme_type = typehigh;
408         mm->mm_rangehigh.mme_level = levelhigh;
409         if (compartmentshigh != NULL)
410                 memcpy(mm->mm_rangehigh.mme_compartments, compartmentshigh,
411                     sizeof(mm->mm_rangehigh.mme_compartments));
412         mm->mm_flags |= MAC_MLS_FLAG_RANGE;
413 }
414
415 static void
416 mls_set_effective(struct mac_mls *mm, u_short type, u_short level,
417     u_char *compartments)
418 {
419
420         mm->mm_effective.mme_type = type;
421         mm->mm_effective.mme_level = level;
422         if (compartments != NULL)
423                 memcpy(mm->mm_effective.mme_compartments, compartments,
424                     sizeof(mm->mm_effective.mme_compartments));
425         mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
426 }
427
428 static void
429 mls_copy_range(struct mac_mls *labelfrom, struct mac_mls *labelto)
430 {
431
432         KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
433             ("mls_copy_range: labelfrom not range"));
434
435         labelto->mm_rangelow = labelfrom->mm_rangelow;
436         labelto->mm_rangehigh = labelfrom->mm_rangehigh;
437         labelto->mm_flags |= MAC_MLS_FLAG_RANGE;
438 }
439
440 static void
441 mls_copy_effective(struct mac_mls *labelfrom, struct mac_mls *labelto)
442 {
443
444         KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
445             ("mls_copy_effective: labelfrom not effective"));
446
447         labelto->mm_effective = labelfrom->mm_effective;
448         labelto->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
449 }
450
451 static void
452 mls_copy(struct mac_mls *source, struct mac_mls *dest)
453 {
454
455         if (source->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
456                 mls_copy_effective(source, dest);
457         if (source->mm_flags & MAC_MLS_FLAG_RANGE)
458                 mls_copy_range(source, dest);
459 }
460
461 /*
462  * Policy module operations.
463  */
464 static void
465 mls_init(struct mac_policy_conf *conf)
466 {
467
468         zone_mls = uma_zcreate("mac_mls", sizeof(struct mac_mls), NULL,
469             NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
470 }
471
472 /*
473  * Label operations.
474  */
475 static void
476 mls_init_label(struct label *label)
477 {
478
479         SLOT_SET(label, mls_alloc(M_WAITOK));
480 }
481
482 static int
483 mls_init_label_waitcheck(struct label *label, int flag)
484 {
485
486         SLOT_SET(label, mls_alloc(flag));
487         if (SLOT(label) == NULL)
488                 return (ENOMEM);
489
490         return (0);
491 }
492
493 static void
494 mls_destroy_label(struct label *label)
495 {
496
497         mls_free(SLOT(label));
498         SLOT_SET(label, NULL);
499 }
500
501 /*
502  * mls_element_to_string() accepts an sbuf and MLS element.  It converts the
503  * MLS element to a string and stores the result in the sbuf; if there isn't
504  * space in the sbuf, -1 is returned.
505  */
506 static int
507 mls_element_to_string(struct sbuf *sb, struct mac_mls_element *element)
508 {
509         int i, first;
510
511         switch (element->mme_type) {
512         case MAC_MLS_TYPE_HIGH:
513                 return (sbuf_printf(sb, "high"));
514
515         case MAC_MLS_TYPE_LOW:
516                 return (sbuf_printf(sb, "low"));
517
518         case MAC_MLS_TYPE_EQUAL:
519                 return (sbuf_printf(sb, "equal"));
520
521         case MAC_MLS_TYPE_LEVEL:
522                 if (sbuf_printf(sb, "%d", element->mme_level) == -1)
523                         return (-1);
524
525                 first = 1;
526                 for (i = 1; i <= MAC_MLS_MAX_COMPARTMENTS; i++) {
527                         if (MAC_MLS_BIT_TEST(i, element->mme_compartments)) {
528                                 if (first) {
529                                         if (sbuf_putc(sb, ':') == -1)
530                                                 return (-1);
531                                         if (sbuf_printf(sb, "%d", i) == -1)
532                                                 return (-1);
533                                         first = 0;
534                                 } else {
535                                         if (sbuf_printf(sb, "+%d", i) == -1)
536                                                 return (-1);
537                                 }
538                         }
539                 }
540                 return (0);
541
542         default:
543                 panic("mls_element_to_string: invalid type (%d)",
544                     element->mme_type);
545         }
546 }
547
548 /*
549  * mls_to_string() converts an MLS label to a string, and places the results
550  * in the passed sbuf.  It returns 0 on success, or EINVAL if there isn't
551  * room in the sbuf.  Note: the sbuf will be modified even in a failure case,
552  * so the caller may need to revert the sbuf by restoring the offset if
553  * that's undesired.
554  */
555 static int
556 mls_to_string(struct sbuf *sb, struct mac_mls *mm)
557 {
558
559         if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
560                 if (mls_element_to_string(sb, &mm->mm_effective) == -1)
561                         return (EINVAL);
562         }
563
564         if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
565                 if (sbuf_putc(sb, '(') == -1)
566                         return (EINVAL);
567
568                 if (mls_element_to_string(sb, &mm->mm_rangelow) == -1)
569                         return (EINVAL);
570
571                 if (sbuf_putc(sb, '-') == -1)
572                         return (EINVAL);
573
574                 if (mls_element_to_string(sb, &mm->mm_rangehigh) == -1)
575                         return (EINVAL);
576
577                 if (sbuf_putc(sb, ')') == -1)
578                         return (EINVAL);
579         }
580
581         return (0);
582 }
583
584 static int
585 mls_externalize_label(struct label *label, char *element_name,
586     struct sbuf *sb, int *claimed)
587 {
588         struct mac_mls *mm;
589
590         if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
591                 return (0);
592
593         (*claimed)++;
594
595         mm = SLOT(label);
596
597         return (mls_to_string(sb, mm));
598 }
599
600 static int
601 mls_parse_element(struct mac_mls_element *element, char *string)
602 {
603         char *compartment, *end, *level;
604         int value;
605
606         if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) {
607                 element->mme_type = MAC_MLS_TYPE_HIGH;
608                 element->mme_level = MAC_MLS_TYPE_UNDEF;
609         } else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) {
610                 element->mme_type = MAC_MLS_TYPE_LOW;
611                 element->mme_level = MAC_MLS_TYPE_UNDEF;
612         } else if (strcmp(string, "equal") == 0 ||
613             strcmp(string, "eq") == 0) {
614                 element->mme_type = MAC_MLS_TYPE_EQUAL;
615                 element->mme_level = MAC_MLS_TYPE_UNDEF;
616         } else {
617                 element->mme_type = MAC_MLS_TYPE_LEVEL;
618
619                 /*
620                  * Numeric level piece of the element.
621                  */
622                 level = strsep(&string, ":");
623                 value = strtol(level, &end, 10);
624                 if (end == level || *end != '\0')
625                         return (EINVAL);
626                 if (value < 0 || value > 65535)
627                         return (EINVAL);
628                 element->mme_level = value;
629
630                 /*
631                  * Optional compartment piece of the element.  If none are
632                  * included, we assume that the label has no compartments.
633                  */
634                 if (string == NULL)
635                         return (0);
636                 if (*string == '\0')
637                         return (0);
638
639                 while ((compartment = strsep(&string, "+")) != NULL) {
640                         value = strtol(compartment, &end, 10);
641                         if (compartment == end || *end != '\0')
642                                 return (EINVAL);
643                         if (value < 1 || value > MAC_MLS_MAX_COMPARTMENTS)
644                                 return (EINVAL);
645                         MAC_MLS_BIT_SET(value, element->mme_compartments);
646                 }
647         }
648
649         return (0);
650 }
651
652 /*
653  * Note: destructively consumes the string, make a local copy before calling
654  * if that's a problem.
655  */
656 static int
657 mls_parse(struct mac_mls *mm, char *string)
658 {
659         char *rangehigh, *rangelow, *effective;
660         int error;
661
662         effective = strsep(&string, "(");
663         if (*effective == '\0')
664                 effective = NULL;
665
666         if (string != NULL) {
667                 rangelow = strsep(&string, "-");
668                 if (string == NULL)
669                         return (EINVAL);
670                 rangehigh = strsep(&string, ")");
671                 if (string == NULL)
672                         return (EINVAL);
673                 if (*string != '\0')
674                         return (EINVAL);
675         } else {
676                 rangelow = NULL;
677                 rangehigh = NULL;
678         }
679
680         KASSERT((rangelow != NULL && rangehigh != NULL) ||
681             (rangelow == NULL && rangehigh == NULL),
682             ("mls_parse: range mismatch"));
683
684         bzero(mm, sizeof(*mm));
685         if (effective != NULL) {
686                 error = mls_parse_element(&mm->mm_effective, effective);
687                 if (error)
688                         return (error);
689                 mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
690         }
691
692         if (rangelow != NULL) {
693                 error = mls_parse_element(&mm->mm_rangelow, rangelow);
694                 if (error)
695                         return (error);
696                 error = mls_parse_element(&mm->mm_rangehigh, rangehigh);
697                 if (error)
698                         return (error);
699                 mm->mm_flags |= MAC_MLS_FLAG_RANGE;
700         }
701
702         error = mls_valid(mm);
703         if (error)
704                 return (error);
705
706         return (0);
707 }
708
709 static int
710 mls_internalize_label(struct label *label, char *element_name,
711     char *element_data, int *claimed)
712 {
713         struct mac_mls *mm, mm_temp;
714         int error;
715
716         if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
717                 return (0);
718
719         (*claimed)++;
720
721         error = mls_parse(&mm_temp, element_data);
722         if (error)
723                 return (error);
724
725         mm = SLOT(label);
726         *mm = mm_temp;
727
728         return (0);
729 }
730
731 static void
732 mls_copy_label(struct label *src, struct label *dest)
733 {
734
735         *SLOT(dest) = *SLOT(src);
736 }
737
738 /*
739  * Object-specific entry point implementations are sorted alphabetically by
740  * object type name and then by operation.
741  */
742 static int
743 mls_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
744      struct ifnet *ifp, struct label *ifplabel)
745 {
746         struct mac_mls *a, *b;
747
748         if (!mls_enabled)
749                 return (0);
750
751         a = SLOT(dlabel);
752         b = SLOT(ifplabel);
753
754         if (mls_equal_effective(a, b))
755                 return (0);
756         return (EACCES);
757 }
758
759 static void
760 mls_bpfdesc_create(struct ucred *cred, struct bpf_d *d, struct label *dlabel)
761 {
762         struct mac_mls *source, *dest;
763
764         source = SLOT(cred->cr_label);
765         dest = SLOT(dlabel);
766
767         mls_copy_effective(source, dest);
768 }
769
770 static void
771 mls_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
772     struct mbuf *m, struct label *mlabel)
773 {
774         struct mac_mls *source, *dest;
775
776         source = SLOT(dlabel);
777         dest = SLOT(mlabel);
778
779         mls_copy_effective(source, dest);
780 }
781
782 static void
783 mls_cred_associate_nfsd(struct ucred *cred) 
784 {
785         struct mac_mls *label;
786
787         label = SLOT(cred->cr_label);
788         mls_set_effective(label, MAC_MLS_TYPE_LOW, 0, NULL);
789         mls_set_range(label, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
790             NULL);
791 }
792
793 static int
794 mls_cred_check_relabel(struct ucred *cred, struct label *newlabel)
795 {
796         struct mac_mls *subj, *new;
797         int error;
798
799         subj = SLOT(cred->cr_label);
800         new = SLOT(newlabel);
801
802         /*
803          * If there is an MLS label update for the credential, it may be an
804          * update of effective, range, or both.
805          */
806         error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
807         if (error)
808                 return (error);
809
810         /*
811          * If the MLS label is to be changed, authorize as appropriate.
812          */
813         if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
814                 /*
815                  * If the change request modifies both the MLS label
816                  * effective and range, check that the new effective will be
817                  * in the new range.
818                  */
819                 if ((new->mm_flags & MAC_MLS_FLAGS_BOTH) ==
820                     MAC_MLS_FLAGS_BOTH && !mls_effective_in_range(new, new))
821                         return (EINVAL);
822
823                 /*
824                  * To change the MLS effective label on a credential, the new
825                  * effective label must be in the current range.
826                  */
827                 if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE &&
828                     !mls_effective_in_range(new, subj))
829                         return (EPERM);
830
831                 /*
832                  * To change the MLS range label on a credential, the new
833                  * range must be in the current range.
834                  */
835                 if (new->mm_flags & MAC_MLS_FLAG_RANGE &&
836                     !mls_range_in_range(new, subj))
837                         return (EPERM);
838
839                 /*
840                  * To have EQUAL in any component of the new credential MLS
841                  * label, the subject must already have EQUAL in their label.
842                  */
843                 if (mls_contains_equal(new)) {
844                         error = mls_subject_privileged(subj);
845                         if (error)
846                                 return (error);
847                 }
848         }
849
850         return (0);
851 }
852
853 static int
854 mls_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
855 {
856         struct mac_mls *subj, *obj;
857
858         if (!mls_enabled)
859                 return (0);
860
861         subj = SLOT(cr1->cr_label);
862         obj = SLOT(cr2->cr_label);
863
864         /* XXX: range */
865         if (!mls_dominate_effective(subj, obj))
866                 return (ESRCH);
867
868         return (0);
869 }
870
871 static void
872 mls_cred_create_init(struct ucred *cred)
873 {
874         struct mac_mls *dest;
875
876         dest = SLOT(cred->cr_label);
877
878         mls_set_effective(dest, MAC_MLS_TYPE_LOW, 0, NULL);
879         mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
880             NULL);
881 }
882
883 static void
884 mls_cred_create_swapper(struct ucred *cred)
885 {
886         struct mac_mls *dest;
887
888         dest = SLOT(cred->cr_label);
889
890         mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
891         mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
892             NULL);
893 }
894
895 static void
896 mls_cred_relabel(struct ucred *cred, struct label *newlabel)
897 {
898         struct mac_mls *source, *dest;
899
900         source = SLOT(newlabel);
901         dest = SLOT(cred->cr_label);
902
903         mls_copy(source, dest);
904 }
905
906 static void
907 mls_devfs_create_device(struct ucred *cred, struct mount *mp,
908     struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
909 {
910         struct mac_mls *mm;
911         int mls_type;
912
913         mm = SLOT(delabel);
914         if (strcmp(dev->si_name, "null") == 0 ||
915             strcmp(dev->si_name, "zero") == 0 ||
916             strcmp(dev->si_name, "random") == 0 ||
917             strncmp(dev->si_name, "fd/", strlen("fd/")) == 0)
918                 mls_type = MAC_MLS_TYPE_EQUAL;
919         else if (strcmp(dev->si_name, "kmem") == 0 ||
920             strcmp(dev->si_name, "mem") == 0)
921                 mls_type = MAC_MLS_TYPE_HIGH;
922         else if (ptys_equal &&
923             (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
924             strncmp(dev->si_name, "pts/", strlen("pts/")) == 0 ||
925             strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
926                 mls_type = MAC_MLS_TYPE_EQUAL;
927         else
928                 mls_type = MAC_MLS_TYPE_LOW;
929         mls_set_effective(mm, mls_type, 0, NULL);
930 }
931
932 static void
933 mls_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
934     struct devfs_dirent *de, struct label *delabel)
935 {
936         struct mac_mls *mm;
937
938         mm = SLOT(delabel);
939         mls_set_effective(mm, MAC_MLS_TYPE_LOW, 0, NULL);
940 }
941
942 static void
943 mls_devfs_create_symlink(struct ucred *cred, struct mount *mp,
944     struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
945     struct label *delabel)
946 {
947         struct mac_mls *source, *dest;
948
949         source = SLOT(cred->cr_label);
950         dest = SLOT(delabel);
951
952         mls_copy_effective(source, dest);
953 }
954
955 static void
956 mls_devfs_update(struct mount *mp, struct devfs_dirent *de,
957     struct label *delabel, struct vnode *vp, struct label *vplabel)
958 {
959         struct mac_mls *source, *dest;
960
961         source = SLOT(vplabel);
962         dest = SLOT(delabel);
963
964         mls_copy_effective(source, dest);
965 }
966
967 static void
968 mls_devfs_vnode_associate(struct mount *mp, struct label *mplabel,
969     struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
970     struct label *vplabel)
971 {
972         struct mac_mls *source, *dest;
973
974         source = SLOT(delabel);
975         dest = SLOT(vplabel);
976
977         mls_copy_effective(source, dest);
978 }
979
980 static int
981 mls_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
982     struct label *ifplabel, struct label *newlabel)
983 {
984         struct mac_mls *subj, *new;
985         int error;
986
987         subj = SLOT(cred->cr_label);
988         new = SLOT(newlabel);
989
990         /*
991          * If there is an MLS label update for the interface, it may be an
992          * update of effective, range, or both.
993          */
994         error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
995         if (error)
996                 return (error);
997
998         /*
999          * Relabeling network interfaces requires MLS privilege.
1000          */
1001         return (mls_subject_privileged(subj));
1002 }
1003
1004 static int
1005 mls_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
1006     struct mbuf *m, struct label *mlabel)
1007 {
1008         struct mac_mls *p, *i;
1009
1010         if (!mls_enabled)
1011                 return (0);
1012
1013         p = SLOT(mlabel);
1014         i = SLOT(ifplabel);
1015
1016         return (mls_effective_in_range(p, i) ? 0 : EACCES);
1017 }
1018
1019 static void
1020 mls_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
1021 {
1022         struct mac_mls *dest;
1023         int type;
1024
1025         dest = SLOT(ifplabel);
1026
1027         if (ifp->if_type == IFT_LOOP)
1028                 type = MAC_MLS_TYPE_EQUAL;
1029         else
1030                 type = MAC_MLS_TYPE_LOW;
1031
1032         mls_set_effective(dest, type, 0, NULL);
1033         mls_set_range(dest, type, 0, NULL, type, 0, NULL);
1034 }
1035
1036 static void
1037 mls_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
1038     struct mbuf *m, struct label *mlabel)
1039 {
1040         struct mac_mls *source, *dest;
1041
1042         source = SLOT(ifplabel);
1043         dest = SLOT(mlabel);
1044
1045         mls_copy_effective(source, dest);
1046 }
1047
1048 static void
1049 mls_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
1050     struct label *ifplabel, struct label *newlabel)
1051 {
1052         struct mac_mls *source, *dest;
1053
1054         source = SLOT(newlabel);
1055         dest = SLOT(ifplabel);
1056
1057         mls_copy(source, dest);
1058 }
1059
1060 static int
1061 mls_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
1062     struct mbuf *m, struct label *mlabel)
1063 {
1064         struct mac_mls *p, *i;
1065
1066         if (!mls_enabled)
1067                 return (0);
1068
1069         p = SLOT(mlabel);
1070         i = SLOT(inplabel);
1071
1072         return (mls_equal_effective(p, i) ? 0 : EACCES);
1073 }
1074
1075 static int
1076 mls_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
1077     struct label *inplabel)
1078 {
1079         struct mac_mls *subj, *obj;
1080
1081         if (!mls_enabled)
1082                 return (0);
1083
1084         subj = SLOT(cred->cr_label);
1085         obj = SLOT(inplabel);
1086
1087         if (!mls_dominate_effective(subj, obj))
1088                 return (ENOENT);
1089
1090         return (0);
1091 }
1092
1093 static void
1094 mls_inpcb_create(struct socket *so, struct label *solabel, struct inpcb *inp,
1095     struct label *inplabel)
1096 {
1097         struct mac_mls *source, *dest;
1098
1099         source = SLOT(solabel);
1100         dest = SLOT(inplabel);
1101
1102         mls_copy_effective(source, dest);
1103 }
1104
1105 static void
1106 mls_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
1107     struct mbuf *m, struct label *mlabel)
1108 {
1109         struct mac_mls *source, *dest;
1110
1111         source = SLOT(inplabel);
1112         dest = SLOT(mlabel);
1113
1114         mls_copy_effective(source, dest);
1115 }
1116
1117 static void
1118 mls_inpcb_sosetlabel(struct socket *so, struct label *solabel,
1119     struct inpcb *inp, struct label *inplabel)
1120 {
1121         struct mac_mls *source, *dest;
1122
1123         SOCK_LOCK_ASSERT(so);
1124
1125         source = SLOT(solabel);
1126         dest = SLOT(inplabel);
1127
1128         mls_copy(source, dest);
1129 }
1130
1131 static void
1132 mls_ip6q_create(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1133     struct label *q6label)
1134 {
1135         struct mac_mls *source, *dest;
1136
1137         source = SLOT(mlabel);
1138         dest = SLOT(q6label);
1139
1140         mls_copy_effective(source, dest);
1141 }
1142
1143 static int
1144 mls_ip6q_match(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1145     struct label *q6label)
1146 {
1147         struct mac_mls *a, *b;
1148
1149         a = SLOT(q6label);
1150         b = SLOT(mlabel);
1151
1152         return (mls_equal_effective(a, b));
1153 }
1154
1155 static void
1156 mls_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
1157     struct label *mlabel)
1158 {
1159         struct mac_mls *source, *dest;
1160
1161         source = SLOT(q6label);
1162         dest = SLOT(mlabel);
1163
1164         /* Just use the head, since we require them all to match. */
1165         mls_copy_effective(source, dest);
1166 }
1167
1168 static void
1169 mls_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
1170     struct label *q6label)
1171 {
1172
1173         /* NOOP: we only accept matching labels, so no need to update */
1174 }
1175
1176 static void
1177 mls_ipq_create(struct mbuf *m, struct label *mlabel, struct ipq *q,
1178     struct label *qlabel)
1179 {
1180         struct mac_mls *source, *dest;
1181
1182         source = SLOT(mlabel);
1183         dest = SLOT(qlabel);
1184
1185         mls_copy_effective(source, dest);
1186 }
1187
1188 static int
1189 mls_ipq_match(struct mbuf *m, struct label *mlabel, struct ipq *q,
1190     struct label *qlabel)
1191 {
1192         struct mac_mls *a, *b;
1193
1194         a = SLOT(qlabel);
1195         b = SLOT(mlabel);
1196
1197         return (mls_equal_effective(a, b));
1198 }
1199
1200 static void
1201 mls_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
1202     struct label *mlabel)
1203 {
1204         struct mac_mls *source, *dest;
1205
1206         source = SLOT(qlabel);
1207         dest = SLOT(mlabel);
1208
1209         /* Just use the head, since we require them all to match. */
1210         mls_copy_effective(source, dest);
1211 }
1212
1213 static void
1214 mls_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
1215     struct label *qlabel)
1216 {
1217
1218         /* NOOP: we only accept matching labels, so no need to update */
1219 }
1220
1221 static int
1222 mls_mount_check_stat(struct ucred *cred, struct mount *mp,
1223     struct label *mntlabel)
1224 {
1225         struct mac_mls *subj, *obj;
1226
1227         if (!mls_enabled)
1228                 return (0);
1229
1230         subj = SLOT(cred->cr_label);
1231         obj = SLOT(mntlabel);
1232
1233         if (!mls_dominate_effective(subj, obj))
1234                 return (EACCES);
1235
1236         return (0);
1237 }
1238
1239 static void
1240 mls_mount_create(struct ucred *cred, struct mount *mp, struct label *mplabel)
1241 {
1242         struct mac_mls *source, *dest;
1243
1244         source = SLOT(cred->cr_label);
1245         dest = SLOT(mplabel);
1246
1247         mls_copy_effective(source, dest);
1248 }
1249
1250 static void
1251 mls_netatalk_aarp_send(struct ifnet *ifp, struct label *ifplabel,
1252     struct mbuf *m, struct label *mlabel)
1253 {
1254         struct mac_mls *dest;
1255
1256         dest = SLOT(mlabel);
1257
1258         mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1259 }
1260
1261 static void
1262 mls_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
1263     struct mbuf *m, struct label *mlabel)
1264 {
1265         struct mac_mls *dest;
1266
1267         dest = SLOT(mlabel);
1268
1269         mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1270 }
1271
1272 static void
1273 mls_netinet_firewall_reply(struct mbuf *mrecv, struct label *mrecvlabel,
1274     struct mbuf *msend, struct label *msendlabel)
1275 {
1276         struct mac_mls *source, *dest;
1277
1278         source = SLOT(mrecvlabel);
1279         dest = SLOT(msendlabel);
1280
1281         mls_copy_effective(source, dest);
1282 }
1283
1284 static void
1285 mls_netinet_firewall_send(struct mbuf *m, struct label *mlabel)
1286 {
1287         struct mac_mls *dest;
1288
1289         dest = SLOT(mlabel);
1290
1291         /* XXX: where is the label for the firewall really comming from? */
1292         mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1293 }
1294
1295 static void
1296 mls_netinet_fragment(struct mbuf *m, struct label *mlabel, struct mbuf *frag,
1297     struct label *fraglabel)
1298 {
1299         struct mac_mls *source, *dest;
1300
1301         source = SLOT(mlabel);
1302         dest = SLOT(fraglabel);
1303
1304         mls_copy_effective(source, dest);
1305 }
1306
1307 static void
1308 mls_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
1309     struct mbuf *msend, struct label *msendlabel)
1310 {
1311         struct mac_mls *source, *dest;
1312
1313         source = SLOT(mrecvlabel);
1314         dest = SLOT(msendlabel);
1315
1316         mls_copy_effective(source, dest);
1317 }
1318
1319 static void
1320 mls_netinet_igmp_send(struct ifnet *ifp, struct label *ifplabel,
1321     struct mbuf *m, struct label *mlabel)
1322 {
1323         struct mac_mls *dest;
1324
1325         dest = SLOT(mlabel);
1326
1327         mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1328 }
1329
1330 static void
1331 mls_netinet6_nd6_send(struct ifnet *ifp, struct label *ifplabel,
1332     struct mbuf *m, struct label *mlabel)
1333 {
1334         struct mac_mls *dest;
1335
1336         dest = SLOT(mlabel);
1337
1338         mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
1339 }
1340
1341 static int
1342 mls_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
1343     struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
1344 {
1345
1346         if (!mls_enabled)
1347                 return (0);
1348
1349         /* XXX: This will be implemented soon... */
1350
1351         return (0);
1352 }
1353
1354 static int
1355 mls_pipe_check_poll(struct ucred *cred, struct pipepair *pp,
1356     struct label *pplabel)
1357 {
1358         struct mac_mls *subj, *obj;
1359
1360         if (!mls_enabled)
1361                 return (0);
1362
1363         subj = SLOT(cred->cr_label);
1364         obj = SLOT(pplabel);
1365
1366         if (!mls_dominate_effective(subj, obj))
1367                 return (EACCES);
1368
1369         return (0);
1370 }
1371
1372 static int
1373 mls_pipe_check_read(struct ucred *cred, struct pipepair *pp,
1374     struct label *pplabel)
1375 {
1376         struct mac_mls *subj, *obj;
1377
1378         if (!mls_enabled)
1379                 return (0);
1380
1381         subj = SLOT(cred->cr_label);
1382         obj = SLOT(pplabel);
1383
1384         if (!mls_dominate_effective(subj, obj))
1385                 return (EACCES);
1386
1387         return (0);
1388 }
1389
1390 static int
1391 mls_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
1392     struct label *pplabel, struct label *newlabel)
1393 {
1394         struct mac_mls *subj, *obj, *new;
1395         int error;
1396
1397         new = SLOT(newlabel);
1398         subj = SLOT(cred->cr_label);
1399         obj = SLOT(pplabel);
1400
1401         /*
1402          * If there is an MLS label update for a pipe, it must be a effective
1403          * update.
1404          */
1405         error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
1406         if (error)
1407                 return (error);
1408
1409         /*
1410          * To perform a relabel of a pipe (MLS label or not), MLS must
1411          * authorize the relabel.
1412          */
1413         if (!mls_effective_in_range(obj, subj))
1414                 return (EPERM);
1415
1416         /*
1417          * If the MLS label is to be changed, authorize as appropriate.
1418          */
1419         if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
1420                 /*
1421                  * To change the MLS label on a pipe, the new pipe label must
1422                  * be in the subject range.
1423                  */
1424                 if (!mls_effective_in_range(new, subj))
1425                         return (EPERM);
1426
1427                 /*
1428                  * To change the MLS label on a pipe to be EQUAL, the subject
1429                  * must have appropriate privilege.
1430                  */
1431                 if (mls_contains_equal(new)) {
1432                         error = mls_subject_privileged(subj);
1433                         if (error)
1434                                 return (error);
1435                 }
1436         }
1437
1438         return (0);
1439 }
1440
1441 static int
1442 mls_pipe_check_stat(struct ucred *cred, struct pipepair *pp,
1443     struct label *pplabel)
1444 {
1445         struct mac_mls *subj, *obj;
1446
1447         if (!mls_enabled)
1448                 return (0);
1449
1450         subj = SLOT(cred->cr_label);
1451         obj = SLOT(pplabel);
1452
1453         if (!mls_dominate_effective(subj, obj))
1454                 return (EACCES);
1455
1456         return (0);
1457 }
1458
1459 static int
1460 mls_pipe_check_write(struct ucred *cred, struct pipepair *pp,
1461     struct label *pplabel)
1462 {
1463         struct mac_mls *subj, *obj;
1464
1465         if (!mls_enabled)
1466                 return (0);
1467
1468         subj = SLOT(cred->cr_label);
1469         obj = SLOT(pplabel);
1470
1471         if (!mls_dominate_effective(obj, subj))
1472                 return (EACCES);
1473
1474         return (0);
1475 }
1476
1477 static void
1478 mls_pipe_create(struct ucred *cred, struct pipepair *pp,
1479     struct label *pplabel)
1480 {
1481         struct mac_mls *source, *dest;
1482
1483         source = SLOT(cred->cr_label);
1484         dest = SLOT(pplabel);
1485
1486         mls_copy_effective(source, dest);
1487 }
1488
1489 static void
1490 mls_pipe_relabel(struct ucred *cred, struct pipepair *pp,
1491     struct label *pplabel, struct label *newlabel)
1492 {
1493         struct mac_mls *source, *dest;
1494
1495         source = SLOT(newlabel);
1496         dest = SLOT(pplabel);
1497
1498         mls_copy(source, dest);
1499 }
1500
1501 static int
1502 mls_posixsem_check_openunlink(struct ucred *cred, struct ksem *ks,
1503     struct label *kslabel)
1504 {
1505         struct mac_mls *subj, *obj;
1506
1507         if (!mls_enabled)
1508                 return (0);
1509
1510         subj = SLOT(cred->cr_label);
1511         obj = SLOT(kslabel);
1512
1513         if (!mls_dominate_effective(obj, subj))
1514                 return (EACCES);
1515
1516         return (0);
1517 }
1518
1519 static int
1520 mls_posixsem_check_rdonly(struct ucred *active_cred, struct ucred *file_cred,
1521     struct ksem *ks, struct label *kslabel)
1522 {
1523         struct mac_mls *subj, *obj;
1524
1525         if (!mls_enabled)
1526                 return (0);
1527
1528         subj = SLOT(active_cred->cr_label);
1529         obj = SLOT(kslabel);
1530
1531         if (!mls_dominate_effective(subj, obj))
1532                 return (EACCES);
1533
1534         return (0);
1535 }
1536
1537 static int
1538 mls_posixsem_check_setmode(struct ucred *cred, struct ksem *ks,
1539     struct label *shmlabel, mode_t mode)
1540 {
1541         struct mac_mls *subj, *obj;
1542
1543         if (!mls_enabled)
1544                 return (0);
1545
1546         subj = SLOT(cred->cr_label);
1547         obj = SLOT(shmlabel);
1548
1549         if (!mls_dominate_effective(obj, subj))
1550                 return (EACCES);
1551
1552         return (0);
1553 }
1554
1555 static int
1556 mls_posixsem_check_setowner(struct ucred *cred, struct ksem *ks,
1557     struct label *shmlabel, uid_t uid, gid_t gid)
1558 {
1559         struct mac_mls *subj, *obj;
1560
1561         if (!mls_enabled)
1562                 return (0);
1563
1564         subj = SLOT(cred->cr_label);
1565         obj = SLOT(shmlabel);
1566
1567         if (!mls_dominate_effective(obj, subj))
1568                 return (EACCES);
1569
1570         return (0);
1571 }
1572
1573 static int
1574 mls_posixsem_check_write(struct ucred *active_cred, struct ucred *file_cred,
1575     struct ksem *ks, struct label *kslabel)
1576 {
1577         struct mac_mls *subj, *obj;
1578
1579         if (!mls_enabled)
1580                 return (0);
1581
1582         subj = SLOT(active_cred->cr_label);
1583         obj = SLOT(kslabel);
1584
1585         if (!mls_dominate_effective(obj, subj))
1586                 return (EACCES);
1587
1588         return (0);
1589 }
1590
1591 static void
1592 mls_posixsem_create(struct ucred *cred, struct ksem *ks,
1593     struct label *kslabel)
1594 {
1595         struct mac_mls *source, *dest;
1596
1597         source = SLOT(cred->cr_label);
1598         dest = SLOT(kslabel);
1599
1600         mls_copy_effective(source, dest);
1601 }
1602
1603 static int
1604 mls_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd,
1605     struct label *shmlabel, int prot, int flags)
1606 {
1607         struct mac_mls *subj, *obj;
1608
1609         if (!mls_enabled)
1610                 return (0);
1611
1612         subj = SLOT(cred->cr_label);
1613         obj = SLOT(shmlabel);
1614
1615         if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
1616                 if (!mls_dominate_effective(subj, obj))
1617                         return (EACCES);
1618         }
1619         if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
1620                 if (!mls_dominate_effective(obj, subj))
1621                         return (EACCES);
1622         }
1623
1624         return (0);
1625 }
1626
1627 static int
1628 mls_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd,
1629     struct label *shmlabel, accmode_t accmode)
1630 {
1631         struct mac_mls *subj, *obj;
1632
1633         if (!mls_enabled)
1634                 return (0);
1635
1636         subj = SLOT(cred->cr_label);
1637         obj = SLOT(shmlabel);
1638
1639         subj = SLOT(cred->cr_label);
1640         obj = SLOT(shmlabel);
1641
1642         if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) {
1643                 if (!mls_dominate_effective(subj, obj))
1644                         return (EACCES);
1645         }
1646         if (accmode & VMODIFY_PERMS) {
1647                 if (!mls_dominate_effective(obj, subj))
1648                         return (EACCES);
1649         }
1650
1651         return (0);
1652 }
1653
1654 static int
1655 mls_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd,
1656     struct label *shmlabel, mode_t mode)
1657 {
1658         struct mac_mls *subj, *obj;
1659
1660         if (!mls_enabled)
1661                 return (0);
1662
1663         subj = SLOT(cred->cr_label);
1664         obj = SLOT(shmlabel);
1665
1666         if (!mls_dominate_effective(obj, subj))
1667                 return (EACCES);
1668
1669         return (0);
1670 }
1671
1672 static int
1673 mls_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd,
1674     struct label *shmlabel, uid_t uid, gid_t gid)
1675 {
1676         struct mac_mls *subj, *obj;
1677
1678         if (!mls_enabled)
1679                 return (0);
1680
1681         subj = SLOT(cred->cr_label);
1682         obj = SLOT(shmlabel);
1683
1684         if (!mls_dominate_effective(obj, subj))
1685                 return (EACCES);
1686
1687         return (0);
1688 }
1689
1690 static int
1691 mls_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred,
1692     struct shmfd *shmfd, struct label *shmlabel)
1693 {
1694         struct mac_mls *subj, *obj;
1695
1696         if (!mls_enabled)
1697                 return (0);
1698
1699         subj = SLOT(active_cred->cr_label);
1700         obj = SLOT(shmlabel);
1701
1702         if (!mls_dominate_effective(subj, obj))
1703                 return (EACCES);
1704
1705         return (0);
1706 }
1707
1708 static int
1709 mls_posixshm_check_truncate(struct ucred *active_cred,
1710     struct ucred *file_cred, struct shmfd *shmfd, struct label *shmlabel)
1711 {
1712         struct mac_mls *subj, *obj;
1713
1714         if (!mls_enabled)
1715                 return (0);
1716
1717         subj = SLOT(active_cred->cr_label);
1718         obj = SLOT(shmlabel);
1719
1720         if (!mls_dominate_effective(obj, subj))
1721                 return (EACCES);
1722
1723         return (0);
1724 }
1725
1726 static int
1727 mls_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd,
1728     struct label *shmlabel)
1729 {
1730         struct mac_mls *subj, *obj;
1731
1732         if (!mls_enabled)
1733                 return (0);
1734
1735         subj = SLOT(cred->cr_label);
1736         obj = SLOT(shmlabel);
1737
1738         if (!mls_dominate_effective(obj, subj))
1739                 return (EACCES);
1740     
1741         return (0);
1742 }
1743
1744 static void
1745 mls_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
1746     struct label *shmlabel)
1747 {
1748         struct mac_mls *source, *dest;
1749
1750         source = SLOT(cred->cr_label);
1751         dest = SLOT(shmlabel);
1752
1753         mls_copy_effective(source, dest);
1754 }
1755
1756 static int
1757 mls_proc_check_debug(struct ucred *cred, struct proc *p)
1758 {
1759         struct mac_mls *subj, *obj;
1760
1761         if (!mls_enabled)
1762                 return (0);
1763
1764         subj = SLOT(cred->cr_label);
1765         obj = SLOT(p->p_ucred->cr_label);
1766
1767         /* XXX: range checks */
1768         if (!mls_dominate_effective(subj, obj))
1769                 return (ESRCH);
1770         if (!mls_dominate_effective(obj, subj))
1771                 return (EACCES);
1772
1773         return (0);
1774 }
1775
1776 static int
1777 mls_proc_check_sched(struct ucred *cred, struct proc *p)
1778 {
1779         struct mac_mls *subj, *obj;
1780
1781         if (!mls_enabled)
1782                 return (0);
1783
1784         subj = SLOT(cred->cr_label);
1785         obj = SLOT(p->p_ucred->cr_label);
1786
1787         /* XXX: range checks */
1788         if (!mls_dominate_effective(subj, obj))
1789                 return (ESRCH);
1790         if (!mls_dominate_effective(obj, subj))
1791                 return (EACCES);
1792
1793         return (0);
1794 }
1795
1796 static int
1797 mls_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
1798 {
1799         struct mac_mls *subj, *obj;
1800
1801         if (!mls_enabled)
1802                 return (0);
1803
1804         subj = SLOT(cred->cr_label);
1805         obj = SLOT(p->p_ucred->cr_label);
1806
1807         /* XXX: range checks */
1808         if (!mls_dominate_effective(subj, obj))
1809                 return (ESRCH);
1810         if (!mls_dominate_effective(obj, subj))
1811                 return (EACCES);
1812
1813         return (0);
1814 }
1815
1816 static int
1817 mls_socket_check_deliver(struct socket *so, struct label *solabel,
1818     struct mbuf *m, struct label *mlabel)
1819 {
1820         struct mac_mls *p, *s;
1821         int error;
1822
1823         if (!mls_enabled)
1824                 return (0);
1825
1826         p = SLOT(mlabel);
1827         s = SLOT(solabel);
1828
1829         SOCK_LOCK(so);
1830         error = mls_equal_effective(p, s) ? 0 : EACCES;
1831         SOCK_UNLOCK(so);
1832
1833         return (error);
1834 }
1835
1836 static int
1837 mls_socket_check_relabel(struct ucred *cred, struct socket *so,
1838     struct label *solabel, struct label *newlabel)
1839 {
1840         struct mac_mls *subj, *obj, *new;
1841         int error;
1842
1843         SOCK_LOCK_ASSERT(so);
1844
1845         new = SLOT(newlabel);
1846         subj = SLOT(cred->cr_label);
1847         obj = SLOT(solabel);
1848
1849         /*
1850          * If there is an MLS label update for the socket, it may be an
1851          * update of effective.
1852          */
1853         error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
1854         if (error)
1855                 return (error);
1856
1857         /*
1858          * To relabel a socket, the old socket effective must be in the
1859          * subject range.
1860          */
1861         if (!mls_effective_in_range(obj, subj))
1862                 return (EPERM);
1863
1864         /*
1865          * If the MLS label is to be changed, authorize as appropriate.
1866          */
1867         if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
1868                 /*
1869                  * To relabel a socket, the new socket effective must be in
1870                  * the subject range.
1871                  */
1872                 if (!mls_effective_in_range(new, subj))
1873                         return (EPERM);
1874
1875                 /*
1876                  * To change the MLS label on the socket to contain EQUAL,
1877                  * the subject must have appropriate privilege.
1878                  */
1879                 if (mls_contains_equal(new)) {
1880                         error = mls_subject_privileged(subj);
1881                         if (error)
1882                                 return (error);
1883                 }
1884         }
1885
1886         return (0);
1887 }
1888
1889 static int
1890 mls_socket_check_visible(struct ucred *cred, struct socket *so,
1891     struct label *solabel)
1892 {
1893         struct mac_mls *subj, *obj;
1894
1895         if (!mls_enabled)
1896                 return (0);
1897
1898         subj = SLOT(cred->cr_label);
1899         obj = SLOT(solabel);
1900
1901         SOCK_LOCK(so);
1902         if (!mls_dominate_effective(subj, obj)) {
1903                 SOCK_UNLOCK(so);
1904                 return (ENOENT);
1905         }
1906         SOCK_UNLOCK(so);
1907
1908         return (0);
1909 }
1910
1911 static void
1912 mls_socket_create(struct ucred *cred, struct socket *so,
1913     struct label *solabel)
1914 {
1915         struct mac_mls *source, *dest;
1916
1917         source = SLOT(cred->cr_label);
1918         dest = SLOT(solabel);
1919
1920         mls_copy_effective(source, dest);
1921 }
1922
1923 static void
1924 mls_socket_create_mbuf(struct socket *so, struct label *solabel,
1925     struct mbuf *m, struct label *mlabel)
1926 {
1927         struct mac_mls *source, *dest;
1928
1929         source = SLOT(solabel);
1930         dest = SLOT(mlabel);
1931
1932         SOCK_LOCK(so);
1933         mls_copy_effective(source, dest);
1934         SOCK_UNLOCK(so);
1935 }
1936
1937 static void
1938 mls_socket_newconn(struct socket *oldso, struct label *oldsolabel,
1939     struct socket *newso, struct label *newsolabel)
1940 {
1941         struct mac_mls source, *dest;
1942
1943         SOCK_LOCK(oldso);
1944         source = *SLOT(oldsolabel);
1945         SOCK_UNLOCK(oldso);
1946
1947         dest = SLOT(newsolabel);
1948
1949         SOCK_LOCK(newso);
1950         mls_copy_effective(&source, dest);
1951         SOCK_UNLOCK(newso);
1952 }
1953
1954 static void
1955 mls_socket_relabel(struct ucred *cred, struct socket *so,
1956     struct label *solabel, struct label *newlabel)
1957 {
1958         struct mac_mls *source, *dest;
1959
1960         SOCK_LOCK_ASSERT(so);
1961
1962         source = SLOT(newlabel);
1963         dest = SLOT(solabel);
1964
1965         mls_copy(source, dest);
1966 }
1967
1968 static void
1969 mls_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
1970     struct socket *so, struct label *sopeerlabel)
1971 {
1972         struct mac_mls *source, *dest;
1973
1974         source = SLOT(mlabel);
1975         dest = SLOT(sopeerlabel);
1976
1977         SOCK_LOCK(so);
1978         mls_copy_effective(source, dest);
1979         SOCK_UNLOCK(so);
1980 }
1981
1982 static void
1983 mls_socketpeer_set_from_socket(struct socket *oldso,
1984     struct label *oldsolabel, struct socket *newso,
1985     struct label *newsopeerlabel)
1986 {
1987         struct mac_mls source, *dest;
1988
1989         SOCK_LOCK(oldso);
1990         source = *SLOT(oldsolabel);
1991         SOCK_UNLOCK(oldso);
1992
1993         dest = SLOT(newsopeerlabel);
1994
1995         SOCK_LOCK(newso);
1996         mls_copy_effective(&source, dest);
1997         SOCK_UNLOCK(newso);
1998 }
1999
2000 static void
2001 mls_syncache_create(struct label *label, struct inpcb *inp)
2002 {
2003         struct mac_mls *source, *dest;
2004
2005         source = SLOT(inp->inp_label);
2006         dest = SLOT(label);
2007
2008         mls_copy_effective(source, dest);
2009 }
2010
2011 static void
2012 mls_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
2013     struct label *mlabel)
2014 {
2015         struct mac_mls *source, *dest;
2016
2017         source = SLOT(sc_label);
2018         dest = SLOT(mlabel);
2019
2020         mls_copy_effective(source, dest);
2021 }
2022
2023 static int
2024 mls_system_check_acct(struct ucred *cred, struct vnode *vp,
2025     struct label *vplabel)
2026 {
2027         struct mac_mls *subj, *obj;
2028
2029         if (!mls_enabled)
2030                 return (0);
2031
2032         subj = SLOT(cred->cr_label);
2033         obj = SLOT(vplabel);
2034
2035         if (!mls_dominate_effective(obj, subj) ||
2036             !mls_dominate_effective(subj, obj))
2037                 return (EACCES);
2038
2039         return (0);
2040 }
2041
2042 static int
2043 mls_system_check_auditctl(struct ucred *cred, struct vnode *vp,
2044     struct label *vplabel)
2045 {
2046         struct mac_mls *subj, *obj;
2047
2048         if (!mls_enabled)
2049                 return (0);
2050
2051         subj = SLOT(cred->cr_label);
2052         obj = SLOT(vplabel);
2053
2054         if (!mls_dominate_effective(obj, subj) ||
2055             !mls_dominate_effective(subj, obj))
2056                 return (EACCES);
2057
2058         return (0);
2059 }
2060
2061 static int
2062 mls_system_check_swapon(struct ucred *cred, struct vnode *vp,
2063     struct label *vplabel)
2064 {
2065         struct mac_mls *subj, *obj;
2066
2067         if (!mls_enabled)
2068                 return (0);
2069
2070         subj = SLOT(cred->cr_label);
2071         obj = SLOT(vplabel);
2072
2073         if (!mls_dominate_effective(obj, subj) ||
2074             !mls_dominate_effective(subj, obj))
2075                 return (EACCES);
2076
2077         return (0);
2078 }
2079
2080 static void
2081 mls_sysvmsg_cleanup(struct label *msglabel)
2082 {
2083
2084         bzero(SLOT(msglabel), sizeof(struct mac_mls));
2085 }
2086
2087 static void
2088 mls_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
2089     struct label *msqlabel, struct msg *msgptr, struct label *msglabel)
2090 {
2091         struct mac_mls *source, *dest;
2092
2093         /* Ignore the msgq label. */
2094         source = SLOT(cred->cr_label);
2095         dest = SLOT(msglabel);
2096
2097         mls_copy_effective(source, dest);
2098 }
2099
2100 static int
2101 mls_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr,
2102     struct label *msglabel)
2103 {
2104         struct mac_mls *subj, *obj;
2105
2106         if (!mls_enabled)
2107                 return (0);
2108
2109         subj = SLOT(cred->cr_label);
2110         obj = SLOT(msglabel);
2111
2112         if (!mls_dominate_effective(subj, obj))
2113                 return (EACCES);
2114
2115         return (0);
2116 }
2117
2118 static int
2119 mls_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr,
2120     struct label *msglabel)
2121 {
2122         struct mac_mls *subj, *obj;
2123
2124         if (!mls_enabled)
2125                 return (0);
2126
2127         subj = SLOT(cred->cr_label);
2128         obj = SLOT(msglabel);
2129
2130         if (!mls_dominate_effective(obj, subj))
2131                 return (EACCES);
2132
2133         return (0);
2134 }
2135
2136 static int
2137 mls_sysvmsq_check_msqget(struct ucred *cred, struct msqid_kernel *msqkptr,
2138     struct label *msqklabel)
2139 {
2140         struct mac_mls *subj, *obj;
2141
2142         if (!mls_enabled)
2143                 return (0);
2144
2145         subj = SLOT(cred->cr_label);
2146         obj = SLOT(msqklabel);
2147
2148         if (!mls_dominate_effective(subj, obj))
2149                 return (EACCES);
2150
2151         return (0);
2152 }
2153
2154 static int
2155 mls_sysvmsq_check_msqsnd(struct ucred *cred, struct msqid_kernel *msqkptr,
2156     struct label *msqklabel)
2157 {
2158         struct mac_mls *subj, *obj;
2159
2160         if (!mls_enabled)
2161                 return (0);
2162
2163         subj = SLOT(cred->cr_label);
2164         obj = SLOT(msqklabel);
2165
2166         if (!mls_dominate_effective(obj, subj))
2167                 return (EACCES);
2168
2169         return (0);
2170 }
2171
2172 static int
2173 mls_sysvmsq_check_msqrcv(struct ucred *cred, struct msqid_kernel *msqkptr,
2174     struct label *msqklabel)
2175 {
2176         struct mac_mls *subj, *obj;
2177
2178         if (!mls_enabled)
2179                 return (0);
2180
2181         subj = SLOT(cred->cr_label);
2182         obj = SLOT(msqklabel);
2183
2184         if (!mls_dominate_effective(subj, obj))
2185                 return (EACCES);
2186
2187         return (0);
2188 }
2189
2190 static int
2191 mls_sysvmsq_check_msqctl(struct ucred *cred, struct msqid_kernel *msqkptr,
2192     struct label *msqklabel, int cmd)
2193 {
2194         struct mac_mls *subj, *obj;
2195
2196         if (!mls_enabled)
2197                 return (0);
2198
2199         subj = SLOT(cred->cr_label);
2200         obj = SLOT(msqklabel);
2201
2202         switch(cmd) {
2203         case IPC_RMID:
2204         case IPC_SET:
2205                 if (!mls_dominate_effective(obj, subj))
2206                         return (EACCES);
2207                 break;
2208
2209         case IPC_STAT:
2210                 if (!mls_dominate_effective(subj, obj))
2211                         return (EACCES);
2212                 break;
2213
2214         default:
2215                 return (EACCES);
2216         }
2217
2218         return (0);
2219 }
2220
2221 static void
2222 mls_sysvmsq_cleanup(struct label *msqlabel)
2223 {
2224
2225         bzero(SLOT(msqlabel), sizeof(struct mac_mls));
2226 }
2227
2228 static void
2229 mls_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr,
2230     struct label *msqlabel)
2231 {
2232         struct mac_mls *source, *dest;
2233
2234         source = SLOT(cred->cr_label);
2235         dest = SLOT(msqlabel);
2236
2237         mls_copy_effective(source, dest);
2238 }
2239
2240 static int
2241 mls_sysvsem_check_semctl(struct ucred *cred, struct semid_kernel *semakptr,
2242     struct label *semaklabel, int cmd)
2243 {
2244         struct mac_mls *subj, *obj;
2245
2246         if (!mls_enabled)
2247                 return (0);
2248
2249         subj = SLOT(cred->cr_label);
2250         obj = SLOT(semaklabel);
2251
2252         switch(cmd) {
2253         case IPC_RMID:
2254         case IPC_SET:
2255         case SETVAL:
2256         case SETALL:
2257                 if (!mls_dominate_effective(obj, subj))
2258                         return (EACCES);
2259                 break;
2260
2261         case IPC_STAT:
2262         case GETVAL:
2263         case GETPID:
2264         case GETNCNT:
2265         case GETZCNT:
2266         case GETALL:
2267                 if (!mls_dominate_effective(subj, obj))
2268                         return (EACCES);
2269                 break;
2270
2271         default:
2272                 return (EACCES);
2273         }
2274
2275         return (0);
2276 }
2277
2278 static int
2279 mls_sysvsem_check_semget(struct ucred *cred, struct semid_kernel *semakptr,
2280     struct label *semaklabel)
2281 {
2282         struct mac_mls *subj, *obj;
2283
2284         if (!mls_enabled)
2285                 return (0);
2286
2287         subj = SLOT(cred->cr_label);
2288         obj = SLOT(semaklabel);
2289
2290         if (!mls_dominate_effective(subj, obj))
2291                 return (EACCES);
2292
2293         return (0);
2294 }
2295
2296 static int
2297 mls_sysvsem_check_semop(struct ucred *cred, struct semid_kernel *semakptr,
2298     struct label *semaklabel, size_t accesstype)
2299 {
2300         struct mac_mls *subj, *obj;
2301
2302         if (!mls_enabled)
2303                 return (0);
2304
2305         subj = SLOT(cred->cr_label);
2306         obj = SLOT(semaklabel);
2307
2308         if( accesstype & SEM_R )
2309                 if (!mls_dominate_effective(subj, obj))
2310                         return (EACCES);
2311
2312         if( accesstype & SEM_A )
2313                 if (!mls_dominate_effective(obj, subj))
2314                         return (EACCES);
2315
2316         return (0);
2317 }
2318
2319 static void
2320 mls_sysvsem_cleanup(struct label *semalabel)
2321 {
2322
2323         bzero(SLOT(semalabel), sizeof(struct mac_mls));
2324 }
2325
2326 static void
2327 mls_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr,
2328     struct label *semalabel)
2329 {
2330         struct mac_mls *source, *dest;
2331
2332         source = SLOT(cred->cr_label);
2333         dest = SLOT(semalabel);
2334
2335         mls_copy_effective(source, dest);
2336 }
2337
2338 static int
2339 mls_sysvshm_check_shmat(struct ucred *cred, struct shmid_kernel *shmsegptr,
2340     struct label *shmseglabel, int shmflg)
2341 {
2342         struct mac_mls *subj, *obj;
2343
2344         if (!mls_enabled)
2345                 return (0);
2346
2347         subj = SLOT(cred->cr_label);
2348         obj = SLOT(shmseglabel);
2349
2350         if (!mls_dominate_effective(subj, obj))
2351                 return (EACCES);
2352         if ((shmflg & SHM_RDONLY) == 0) {
2353                 if (!mls_dominate_effective(obj, subj))
2354                         return (EACCES);
2355         }
2356         
2357         return (0);
2358 }
2359
2360 static int
2361 mls_sysvshm_check_shmctl(struct ucred *cred, struct shmid_kernel *shmsegptr,
2362     struct label *shmseglabel, int cmd)
2363 {
2364         struct mac_mls *subj, *obj;
2365
2366         if (!mls_enabled)
2367                 return (0);
2368
2369         subj = SLOT(cred->cr_label);
2370         obj = SLOT(shmseglabel);
2371
2372         switch(cmd) {
2373         case IPC_RMID:
2374         case IPC_SET:
2375                 if (!mls_dominate_effective(obj, subj))
2376                         return (EACCES);
2377                 break;
2378
2379         case IPC_STAT:
2380         case SHM_STAT:
2381                 if (!mls_dominate_effective(subj, obj))
2382                         return (EACCES);
2383                 break;
2384
2385         default:
2386                 return (EACCES);
2387         }
2388
2389         return (0);
2390 }
2391
2392 static int
2393 mls_sysvshm_check_shmget(struct ucred *cred, struct shmid_kernel *shmsegptr,
2394     struct label *shmseglabel, int shmflg)
2395 {
2396         struct mac_mls *subj, *obj;
2397
2398         if (!mls_enabled)
2399                 return (0);
2400
2401         subj = SLOT(cred->cr_label);
2402         obj = SLOT(shmseglabel);
2403
2404         if (!mls_dominate_effective(obj, subj))
2405                 return (EACCES);
2406
2407         return (0);
2408 }
2409
2410 static void
2411 mls_sysvshm_cleanup(struct label *shmlabel)
2412 {
2413
2414         bzero(SLOT(shmlabel), sizeof(struct mac_mls));
2415 }
2416
2417 static void
2418 mls_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr,
2419     struct label *shmlabel)
2420 {
2421         struct mac_mls *source, *dest;
2422
2423         source = SLOT(cred->cr_label);
2424         dest = SLOT(shmlabel);
2425
2426         mls_copy_effective(source, dest);
2427 }
2428
2429 static int
2430 mls_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
2431     struct vnode *vp, struct label *vplabel)
2432 {
2433         struct mac_mls mm_temp, *source, *dest;
2434         int buflen, error;
2435
2436         source = SLOT(mplabel);
2437         dest = SLOT(vplabel);
2438
2439         buflen = sizeof(mm_temp);
2440         bzero(&mm_temp, buflen);
2441
2442         error = vn_extattr_get(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
2443             MAC_MLS_EXTATTR_NAME, &buflen, (char *) &mm_temp, curthread);
2444         if (error == ENOATTR || error == EOPNOTSUPP) {
2445                 /* Fall back to the mntlabel. */
2446                 mls_copy_effective(source, dest);
2447                 return (0);
2448         } else if (error)
2449                 return (error);
2450
2451         if (buflen != sizeof(mm_temp)) {
2452                 printf("mls_vnode_associate_extattr: bad size %d\n", buflen);
2453                 return (EPERM);
2454         }
2455         if (mls_valid(&mm_temp) != 0) {
2456                 printf("mls_vnode_associate_extattr: invalid\n");
2457                 return (EPERM);
2458         }
2459         if ((mm_temp.mm_flags & MAC_MLS_FLAGS_BOTH) !=
2460             MAC_MLS_FLAG_EFFECTIVE) {
2461                 printf("mls_associated_vnode_extattr: not effective\n");
2462                 return (EPERM);
2463         }
2464
2465         mls_copy_effective(&mm_temp, dest);
2466         return (0);
2467 }
2468
2469 static void
2470 mls_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
2471     struct vnode *vp, struct label *vplabel)
2472 {
2473         struct mac_mls *source, *dest;
2474
2475         source = SLOT(mplabel);
2476         dest = SLOT(vplabel);
2477
2478         mls_copy_effective(source, dest);
2479 }
2480
2481 static int
2482 mls_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
2483     struct label *dvplabel)
2484 {
2485         struct mac_mls *subj, *obj;
2486
2487         if (!mls_enabled)
2488                 return (0);
2489
2490         subj = SLOT(cred->cr_label);
2491         obj = SLOT(dvplabel);
2492
2493         if (!mls_dominate_effective(subj, obj))
2494                 return (EACCES);
2495
2496         return (0);
2497 }
2498
2499 static int
2500 mls_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
2501     struct label *dvplabel)
2502 {
2503         struct mac_mls *subj, *obj;
2504
2505         if (!mls_enabled)
2506                 return (0);
2507
2508         subj = SLOT(cred->cr_label);
2509         obj = SLOT(dvplabel);
2510
2511         if (!mls_dominate_effective(subj, obj))
2512                 return (EACCES);
2513
2514         return (0);
2515 }
2516
2517 static int
2518 mls_vnode_check_create(struct ucred *cred, struct vnode *dvp,
2519     struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
2520 {
2521         struct mac_mls *subj, *obj;
2522
2523         if (!mls_enabled)
2524                 return (0);
2525
2526         subj = SLOT(cred->cr_label);
2527         obj = SLOT(dvplabel);
2528
2529         if (!mls_dominate_effective(obj, subj))
2530                 return (EACCES);
2531
2532         return (0);
2533 }
2534
2535 static int
2536 mls_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
2537     struct label *vplabel, acl_type_t type)
2538 {
2539         struct mac_mls *subj, *obj;
2540
2541         if (!mls_enabled)
2542                 return (0);
2543
2544         subj = SLOT(cred->cr_label);
2545         obj = SLOT(vplabel);
2546
2547         if (!mls_dominate_effective(obj, subj))
2548                 return (EACCES);
2549
2550         return (0);
2551 }
2552
2553 static int
2554 mls_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
2555     struct label *vplabel, int attrnamespace, const char *name)
2556 {
2557         struct mac_mls *subj, *obj;
2558
2559         if (!mls_enabled)
2560                 return (0);
2561
2562         subj = SLOT(cred->cr_label);
2563         obj = SLOT(vplabel);
2564
2565         if (!mls_dominate_effective(obj, subj))
2566                 return (EACCES);
2567
2568         return (0);
2569 }
2570
2571 static int
2572 mls_vnode_check_exec(struct ucred *cred, struct vnode *vp,
2573     struct label *vplabel, struct image_params *imgp,
2574     struct label *execlabel)
2575 {
2576         struct mac_mls *subj, *obj, *exec;
2577         int error;
2578
2579         if (execlabel != NULL) {
2580                 /*
2581                  * We currently don't permit labels to be changed at
2582                  * exec-time as part of MLS, so disallow non-NULL MLS label
2583                  * elements in the execlabel.
2584                  */
2585                 exec = SLOT(execlabel);
2586                 error = mls_atmostflags(exec, 0);
2587                 if (error)
2588                         return (error);
2589         }
2590
2591         if (!mls_enabled)
2592                 return (0);
2593
2594         subj = SLOT(cred->cr_label);
2595         obj = SLOT(vplabel);
2596
2597         if (!mls_dominate_effective(subj, obj))
2598                 return (EACCES);
2599
2600         return (0);
2601 }
2602
2603 static int
2604 mls_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
2605     struct label *vplabel, acl_type_t type)
2606 {
2607         struct mac_mls *subj, *obj;
2608
2609         if (!mls_enabled)
2610                 return (0);
2611
2612         subj = SLOT(cred->cr_label);
2613         obj = SLOT(vplabel);
2614
2615         if (!mls_dominate_effective(subj, obj))
2616                 return (EACCES);
2617
2618         return (0);
2619 }
2620
2621 static int
2622 mls_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
2623     struct label *vplabel, int attrnamespace, const char *name)
2624 {
2625         struct mac_mls *subj, *obj;
2626
2627         if (!mls_enabled)
2628                 return (0);
2629
2630         subj = SLOT(cred->cr_label);
2631         obj = SLOT(vplabel);
2632
2633         if (!mls_dominate_effective(subj, obj))
2634                 return (EACCES);
2635
2636         return (0);
2637 }
2638
2639 static int
2640 mls_vnode_check_link(struct ucred *cred, struct vnode *dvp,
2641     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2642     struct componentname *cnp)
2643 {
2644         struct mac_mls *subj, *obj;
2645
2646         if (!mls_enabled)
2647                 return (0);
2648
2649         subj = SLOT(cred->cr_label);
2650         obj = SLOT(dvplabel);
2651
2652         if (!mls_dominate_effective(obj, subj))
2653                 return (EACCES);
2654
2655         obj = SLOT(vplabel);
2656         if (!mls_dominate_effective(obj, subj))
2657                 return (EACCES);
2658
2659         return (0);
2660 }
2661
2662 static int
2663 mls_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
2664     struct label *vplabel, int attrnamespace)
2665 {
2666
2667         struct mac_mls *subj, *obj;
2668
2669         if (!mls_enabled)
2670                 return (0);
2671
2672         subj = SLOT(cred->cr_label);
2673         obj = SLOT(vplabel);
2674
2675         if (!mls_dominate_effective(subj, obj))
2676                 return (EACCES);
2677
2678         return (0);
2679 }
2680
2681 static int
2682 mls_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
2683     struct label *dvplabel, struct componentname *cnp)
2684 {
2685         struct mac_mls *subj, *obj;
2686
2687         if (!mls_enabled)
2688                 return (0);
2689
2690         subj = SLOT(cred->cr_label);
2691         obj = SLOT(dvplabel);
2692
2693         if (!mls_dominate_effective(subj, obj))
2694                 return (EACCES);
2695
2696         return (0);
2697 }
2698
2699 static int
2700 mls_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
2701     struct label *vplabel, int prot, int flags)
2702 {
2703         struct mac_mls *subj, *obj;
2704
2705         /*
2706          * Rely on the use of open()-time protections to handle
2707          * non-revocation cases.
2708          */
2709         if (!mls_enabled || !revocation_enabled)
2710                 return (0);
2711
2712         subj = SLOT(cred->cr_label);
2713         obj = SLOT(vplabel);
2714
2715         if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
2716                 if (!mls_dominate_effective(subj, obj))
2717                         return (EACCES);
2718         }
2719         if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
2720                 if (!mls_dominate_effective(obj, subj))
2721                         return (EACCES);
2722         }
2723
2724         return (0);
2725 }
2726
2727 static int
2728 mls_vnode_check_open(struct ucred *cred, struct vnode *vp,
2729     struct label *vplabel, accmode_t accmode)
2730 {
2731         struct mac_mls *subj, *obj;
2732
2733         if (!mls_enabled)
2734                 return (0);
2735
2736         subj = SLOT(cred->cr_label);
2737         obj = SLOT(vplabel);
2738
2739         /* XXX privilege override for admin? */
2740         if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) {
2741                 if (!mls_dominate_effective(subj, obj))
2742                         return (EACCES);
2743         }
2744         if (accmode & VMODIFY_PERMS) {
2745                 if (!mls_dominate_effective(obj, subj))
2746                         return (EACCES);
2747         }
2748
2749         return (0);
2750 }
2751
2752 static int
2753 mls_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
2754     struct vnode *vp, struct label *vplabel)
2755 {
2756         struct mac_mls *subj, *obj;
2757
2758         if (!mls_enabled || !revocation_enabled)
2759                 return (0);
2760
2761         subj = SLOT(active_cred->cr_label);
2762         obj = SLOT(vplabel);
2763
2764         if (!mls_dominate_effective(subj, obj))
2765                 return (EACCES);
2766
2767         return (0);
2768 }
2769
2770 static int
2771 mls_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
2772     struct vnode *vp, struct label *vplabel)
2773 {
2774         struct mac_mls *subj, *obj;
2775
2776         if (!mls_enabled || !revocation_enabled)
2777                 return (0);
2778
2779         subj = SLOT(active_cred->cr_label);
2780         obj = SLOT(vplabel);
2781
2782         if (!mls_dominate_effective(subj, obj))
2783                 return (EACCES);
2784
2785         return (0);
2786 }
2787
2788 static int
2789 mls_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
2790     struct label *dvplabel)
2791 {
2792         struct mac_mls *subj, *obj;
2793
2794         if (!mls_enabled)
2795                 return (0);
2796
2797         subj = SLOT(cred->cr_label);
2798         obj = SLOT(dvplabel);
2799
2800         if (!mls_dominate_effective(subj, obj))
2801                 return (EACCES);
2802
2803         return (0);
2804 }
2805
2806 static int
2807 mls_vnode_check_readlink(struct ucred *cred, struct vnode *vp,
2808     struct label *vplabel)
2809 {
2810         struct mac_mls *subj, *obj;
2811
2812         if (!mls_enabled)
2813                 return (0);
2814
2815         subj = SLOT(cred->cr_label);
2816         obj = SLOT(vplabel);
2817
2818         if (!mls_dominate_effective(subj, obj))
2819                 return (EACCES);
2820
2821         return (0);
2822 }
2823
2824 static int
2825 mls_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
2826     struct label *vplabel, struct label *newlabel)
2827 {
2828         struct mac_mls *old, *new, *subj;
2829         int error;
2830
2831         old = SLOT(vplabel);
2832         new = SLOT(newlabel);
2833         subj = SLOT(cred->cr_label);
2834
2835         /*
2836          * If there is an MLS label update for the vnode, it must be a
2837          * effective label.
2838          */
2839         error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
2840         if (error)
2841                 return (error);
2842
2843         /*
2844          * To perform a relabel of the vnode (MLS label or not), MLS must
2845          * authorize the relabel.
2846          */
2847         if (!mls_effective_in_range(old, subj))
2848                 return (EPERM);
2849
2850         /*
2851          * If the MLS label is to be changed, authorize as appropriate.
2852          */
2853         if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
2854                 /*
2855                  * To change the MLS label on a vnode, the new vnode label
2856                  * must be in the subject range.
2857                  */
2858                 if (!mls_effective_in_range(new, subj))
2859                         return (EPERM);
2860
2861                 /*
2862                  * To change the MLS label on the vnode to be EQUAL, the
2863                  * subject must have appropriate privilege.
2864                  */
2865                 if (mls_contains_equal(new)) {
2866                         error = mls_subject_privileged(subj);
2867                         if (error)
2868                                 return (error);
2869                 }
2870         }
2871
2872         return (0);
2873 }
2874
2875 static int
2876 mls_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
2877     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2878     struct componentname *cnp)
2879 {
2880         struct mac_mls *subj, *obj;
2881
2882         if (!mls_enabled)
2883                 return (0);
2884
2885         subj = SLOT(cred->cr_label);
2886         obj = SLOT(dvplabel);
2887
2888         if (!mls_dominate_effective(obj, subj))
2889                 return (EACCES);
2890
2891         obj = SLOT(vplabel);
2892
2893         if (!mls_dominate_effective(obj, subj))
2894                 return (EACCES);
2895
2896         return (0);
2897 }
2898
2899 static int
2900 mls_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
2901     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
2902     int samedir, struct componentname *cnp)
2903 {
2904         struct mac_mls *subj, *obj;
2905
2906         if (!mls_enabled)
2907                 return (0);
2908
2909         subj = SLOT(cred->cr_label);
2910         obj = SLOT(dvplabel);
2911
2912         if (!mls_dominate_effective(obj, subj))
2913                 return (EACCES);
2914
2915         if (vp != NULL) {
2916                 obj = SLOT(vplabel);
2917
2918                 if (!mls_dominate_effective(obj, subj))
2919                         return (EACCES);
2920         }
2921
2922         return (0);
2923 }
2924
2925 static int
2926 mls_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
2927     struct label *vplabel)
2928 {
2929         struct mac_mls *subj, *obj;
2930
2931         if (!mls_enabled)
2932                 return (0);
2933
2934         subj = SLOT(cred->cr_label);
2935         obj = SLOT(vplabel);
2936
2937         if (!mls_dominate_effective(obj, subj))
2938                 return (EACCES);
2939
2940         return (0);
2941 }
2942
2943 static int
2944 mls_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
2945     struct label *vplabel, acl_type_t type, struct acl *acl)
2946 {
2947         struct mac_mls *subj, *obj;
2948
2949         if (!mls_enabled)
2950                 return (0);
2951
2952         subj = SLOT(cred->cr_label);
2953         obj = SLOT(vplabel);
2954
2955         if (!mls_dominate_effective(obj, subj))
2956                 return (EACCES);
2957
2958         return (0);
2959 }
2960
2961 static int
2962 mls_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
2963     struct label *vplabel, int attrnamespace, const char *name)
2964 {
2965         struct mac_mls *subj, *obj;
2966
2967         if (!mls_enabled)
2968                 return (0);
2969
2970         subj = SLOT(cred->cr_label);
2971         obj = SLOT(vplabel);
2972
2973         if (!mls_dominate_effective(obj, subj))
2974                 return (EACCES);
2975
2976         /* XXX: protect the MAC EA in a special way? */
2977
2978         return (0);
2979 }
2980
2981 static int
2982 mls_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
2983     struct label *vplabel, u_long flags)
2984 {
2985         struct mac_mls *subj, *obj;
2986
2987         if (!mls_enabled)
2988                 return (0);
2989
2990         subj = SLOT(cred->cr_label);
2991         obj = SLOT(vplabel);
2992
2993         if (!mls_dominate_effective(obj, subj))
2994                 return (EACCES);
2995
2996         return (0);
2997 }
2998
2999 static int
3000 mls_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
3001     struct label *vplabel, mode_t mode)
3002 {
3003         struct mac_mls *subj, *obj;
3004
3005         if (!mls_enabled)
3006                 return (0);
3007
3008         subj = SLOT(cred->cr_label);
3009         obj = SLOT(vplabel);
3010
3011         if (!mls_dominate_effective(obj, subj))
3012                 return (EACCES);
3013
3014         return (0);
3015 }
3016
3017 static int
3018 mls_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
3019     struct label *vplabel, uid_t uid, gid_t gid)
3020 {
3021         struct mac_mls *subj, *obj;
3022
3023         if (!mls_enabled)
3024                 return (0);
3025
3026         subj = SLOT(cred->cr_label);
3027         obj = SLOT(vplabel);
3028
3029         if (!mls_dominate_effective(obj, subj))
3030                 return (EACCES);
3031
3032         return (0);
3033 }
3034
3035 static int
3036 mls_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
3037     struct label *vplabel, struct timespec atime, struct timespec mtime)
3038 {
3039         struct mac_mls *subj, *obj;
3040
3041         if (!mls_enabled)
3042                 return (0);
3043
3044         subj = SLOT(cred->cr_label);
3045         obj = SLOT(vplabel);
3046
3047         if (!mls_dominate_effective(obj, subj))
3048                 return (EACCES);
3049
3050         return (0);
3051 }
3052
3053 static int
3054 mls_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
3055     struct vnode *vp, struct label *vplabel)
3056 {
3057         struct mac_mls *subj, *obj;
3058
3059         if (!mls_enabled)
3060                 return (0);
3061
3062         subj = SLOT(active_cred->cr_label);
3063         obj = SLOT(vplabel);
3064
3065         if (!mls_dominate_effective(subj, obj))
3066                 return (EACCES);
3067
3068         return (0);
3069 }
3070
3071 static int
3072 mls_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
3073     struct label *dvplabel, struct vnode *vp, struct label *vplabel,
3074     struct componentname *cnp)
3075 {
3076         struct mac_mls *subj, *obj;
3077
3078         if (!mls_enabled)
3079                 return (0);
3080
3081         subj = SLOT(cred->cr_label);
3082         obj = SLOT(dvplabel);
3083
3084         if (!mls_dominate_effective(obj, subj))
3085                 return (EACCES);
3086
3087         obj = SLOT(vplabel);
3088
3089         if (!mls_dominate_effective(obj, subj))
3090                 return (EACCES);
3091
3092         return (0);
3093 }
3094
3095 static int
3096 mls_vnode_check_write(struct ucred *active_cred, struct ucred *file_cred,
3097     struct vnode *vp, struct label *vplabel)
3098 {
3099         struct mac_mls *subj, *obj;
3100
3101         if (!mls_enabled || !revocation_enabled)
3102                 return (0);
3103
3104         subj = SLOT(active_cred->cr_label);
3105         obj = SLOT(vplabel);
3106
3107         if (!mls_dominate_effective(obj, subj))
3108                 return (EACCES);
3109
3110         return (0);
3111 }
3112
3113 static int
3114 mls_vnode_create_extattr(struct ucred *cred, struct mount *mp,
3115     struct label *mplabel, struct vnode *dvp, struct label *dvplabel,
3116     struct vnode *vp, struct label *vplabel, struct componentname *cnp)
3117 {
3118         struct mac_mls *source, *dest, mm_temp;
3119         size_t buflen;
3120         int error;
3121
3122         buflen = sizeof(mm_temp);
3123         bzero(&mm_temp, buflen);
3124
3125         source = SLOT(cred->cr_label);
3126         dest = SLOT(vplabel);
3127         mls_copy_effective(source, &mm_temp);
3128
3129         error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
3130             MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
3131         if (error == 0)
3132                 mls_copy_effective(source, dest);
3133         return (error);
3134 }
3135
3136 static void
3137 mls_vnode_relabel(struct ucred *cred, struct vnode *vp,
3138     struct label *vplabel, struct label *label)
3139 {
3140         struct mac_mls *source, *dest;
3141
3142         source = SLOT(label);
3143         dest = SLOT(vplabel);
3144
3145         mls_copy(source, dest);
3146 }
3147
3148 static int
3149 mls_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
3150     struct label *vplabel, struct label *intlabel)
3151 {
3152         struct mac_mls *source, mm_temp;
3153         size_t buflen;
3154         int error;
3155
3156         buflen = sizeof(mm_temp);
3157         bzero(&mm_temp, buflen);
3158
3159         source = SLOT(intlabel);
3160         if ((source->mm_flags & MAC_MLS_FLAG_EFFECTIVE) == 0)
3161                 return (0);
3162
3163         mls_copy_effective(source, &mm_temp);
3164
3165         error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
3166             MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
3167         return (error);
3168 }
3169
3170 static struct mac_policy_ops mls_ops =
3171 {
3172         .mpo_init = mls_init,
3173
3174         .mpo_bpfdesc_check_receive = mls_bpfdesc_check_receive,
3175         .mpo_bpfdesc_create = mls_bpfdesc_create,
3176         .mpo_bpfdesc_create_mbuf = mls_bpfdesc_create_mbuf,
3177         .mpo_bpfdesc_destroy_label = mls_destroy_label,
3178         .mpo_bpfdesc_init_label = mls_init_label,
3179
3180         .mpo_cred_associate_nfsd = mls_cred_associate_nfsd,
3181         .mpo_cred_check_relabel = mls_cred_check_relabel,
3182         .mpo_cred_check_visible = mls_cred_check_visible,
3183         .mpo_cred_copy_label = mls_copy_label,
3184         .mpo_cred_create_init = mls_cred_create_init,
3185         .mpo_cred_create_swapper = mls_cred_create_swapper,
3186         .mpo_cred_destroy_label = mls_destroy_label,
3187         .mpo_cred_externalize_label = mls_externalize_label,
3188         .mpo_cred_init_label = mls_init_label,
3189         .mpo_cred_internalize_label = mls_internalize_label,
3190         .mpo_cred_relabel = mls_cred_relabel,
3191
3192         .mpo_devfs_create_device = mls_devfs_create_device,
3193         .mpo_devfs_create_directory = mls_devfs_create_directory,
3194         .mpo_devfs_create_symlink = mls_devfs_create_symlink,
3195         .mpo_devfs_destroy_label = mls_destroy_label,
3196         .mpo_devfs_init_label = mls_init_label,
3197         .mpo_devfs_update = mls_devfs_update,
3198         .mpo_devfs_vnode_associate = mls_devfs_vnode_associate,
3199
3200         .mpo_ifnet_check_relabel = mls_ifnet_check_relabel,
3201         .mpo_ifnet_check_transmit = mls_ifnet_check_transmit,
3202         .mpo_ifnet_copy_label = mls_copy_label,
3203         .mpo_ifnet_create = mls_ifnet_create,
3204         .mpo_ifnet_create_mbuf = mls_ifnet_create_mbuf,
3205         .mpo_ifnet_destroy_label = mls_destroy_label,
3206         .mpo_ifnet_externalize_label = mls_externalize_label,
3207         .mpo_ifnet_init_label = mls_init_label,
3208         .mpo_ifnet_internalize_label = mls_internalize_label,
3209         .mpo_ifnet_relabel = mls_ifnet_relabel,
3210
3211         .mpo_inpcb_check_deliver = mls_inpcb_check_deliver,
3212         .mpo_inpcb_check_visible = mls_inpcb_check_visible,
3213         .mpo_inpcb_create = mls_inpcb_create,
3214         .mpo_inpcb_create_mbuf = mls_inpcb_create_mbuf,
3215         .mpo_inpcb_destroy_label = mls_destroy_label,
3216         .mpo_inpcb_init_label = mls_init_label_waitcheck,
3217         .mpo_inpcb_sosetlabel = mls_inpcb_sosetlabel,
3218
3219         .mpo_ip6q_create = mls_ip6q_create,
3220         .mpo_ip6q_destroy_label = mls_destroy_label,
3221         .mpo_ip6q_init_label = mls_init_label_waitcheck,
3222         .mpo_ip6q_match = mls_ip6q_match,
3223         .mpo_ip6q_reassemble = mls_ip6q_reassemble,
3224         .mpo_ip6q_update = mls_ip6q_update,
3225
3226         .mpo_ipq_create = mls_ipq_create,
3227         .mpo_ipq_destroy_label = mls_destroy_label,
3228         .mpo_ipq_init_label = mls_init_label_waitcheck,
3229         .mpo_ipq_match = mls_ipq_match,
3230         .mpo_ipq_reassemble = mls_ipq_reassemble,
3231         .mpo_ipq_update = mls_ipq_update,
3232
3233         .mpo_mbuf_copy_label = mls_copy_label,
3234         .mpo_mbuf_destroy_label = mls_destroy_label,
3235         .mpo_mbuf_init_label = mls_init_label_waitcheck,
3236
3237         .mpo_mount_check_stat = mls_mount_check_stat,
3238         .mpo_mount_create = mls_mount_create,
3239         .mpo_mount_destroy_label = mls_destroy_label,
3240         .mpo_mount_init_label = mls_init_label,
3241
3242         .mpo_netatalk_aarp_send = mls_netatalk_aarp_send,
3243
3244         .mpo_netinet_arp_send = mls_netinet_arp_send,
3245         .mpo_netinet_firewall_reply = mls_netinet_firewall_reply,
3246         .mpo_netinet_firewall_send = mls_netinet_firewall_send,
3247         .mpo_netinet_fragment = mls_netinet_fragment,
3248         .mpo_netinet_icmp_reply = mls_netinet_icmp_reply,
3249         .mpo_netinet_igmp_send = mls_netinet_igmp_send,
3250
3251         .mpo_netinet6_nd6_send = mls_netinet6_nd6_send,
3252
3253         .mpo_pipe_check_ioctl = mls_pipe_check_ioctl,
3254         .mpo_pipe_check_poll = mls_pipe_check_poll,
3255         .mpo_pipe_check_read = mls_pipe_check_read,
3256         .mpo_pipe_check_relabel = mls_pipe_check_relabel,
3257         .mpo_pipe_check_stat = mls_pipe_check_stat,
3258         .mpo_pipe_check_write = mls_pipe_check_write,
3259         .mpo_pipe_copy_label = mls_copy_label,
3260         .mpo_pipe_create = mls_pipe_create,
3261         .mpo_pipe_destroy_label = mls_destroy_label,
3262         .mpo_pipe_externalize_label = mls_externalize_label,
3263         .mpo_pipe_init_label = mls_init_label,
3264         .mpo_pipe_internalize_label = mls_internalize_label,
3265         .mpo_pipe_relabel = mls_pipe_relabel,
3266
3267         .mpo_posixsem_check_getvalue = mls_posixsem_check_rdonly,
3268         .mpo_posixsem_check_open = mls_posixsem_check_openunlink,
3269         .mpo_posixsem_check_post = mls_posixsem_check_write,
3270         .mpo_posixsem_check_setmode = mls_posixsem_check_setmode,
3271         .mpo_posixsem_check_setowner = mls_posixsem_check_setowner,
3272         .mpo_posixsem_check_stat = mls_posixsem_check_rdonly,
3273         .mpo_posixsem_check_unlink = mls_posixsem_check_openunlink,
3274         .mpo_posixsem_check_wait = mls_posixsem_check_write,
3275         .mpo_posixsem_create = mls_posixsem_create,
3276         .mpo_posixsem_destroy_label = mls_destroy_label,
3277         .mpo_posixsem_init_label = mls_init_label,
3278
3279         .mpo_posixshm_check_mmap = mls_posixshm_check_mmap,
3280         .mpo_posixshm_check_open = mls_posixshm_check_open,
3281         .mpo_posixshm_check_setmode = mls_posixshm_check_setmode,
3282         .mpo_posixshm_check_setowner = mls_posixshm_check_setowner,
3283         .mpo_posixshm_check_stat = mls_posixshm_check_stat,
3284         .mpo_posixshm_check_truncate = mls_posixshm_check_truncate,
3285         .mpo_posixshm_check_unlink = mls_posixshm_check_unlink,
3286         .mpo_posixshm_create = mls_posixshm_create,
3287         .mpo_posixshm_destroy_label = mls_destroy_label,
3288         .mpo_posixshm_init_label = mls_init_label,
3289
3290         .mpo_proc_check_debug = mls_proc_check_debug,
3291         .mpo_proc_check_sched = mls_proc_check_sched,
3292         .mpo_proc_check_signal = mls_proc_check_signal,
3293
3294         .mpo_socket_check_deliver = mls_socket_check_deliver,
3295         .mpo_socket_check_relabel = mls_socket_check_relabel,
3296         .mpo_socket_check_visible = mls_socket_check_visible,
3297         .mpo_socket_copy_label = mls_copy_label,
3298         .mpo_socket_create = mls_socket_create,
3299         .mpo_socket_create_mbuf = mls_socket_create_mbuf,
3300         .mpo_socket_destroy_label = mls_destroy_label,
3301         .mpo_socket_externalize_label = mls_externalize_label,
3302         .mpo_socket_init_label = mls_init_label_waitcheck,
3303         .mpo_socket_internalize_label = mls_internalize_label,
3304         .mpo_socket_newconn = mls_socket_newconn,
3305         .mpo_socket_relabel = mls_socket_relabel,
3306
3307         .mpo_socketpeer_destroy_label = mls_destroy_label,
3308         .mpo_socketpeer_externalize_label = mls_externalize_label,
3309         .mpo_socketpeer_init_label = mls_init_label_waitcheck,
3310         .mpo_socketpeer_set_from_mbuf = mls_socketpeer_set_from_mbuf,
3311         .mpo_socketpeer_set_from_socket = mls_socketpeer_set_from_socket,
3312
3313         .mpo_syncache_create = mls_syncache_create,
3314         .mpo_syncache_create_mbuf = mls_syncache_create_mbuf,
3315         .mpo_syncache_destroy_label = mls_destroy_label,
3316         .mpo_syncache_init_label = mls_init_label_waitcheck,
3317
3318         .mpo_sysvmsg_cleanup = mls_sysvmsg_cleanup,
3319         .mpo_sysvmsg_create = mls_sysvmsg_create,
3320         .mpo_sysvmsg_destroy_label = mls_destroy_label,
3321         .mpo_sysvmsg_init_label = mls_init_label,
3322
3323         .mpo_sysvmsq_check_msgrcv = mls_sysvmsq_check_msgrcv,
3324         .mpo_sysvmsq_check_msgrmid = mls_sysvmsq_check_msgrmid,
3325         .mpo_sysvmsq_check_msqget = mls_sysvmsq_check_msqget,
3326         .mpo_sysvmsq_check_msqsnd = mls_sysvmsq_check_msqsnd,
3327         .mpo_sysvmsq_check_msqrcv = mls_sysvmsq_check_msqrcv,
3328         .mpo_sysvmsq_check_msqctl = mls_sysvmsq_check_msqctl,
3329         .mpo_sysvmsq_cleanup = mls_sysvmsq_cleanup,
3330         .mpo_sysvmsq_destroy_label = mls_destroy_label,
3331         .mpo_sysvmsq_init_label = mls_init_label,
3332         .mpo_sysvmsq_create = mls_sysvmsq_create,
3333
3334         .mpo_sysvsem_check_semctl = mls_sysvsem_check_semctl,
3335         .mpo_sysvsem_check_semget = mls_sysvsem_check_semget,
3336         .mpo_sysvsem_check_semop = mls_sysvsem_check_semop,
3337         .mpo_sysvsem_cleanup = mls_sysvsem_cleanup,
3338         .mpo_sysvsem_create = mls_sysvsem_create,
3339         .mpo_sysvsem_destroy_label = mls_destroy_label,
3340         .mpo_sysvsem_init_label = mls_init_label,
3341
3342         .mpo_sysvshm_check_shmat = mls_sysvshm_check_shmat,
3343         .mpo_sysvshm_check_shmctl = mls_sysvshm_check_shmctl,
3344         .mpo_sysvshm_check_shmget = mls_sysvshm_check_shmget,
3345         .mpo_sysvshm_cleanup = mls_sysvshm_cleanup,
3346         .mpo_sysvshm_create = mls_sysvshm_create,
3347         .mpo_sysvshm_destroy_label = mls_destroy_label,
3348         .mpo_sysvshm_init_label = mls_init_label,
3349
3350
3351         .mpo_system_check_acct = mls_system_check_acct,
3352         .mpo_system_check_auditctl = mls_system_check_auditctl,
3353         .mpo_system_check_swapon = mls_system_check_swapon,
3354
3355         .mpo_vnode_associate_extattr = mls_vnode_associate_extattr,
3356         .mpo_vnode_associate_singlelabel = mls_vnode_associate_singlelabel,
3357         .mpo_vnode_check_access = mls_vnode_check_open,
3358         .mpo_vnode_check_chdir = mls_vnode_check_chdir,
3359         .mpo_vnode_check_chroot = mls_vnode_check_chroot,
3360         .mpo_vnode_check_create = mls_vnode_check_create,
3361         .mpo_vnode_check_deleteacl = mls_vnode_check_deleteacl,
3362         .mpo_vnode_check_deleteextattr = mls_vnode_check_deleteextattr,
3363         .mpo_vnode_check_exec = mls_vnode_check_exec,
3364         .mpo_vnode_check_getacl = mls_vnode_check_getacl,
3365         .mpo_vnode_check_getextattr = mls_vnode_check_getextattr,
3366         .mpo_vnode_check_link = mls_vnode_check_link,
3367         .mpo_vnode_check_listextattr = mls_vnode_check_listextattr,
3368         .mpo_vnode_check_lookup = mls_vnode_check_lookup,
3369         .mpo_vnode_check_mmap = mls_vnode_check_mmap,
3370         .mpo_vnode_check_open = mls_vnode_check_open,
3371         .mpo_vnode_check_poll = mls_vnode_check_poll,
3372         .mpo_vnode_check_read = mls_vnode_check_read,
3373         .mpo_vnode_check_readdir = mls_vnode_check_readdir,
3374         .mpo_vnode_check_readlink = mls_vnode_check_readlink,
3375         .mpo_vnode_check_relabel = mls_vnode_check_relabel,
3376         .mpo_vnode_check_rename_from = mls_vnode_check_rename_from,
3377         .mpo_vnode_check_rename_to = mls_vnode_check_rename_to,
3378         .mpo_vnode_check_revoke = mls_vnode_check_revoke,
3379         .mpo_vnode_check_setacl = mls_vnode_check_setacl,
3380         .mpo_vnode_check_setextattr = mls_vnode_check_setextattr,
3381         .mpo_vnode_check_setflags = mls_vnode_check_setflags,
3382         .mpo_vnode_check_setmode = mls_vnode_check_setmode,
3383         .mpo_vnode_check_setowner = mls_vnode_check_setowner,
3384         .mpo_vnode_check_setutimes = mls_vnode_check_setutimes,
3385         .mpo_vnode_check_stat = mls_vnode_check_stat,
3386         .mpo_vnode_check_unlink = mls_vnode_check_unlink,
3387         .mpo_vnode_check_write = mls_vnode_check_write,
3388         .mpo_vnode_copy_label = mls_copy_label,
3389         .mpo_vnode_create_extattr = mls_vnode_create_extattr,
3390         .mpo_vnode_destroy_label = mls_destroy_label,
3391         .mpo_vnode_externalize_label = mls_externalize_label,
3392         .mpo_vnode_init_label = mls_init_label,
3393         .mpo_vnode_internalize_label = mls_internalize_label,
3394         .mpo_vnode_relabel = mls_vnode_relabel,
3395         .mpo_vnode_setlabel_extattr = mls_vnode_setlabel_extattr,
3396 };
3397
3398 MAC_POLICY_SET(&mls_ops, mac_mls, "TrustedBSD MAC/MLS",
3399     MPC_LOADTIME_FLAG_NOTLATE, &mls_slot);