]> git.saurik.com Git - apple/xnu.git/blob - security/mac_vfs.c
2bbfb04db49fae57e42b9ec2721dc5d52ddd1eab
[apple/xnu.git] / security / mac_vfs.c
1 /*
2 * Copyright (c) 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*-
29 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
30 * Copyright (c) 2001 Ilmar S. Habibulin
31 * Copyright (c) 2001, 2002, 2003, 2004 Networks Associates Technology, Inc.
32 * Copyright (c) 2005 SPARTA, Inc.
33 *
34 * This software was developed by Robert Watson and Ilmar Habibulin for the
35 * TrustedBSD Project.
36 *
37 * This software was developed for the FreeBSD Project in part by Network
38 * Associates Laboratories, the Security Research Division of Network
39 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
40 * as part of the DARPA CHATS research program.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 */
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/kernel.h>
68 #include <sys/proc.h>
69 #include <sys/kauth.h>
70
71 #include <sys/file_internal.h>
72 #include <sys/imgact.h>
73 #include <sys/namei.h>
74 #include <sys/mount_internal.h>
75 #include <sys/pipe.h>
76 #include <sys/posix_sem.h>
77 #include <sys/posix_shm.h>
78 #include <sys/uio_internal.h>
79 #include <sys/vnode_internal.h>
80
81 #include <miscfs/devfs/devfsdefs.h>
82 #include <miscfs/fdesc/fdesc.h>
83
84 #include <security/mac_internal.h>
85
86 /* convert {R,W,X}_OK values to V{READ,WRITE,EXEC} */
87 #define ACCESS_MODE_TO_VNODE_MASK(m) (m << 6)
88
89 static struct label *
90 mac_devfsdirent_label_alloc(void)
91 {
92 struct label *label;
93
94 label = mac_labelzone_alloc(MAC_WAITOK);
95 if (label == NULL)
96 return (NULL);
97 MAC_PERFORM(devfs_label_init, label);
98 return (label);
99 }
100
101 void
102 mac_devfs_label_init(struct devnode *de)
103 {
104
105 de->dn_label = mac_devfsdirent_label_alloc();
106 }
107
108 static struct label *
109 mac_mount_label_alloc(void)
110 {
111 struct label *label;
112
113 label = mac_labelzone_alloc(MAC_WAITOK);
114 if (label == NULL)
115 return (NULL);
116 MAC_PERFORM(mount_label_init, label);
117 return (label);
118 }
119
120 void
121 mac_mount_label_init(struct mount *mp)
122 {
123
124 mp->mnt_mntlabel = mac_mount_label_alloc();
125 }
126
127 struct label *
128 mac_vnode_label_alloc(void)
129 {
130 struct label *label;
131
132 label = mac_labelzone_alloc(MAC_WAITOK);
133 if (label == NULL)
134 return (NULL);
135 MAC_PERFORM(vnode_label_init, label);
136 return (label);
137 }
138
139 void
140 mac_vnode_label_init(vnode_t vp)
141 {
142
143 vp->v_label = mac_vnode_label_alloc();
144 }
145
146 /*
147 * vnode labels are allocated at the same time as vnodes, but vnodes are never
148 * freed. Instead, we want to remove any sensitive information before putting
149 * them on the free list for reuse.
150 */
151 void
152 mac_vnode_label_recycle(vnode_t vp)
153 {
154
155 MAC_PERFORM(vnode_label_recycle, vp->v_label);
156 }
157
158 static void
159 mac_devfs_label_free(struct label *label)
160 {
161 MAC_PERFORM(devfs_label_destroy, label);
162 mac_labelzone_free(label);
163 }
164
165 void
166 mac_devfs_label_destroy(struct devnode *de)
167 {
168 if (de->dn_label != NULL) {
169 mac_devfs_label_free(de->dn_label);
170 de->dn_label = NULL;
171 }
172 }
173
174 static void
175 mac_mount_label_free(struct label *label)
176 {
177
178 MAC_PERFORM(mount_label_destroy, label);
179 mac_labelzone_free(label);
180 }
181
182 void
183 mac_mount_label_destroy(struct mount *mp)
184 {
185
186
187 if (mp->mnt_mntlabel != NULL) {
188 mac_mount_label_free(mp->mnt_mntlabel);
189 mp->mnt_mntlabel = NULL;
190 }
191 }
192
193 void
194 mac_vnode_label_free(struct label *label)
195 {
196
197 MAC_PERFORM(vnode_label_destroy, label);
198 mac_labelzone_free(label);
199 }
200
201 #ifndef __APPLE__
202 void
203 mac_vnode_label_destroy(struct vnode *vp)
204 {
205
206 mac_vnode_label_free(vp->v_label);
207 vp->v_label = NULL;
208 }
209 #endif
210
211 void
212 mac_vnode_label_copy(struct label *src, struct label *dest)
213 {
214
215 MAC_PERFORM(vnode_label_copy, src, dest);
216 }
217
218 int
219 mac_vnode_label_externalize_audit(struct vnode *vp, struct mac *mac)
220 {
221 int error;
222
223 /* It is assumed that any necessary vnode locking is done on entry */
224 error = MAC_EXTERNALIZE_AUDIT(vnode, vp->v_label,
225 mac->m_string, mac->m_buflen);
226
227 return (error);
228 }
229
230 int
231 mac_vnode_label_externalize(struct label *label, char *elements,
232 char *outbuf, size_t outbuflen, int flags __unused)
233 {
234 int error;
235
236 error = MAC_EXTERNALIZE(vnode, label, elements, outbuf, outbuflen);
237
238 return (error);
239 }
240
241 int
242 mac_vnode_label_internalize(struct label *label, char *string)
243 {
244 int error;
245
246 error = MAC_INTERNALIZE(vnode, label, string);
247
248 return (error);
249 }
250
251 int
252 mac_mount_label_internalize(struct label *label, char *string)
253 {
254 int error;
255
256 error = MAC_INTERNALIZE(mount, label, string);
257
258 return (error);
259 }
260
261 int
262 mac_mount_label_externalize(struct label *label, char *elements,
263 char *outbuf, size_t outbuflen)
264 {
265 int error;
266
267 error = MAC_EXTERNALIZE(mount, label, elements, outbuf, outbuflen);
268
269 return (error);
270 }
271
272 void
273 mac_devfs_label_copy(struct label *src, struct label *dest)
274 {
275 if (!mac_device_enforce)
276 return;
277
278 MAC_PERFORM(devfs_label_copy, src, dest);
279 }
280
281 void
282 mac_devfs_label_update(struct mount *mp, struct devnode *de,
283 struct vnode *vp)
284 {
285
286 if (!mac_device_enforce)
287 return;
288
289 MAC_PERFORM(devfs_label_update, mp, de, de->dn_label, vp,
290 vp->v_label);
291 }
292
293 int
294 mac_vnode_label_associate(struct mount *mp, struct vnode *vp, vfs_context_t ctx)
295 {
296 struct devnode *dnp;
297 struct fdescnode *fnp;
298 int error = 0;
299
300 if (!mac_vnode_enforce)
301 return (error);
302
303 /* XXX: should not inspect v_tag in kernel! */
304 switch (vp->v_tag) {
305 case VT_DEVFS:
306 dnp = VTODN(vp);
307 mac_vnode_label_associate_devfs(mp, dnp, vp);
308 break;
309 case VT_FDESC:
310 fnp = VTOFDESC(vp);
311 error = mac_vnode_label_associate_fdesc(mp, fnp, vp, ctx);
312 break;
313 default:
314 error = mac_vnode_label_associate_extattr(mp, vp);
315 break;
316 }
317
318 return (error);
319 }
320
321 void
322 mac_vnode_label_associate_devfs(struct mount *mp, struct devnode *de,
323 struct vnode *vp)
324 {
325 if (!mac_device_enforce)
326 return;
327
328 MAC_PERFORM(vnode_label_associate_devfs,
329 mp, mp ? mp->mnt_mntlabel : NULL,
330 de, de->dn_label,
331 vp, vp->v_label);
332 }
333
334 int
335 mac_vnode_label_associate_extattr(struct mount *mp, struct vnode *vp)
336 {
337 int error;
338
339 MAC_CHECK(vnode_label_associate_extattr, mp, mp->mnt_mntlabel, vp,
340 vp->v_label);
341
342 return (error);
343 }
344
345 void
346 mac_vnode_label_associate_singlelabel(struct mount *mp, struct vnode *vp)
347 {
348
349 if (!mac_vnode_enforce)
350 return;
351
352 MAC_PERFORM(vnode_label_associate_singlelabel, mp,
353 mp ? mp->mnt_mntlabel : NULL, vp, vp->v_label);
354 }
355
356 int
357 mac_vnode_notify_create(vfs_context_t ctx, struct mount *mp,
358 struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
359 {
360 kauth_cred_t cred;
361 int error;
362
363 if (!mac_vnode_enforce ||
364 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
365 return (0);
366
367 cred = vfs_context_ucred(ctx);
368 MAC_CHECK(vnode_notify_create, cred, mp, mp->mnt_mntlabel,
369 dvp, dvp->v_label, vp, vp->v_label, cnp);
370
371 return (error);
372 }
373
374 /*
375 * Extended attribute 'name' was updated via
376 * vn_setxattr() or vn_removexattr(). Allow the
377 * policy to update the vnode label.
378 */
379 void
380 mac_vnode_label_update_extattr(struct mount *mp, struct vnode *vp,
381 const char *name)
382 {
383 int error = 0;
384
385 if (!mac_vnode_enforce)
386 return;
387
388 MAC_PERFORM(vnode_label_update_extattr, mp, mp->mnt_mntlabel, vp,
389 vp->v_label, name);
390 if (error == 0)
391 return;
392
393 vnode_lock(vp);
394 vnode_relabel(vp);
395 vnode_unlock(vp);
396 return;
397 }
398
399 static int
400 mac_vnode_label_store(vfs_context_t ctx, struct vnode *vp,
401 struct label *intlabel)
402 {
403 kauth_cred_t cred;
404 int error;
405
406 if (!mac_vnode_enforce &&
407 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
408 return 0;
409
410 cred = vfs_context_ucred(ctx);
411 MAC_CHECK(vnode_label_store, cred, vp, vp->v_label, intlabel);
412
413 return (error);
414 }
415
416 void
417 mac_cred_label_update_execve(vfs_context_t ctx, kauth_cred_t new, struct vnode *vp,
418 struct label *scriptvnodelabel, struct label *execl)
419 {
420 kauth_cred_t cred;
421
422 if (!mac_proc_enforce && !mac_vnode_enforce)
423 return;
424
425 /* mark the new cred to indicate "matching" includes the label */
426 new->cr_flags |= CRF_MAC_ENFORCE;
427
428 cred = vfs_context_ucred(ctx);
429 MAC_PERFORM(cred_label_update_execve, cred, new, vp, vp->v_label,
430 scriptvnodelabel, execl);
431 }
432
433 int
434 mac_cred_check_label_update_execve(vfs_context_t ctx, struct vnode *vp,
435 struct label *scriptvnodelabel, struct label *execlabel, struct proc *p)
436 {
437 kauth_cred_t cred;
438 int result = 0;
439
440 if (!mac_proc_enforce && !mac_vnode_enforce)
441 return result;
442
443 cred = vfs_context_ucred(ctx);
444 MAC_BOOLEAN(cred_check_label_update_execve, ||, cred, vp, vp->v_label,
445 scriptvnodelabel, execlabel, p);
446
447 return (result);
448 }
449
450 int
451 mac_vnode_check_access(vfs_context_t ctx, struct vnode *vp,
452 int acc_mode)
453 {
454 kauth_cred_t cred;
455 int error;
456 int mask;
457
458 if (!mac_vnode_enforce ||
459 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
460 return 0;
461
462 cred = vfs_context_ucred(ctx);
463 /* Convert {R,W,X}_OK values to V{READ,WRITE,EXEC} for entry points */
464 mask = ACCESS_MODE_TO_VNODE_MASK(acc_mode);
465 MAC_CHECK(vnode_check_access, cred, vp, vp->v_label, mask);
466 return (error);
467 }
468
469 int
470 mac_vnode_check_chdir(vfs_context_t ctx, struct vnode *dvp)
471 {
472 kauth_cred_t cred;
473 int error;
474
475 if (!mac_vnode_enforce ||
476 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
477 return (0);
478
479 cred = vfs_context_ucred(ctx);
480 MAC_CHECK(vnode_check_chdir, cred, dvp, dvp->v_label);
481 return (error);
482 }
483
484 int
485 mac_vnode_check_chroot(vfs_context_t ctx, struct vnode *dvp,
486 struct componentname *cnp)
487 {
488 kauth_cred_t cred;
489 int error;
490
491 if (!mac_vnode_enforce ||
492 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
493 return (0);
494
495 cred = vfs_context_ucred(ctx);
496 MAC_CHECK(vnode_check_chroot, cred, dvp, dvp->v_label, cnp);
497 return (error);
498 }
499
500 int
501 mac_vnode_check_create(vfs_context_t ctx, struct vnode *dvp,
502 struct componentname *cnp, struct vnode_attr *vap)
503 {
504 kauth_cred_t cred;
505 int error;
506
507 if (!mac_vnode_enforce ||
508 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
509 return (0);
510
511 cred = vfs_context_ucred(ctx);
512 MAC_CHECK(vnode_check_create, cred, dvp, dvp->v_label, cnp, vap);
513 return (error);
514 }
515
516 int
517 mac_vnode_check_unlink(vfs_context_t ctx, struct vnode *dvp, struct vnode *vp,
518 struct componentname *cnp)
519 {
520 kauth_cred_t cred;
521 int error;
522
523 if (!mac_vnode_enforce ||
524 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
525 return (0);
526
527 cred = vfs_context_ucred(ctx);
528 MAC_CHECK(vnode_check_unlink, cred, dvp, dvp->v_label, vp,
529 vp->v_label, cnp);
530 return (error);
531 }
532 #if 0
533 int
534 mac_vnode_check_deleteacl(vfs_context_t ctx, struct vnode *vp,
535 acl_type_t type)
536 {
537 kauth_cred_t cred;
538 int error;
539
540 if (!mac_vnode_enforce ||
541 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
542 return (0);
543
544 cred = vfs_context_ucred(ctx);
545 MAC_CHECK(vnode_check_deleteacl, cred, vp, vp->v_label, type);
546 return (error);
547 }
548 #endif
549
550 int
551 mac_vnode_check_deleteextattr(vfs_context_t ctx, struct vnode *vp,
552 const char *name)
553 {
554 kauth_cred_t cred;
555 int error;
556
557 if (!mac_vnode_enforce ||
558 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
559 return (0);
560
561 cred = vfs_context_ucred(ctx);
562 MAC_CHECK(vnode_check_deleteextattr, cred, vp, vp->v_label, name);
563 return (error);
564 }
565 int
566 mac_vnode_check_exchangedata(vfs_context_t ctx,
567 struct vnode *v1, struct vnode *v2)
568 {
569 kauth_cred_t cred;
570 int error;
571
572 if (!mac_vnode_enforce ||
573 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
574 return (0);
575
576 cred = vfs_context_ucred(ctx);
577 MAC_CHECK(vnode_check_exchangedata, cred, v1, v1->v_label,
578 v2, v2->v_label);
579
580 return (error);
581 }
582
583 #if 0
584 int
585 mac_vnode_check_getacl(vfs_context_t ctx, struct vnode *vp, acl_type_t type)
586 {
587 kauth_cred_t cred;
588 int error;
589
590 if (!mac_vnode_enforce ||
591 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
592 return (0);
593
594 cred = vfs_context_ucred(ctx);
595 MAC_CHECK(vnode_check_getacl, cred, vp, vp->v_label, type);
596 return (error);
597 }
598 #endif
599
600 int
601 mac_vnode_check_getattrlist(vfs_context_t ctx, struct vnode *vp,
602 struct attrlist *alist)
603 {
604 kauth_cred_t cred;
605 int error;
606
607 if (!mac_vnode_enforce ||
608 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
609 return (0);
610
611 cred = vfs_context_ucred(ctx);
612 MAC_CHECK(vnode_check_getattrlist, cred, vp, vp->v_label, alist);
613
614 /* Falsify results instead of returning error? */
615 return (error);
616 }
617
618 int
619 mac_vnode_check_exec(vfs_context_t ctx, struct vnode *vp,
620 struct image_params *imgp)
621 {
622 kauth_cred_t cred;
623 int error;
624
625 if (!mac_vnode_enforce || !mac_proc_enforce)
626 return (0);
627
628 cred = vfs_context_ucred(ctx);
629 MAC_CHECK(vnode_check_exec, cred, vp, vp->v_label,
630 (imgp != NULL) ? imgp->ip_execlabelp : NULL,
631 (imgp != NULL) ? &imgp->ip_ndp->ni_cnd : NULL,
632 (imgp != NULL) ? &imgp->ip_csflags : NULL);
633 return (error);
634 }
635
636 int
637 mac_vnode_check_signature(struct vnode *vp, unsigned char *sha1,
638 void * signature, size_t size)
639 {
640 int error;
641
642 if (!mac_vnode_enforce || !mac_proc_enforce)
643 return (0);
644
645 MAC_CHECK(vnode_check_signature, vp, vp->v_label, sha1, signature, size);
646 return (error);
647 }
648
649 #if 0
650 int
651 mac_vnode_check_getacl(vfs_context_t ctx, struct vnode *vp, acl_type_t type)
652 {
653 kauth_cred_t cred;
654 int error;
655
656 if (!mac_vnode_enforce ||
657 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
658 return (0);
659
660 cred = vfs_context_ucred(ctx);
661 MAC_CHECK(vnode_check_getacl, cred, vp, vp->v_label, type);
662 return (error);
663 }
664 #endif
665
666 int
667 mac_vnode_check_getextattr(vfs_context_t ctx, struct vnode *vp,
668 const char *name, struct uio *uio)
669 {
670 kauth_cred_t cred;
671 int error;
672
673 if (!mac_vnode_enforce ||
674 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
675 return (0);
676
677 cred = vfs_context_ucred(ctx);
678 MAC_CHECK(vnode_check_getextattr, cred, vp, vp->v_label,
679 name, uio);
680 return (error);
681 }
682
683 int
684 mac_vnode_check_ioctl(vfs_context_t ctx, struct vnode *vp, u_int cmd)
685 {
686 kauth_cred_t cred;
687 int error;
688
689 if (!mac_vnode_enforce ||
690 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
691 return (0);
692
693 cred = vfs_context_ucred(ctx);
694 MAC_CHECK(vnode_check_ioctl, cred, vp, vp->v_label, cmd);
695 return (error);
696 }
697
698 int
699 mac_vnode_check_kqfilter(vfs_context_t ctx, kauth_cred_t file_cred,
700 struct knote *kn, struct vnode *vp)
701 {
702 kauth_cred_t cred;
703 int error;
704
705 if (!mac_vnode_enforce ||
706 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
707 return (0);
708
709 cred = vfs_context_ucred(ctx);
710 MAC_CHECK(vnode_check_kqfilter, cred, file_cred, kn, vp,
711 vp->v_label);
712
713 return (error);
714 }
715
716 int
717 mac_vnode_check_link(vfs_context_t ctx, struct vnode *dvp,
718 struct vnode *vp, struct componentname *cnp)
719 {
720 kauth_cred_t cred;
721 int error;
722
723 if (!mac_vnode_enforce ||
724 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
725 return (0);
726
727 cred = vfs_context_ucred(ctx);
728 MAC_CHECK(vnode_check_link, cred, dvp, dvp->v_label, vp,
729 vp->v_label, cnp);
730 return (error);
731 }
732
733 int
734 mac_vnode_check_listextattr(vfs_context_t ctx, struct vnode *vp)
735 {
736 kauth_cred_t cred;
737 int error;
738
739 if (!mac_vnode_enforce ||
740 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
741 return (0);
742
743 cred = vfs_context_ucred(ctx);
744 MAC_CHECK(vnode_check_listextattr, cred, vp, vp->v_label);
745 return (error);
746 }
747
748 int
749 mac_vnode_check_lookup(vfs_context_t ctx, struct vnode *dvp,
750 struct componentname *cnp)
751 {
752 kauth_cred_t cred;
753 int error;
754
755 if (!mac_vnode_enforce ||
756 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
757 return (0);
758
759 cred = vfs_context_ucred(ctx);
760 MAC_CHECK(vnode_check_lookup, cred, dvp, dvp->v_label, cnp);
761 return (error);
762 }
763
764 int
765 mac_vnode_check_open(vfs_context_t ctx, struct vnode *vp, int acc_mode)
766 {
767 kauth_cred_t cred;
768 int error;
769
770 if (!mac_vnode_enforce ||
771 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
772 return (0);
773
774 cred = vfs_context_ucred(ctx);
775 MAC_CHECK(vnode_check_open, cred, vp, vp->v_label, acc_mode);
776 return (error);
777 }
778
779 int
780 mac_vnode_check_read(vfs_context_t ctx, struct ucred *file_cred,
781 struct vnode *vp)
782 {
783 kauth_cred_t cred;
784 int error;
785
786 if (!mac_vnode_enforce ||
787 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
788 return (0);
789
790 cred = vfs_context_ucred(ctx);
791 MAC_CHECK(vnode_check_read, cred, file_cred, vp,
792 vp->v_label);
793
794 return (error);
795 }
796
797 int
798 mac_vnode_check_readdir(vfs_context_t ctx, struct vnode *dvp)
799 {
800 kauth_cred_t cred;
801 int error;
802
803 if (!mac_vnode_enforce ||
804 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
805 return (0);
806
807 cred = vfs_context_ucred(ctx);
808 MAC_CHECK(vnode_check_readdir, cred, dvp, dvp->v_label);
809 return (error);
810 }
811
812 int
813 mac_vnode_check_readlink(vfs_context_t ctx, struct vnode *vp)
814 {
815 kauth_cred_t cred;
816 int error;
817
818 if (!mac_vnode_enforce ||
819 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
820 return (0);
821
822 cred = vfs_context_ucred(ctx);
823 MAC_CHECK(vnode_check_readlink, cred, vp, vp->v_label);
824 return (error);
825 }
826
827 int
828 mac_vnode_check_label_update(vfs_context_t ctx, struct vnode *vp,
829 struct label *newlabel)
830 {
831 kauth_cred_t cred;
832 int error;
833
834 if (!mac_vnode_enforce ||
835 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
836 return (0);
837
838 cred = vfs_context_ucred(ctx);
839 MAC_CHECK(vnode_check_label_update, cred, vp, vp->v_label, newlabel);
840
841 return (error);
842 }
843
844 int
845 mac_vnode_check_rename_from(vfs_context_t ctx, struct vnode *dvp,
846 struct vnode *vp, struct componentname *cnp)
847 {
848 kauth_cred_t cred;
849 int error;
850
851 if (!mac_vnode_enforce ||
852 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
853 return (0);
854
855 cred = vfs_context_ucred(ctx);
856 MAC_CHECK(vnode_check_rename_from, cred, dvp, dvp->v_label, vp,
857 vp->v_label, cnp);
858 return (error);
859 }
860
861 int
862 mac_vnode_check_rename_to(vfs_context_t ctx, struct vnode *dvp,
863 struct vnode *vp, int samedir, struct componentname *cnp)
864 {
865 kauth_cred_t cred;
866 int error;
867
868 if (!mac_vnode_enforce ||
869 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
870 return (0);
871
872 cred = vfs_context_ucred(ctx);
873 MAC_CHECK(vnode_check_rename_to, cred, dvp, dvp->v_label, vp,
874 vp != NULL ? vp->v_label : NULL, samedir, cnp);
875 return (error);
876 }
877
878 int
879 mac_vnode_check_revoke(vfs_context_t ctx, struct vnode *vp)
880 {
881 kauth_cred_t cred;
882 int error;
883
884 if (!mac_vnode_enforce ||
885 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
886 return (0);
887
888 cred = vfs_context_ucred(ctx);
889 MAC_CHECK(vnode_check_revoke, cred, vp, vp->v_label);
890 return (error);
891 }
892
893 int
894 mac_vnode_check_select(vfs_context_t ctx, struct vnode *vp, int which)
895 {
896 kauth_cred_t cred;
897 int error;
898
899 if (!mac_vnode_enforce ||
900 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
901 return (0);
902
903 cred = vfs_context_ucred(ctx);
904 MAC_CHECK(vnode_check_select, cred, vp, vp->v_label, which);
905 return (error);
906 }
907
908 #if 0
909 int
910 mac_vnode_check_setacl(vfs_context_t ctx, struct vnode *vp, acl_type_t type,
911 struct acl *acl)
912 {
913 kauth_cred_t cred;
914 int error;
915
916 if (!mac_vnode_enforce ||
917 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
918 return (0);
919
920 cred = vfs_context_ucred(ctx);
921 MAC_CHECK(vnode_check_setacl, cred, vp, vp->v_label, type, acl);
922 return (error);
923 }
924 #endif
925
926 int
927 mac_vnode_check_setattrlist(vfs_context_t ctx, struct vnode *vp,
928 struct attrlist *alist)
929 {
930 kauth_cred_t cred;
931 int error;
932
933 if (!mac_vnode_enforce ||
934 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
935 return (0);
936
937 cred = vfs_context_ucred(ctx);
938 MAC_CHECK(vnode_check_setattrlist, cred, vp, vp->v_label, alist);
939 return (error);
940 }
941
942 int
943 mac_vnode_check_setextattr(vfs_context_t ctx, struct vnode *vp,
944 const char *name, struct uio *uio)
945 {
946 kauth_cred_t cred;
947 int error;
948
949 if (!mac_vnode_enforce ||
950 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
951 return (0);
952
953 cred = vfs_context_ucred(ctx);
954 MAC_CHECK(vnode_check_setextattr, cred, vp, vp->v_label,
955 name, uio);
956 return (error);
957 }
958
959 int
960 mac_vnode_check_setflags(vfs_context_t ctx, struct vnode *vp, u_long flags)
961 {
962 kauth_cred_t cred;
963 int error;
964
965 if (!mac_vnode_enforce ||
966 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
967 return (0);
968
969 cred = vfs_context_ucred(ctx);
970 MAC_CHECK(vnode_check_setflags, cred, vp, vp->v_label, flags);
971 return (error);
972 }
973
974 int
975 mac_vnode_check_setmode(vfs_context_t ctx, struct vnode *vp, mode_t mode)
976 {
977 kauth_cred_t cred;
978 int error;
979
980 if (!mac_vnode_enforce ||
981 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
982 return (0);
983
984 cred = vfs_context_ucred(ctx);
985 MAC_CHECK(vnode_check_setmode, cred, vp, vp->v_label, mode);
986 return (error);
987 }
988
989 int
990 mac_vnode_check_setowner(vfs_context_t ctx, struct vnode *vp, uid_t uid,
991 gid_t gid)
992 {
993 kauth_cred_t cred;
994 int error;
995
996 if (!mac_vnode_enforce ||
997 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
998 return (0);
999
1000 cred = vfs_context_ucred(ctx);
1001 MAC_CHECK(vnode_check_setowner, cred, vp, vp->v_label, uid, gid);
1002 return (error);
1003 }
1004
1005 int
1006 mac_vnode_check_setutimes(vfs_context_t ctx, struct vnode *vp,
1007 struct timespec atime, struct timespec mtime)
1008 {
1009 kauth_cred_t cred;
1010 int error;
1011
1012 if (!mac_vnode_enforce ||
1013 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1014 return (0);
1015
1016 cred = vfs_context_ucred(ctx);
1017 MAC_CHECK(vnode_check_setutimes, cred, vp, vp->v_label, atime,
1018 mtime);
1019 return (error);
1020 }
1021
1022 int
1023 mac_vnode_check_stat(vfs_context_t ctx, struct ucred *file_cred,
1024 struct vnode *vp)
1025 {
1026 kauth_cred_t cred;
1027 int error;
1028
1029 if (!mac_vnode_enforce ||
1030 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1031 return (0);
1032
1033 cred = vfs_context_ucred(ctx);
1034 MAC_CHECK(vnode_check_stat, cred, file_cred, vp,
1035 vp->v_label);
1036 return (error);
1037 }
1038
1039 int
1040 mac_vnode_check_truncate(vfs_context_t ctx, struct ucred *file_cred,
1041 struct vnode *vp)
1042 {
1043 kauth_cred_t cred;
1044 int error;
1045
1046 if (!mac_vnode_enforce ||
1047 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1048 return (0);
1049
1050 cred = vfs_context_ucred(ctx);
1051 MAC_CHECK(vnode_check_truncate, cred, file_cred, vp,
1052 vp->v_label);
1053
1054 return (error);
1055 }
1056
1057 int
1058 mac_vnode_check_write(vfs_context_t ctx, struct ucred *file_cred,
1059 struct vnode *vp)
1060 {
1061 kauth_cred_t cred;
1062 int error;
1063
1064 if (!mac_vnode_enforce ||
1065 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1066 return (0);
1067
1068 cred = vfs_context_ucred(ctx);
1069 MAC_CHECK(vnode_check_write, cred, file_cred, vp, vp->v_label);
1070
1071 return (error);
1072 }
1073
1074 void
1075 mac_vnode_label_update(vfs_context_t ctx, struct vnode *vp, struct label *newlabel)
1076 {
1077 kauth_cred_t cred = vfs_context_ucred(ctx);
1078
1079 vnode_lock(vp);
1080 MAC_PERFORM(vnode_label_update, cred, vp, vp->v_label, newlabel);
1081 vnode_unlock(vp);
1082 }
1083
1084 void
1085 mac_mount_label_associate(vfs_context_t ctx, struct mount *mp)
1086 {
1087 kauth_cred_t cred = vfs_context_ucred(ctx);
1088
1089 /* XXX: eventually this logic may be handled by the policy? */
1090
1091 /* We desire MULTILABEL for the root filesystem. */
1092 if ((mp->mnt_flag & MNT_ROOTFS) &&
1093 (strcmp(mp->mnt_vfsstat.f_fstypename, "hfs") == 0))
1094 mp->mnt_flag |= MNT_MULTILABEL;
1095
1096 /* MULTILABEL on DEVFS. */
1097 if (strcmp(mp->mnt_vfsstat.f_fstypename, "devfs") == 0)
1098 mp->mnt_flag |= MNT_MULTILABEL;
1099
1100 /* MULTILABEL on FDESC pseudo-filesystem. */
1101 if (strcmp(mp->mnt_vfsstat.f_fstypename, "fdesc") == 0)
1102 mp->mnt_flag |= MNT_MULTILABEL;
1103
1104 /* MULTILABEL on all NFS filesystems. */
1105 if (strcmp(mp->mnt_vfsstat.f_fstypename, "nfs") == 0)
1106 mp->mnt_flag |= MNT_MULTILABEL;
1107
1108 /* MULTILABEL on all AFP filesystems. */
1109 if (strcmp(mp->mnt_vfsstat.f_fstypename, "afpfs") == 0)
1110 mp->mnt_flag |= MNT_MULTILABEL;
1111
1112 if (mp->mnt_vtable != NULL) {
1113 /* Any filesystem that supports native XATTRs. */
1114 if ((mp->mnt_vtable->vfc_vfsflags & VFC_VFSNATIVEXATTR))
1115 mp->mnt_flag |= MNT_MULTILABEL;
1116
1117 /* Filesystem does not support multilabel. */
1118 if ((mp->mnt_vtable->vfc_vfsflags & VFC_VFSNOMACLABEL) &&
1119 (mp->mnt_flag & MNT_MULTILABEL))
1120 mp->mnt_flag &= ~MNT_MULTILABEL;
1121 }
1122
1123 MAC_PERFORM(mount_label_associate, cred, mp, mp->mnt_mntlabel);
1124 #if MAC_DEBUG
1125 printf("MAC Framework enabling %s support: %s -> %s (%s)\n",
1126 mp->mnt_flag & MNT_MULTILABEL ? "multilabel" : "singlelabel",
1127 mp->mnt_vfsstat.f_mntfromname,
1128 mp->mnt_vfsstat.f_mntonname,
1129 mp->mnt_vfsstat.f_fstypename);
1130 #endif
1131 }
1132
1133 int
1134 mac_mount_check_mount(vfs_context_t ctx, struct vnode *vp,
1135 struct componentname *cnp, const char *vfc_name)
1136 {
1137 kauth_cred_t cred;
1138 int error;
1139
1140 if (!mac_vnode_enforce ||
1141 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1142 return (0);
1143
1144 cred = vfs_context_ucred(ctx);
1145 MAC_CHECK(mount_check_mount, cred, vp, vp->v_label, cnp, vfc_name);
1146
1147 return (error);
1148 }
1149
1150 int
1151 mac_mount_check_remount(vfs_context_t ctx, struct mount *mp)
1152 {
1153 kauth_cred_t cred;
1154 int error;
1155
1156 if (!mac_vnode_enforce ||
1157 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1158 return (0);
1159
1160 cred = vfs_context_ucred(ctx);
1161 MAC_CHECK(mount_check_remount, cred, mp, mp->mnt_mntlabel);
1162
1163 return (error);
1164 }
1165
1166 int
1167 mac_mount_check_umount(vfs_context_t ctx, struct mount *mp)
1168 {
1169 kauth_cred_t cred;
1170 int error;
1171
1172 if (!mac_vnode_enforce ||
1173 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1174 return (0);
1175
1176 cred = vfs_context_ucred(ctx);
1177 MAC_CHECK(mount_check_umount, cred, mp, mp->mnt_mntlabel);
1178
1179 return (error);
1180 }
1181
1182 int
1183 mac_mount_check_getattr(vfs_context_t ctx, struct mount *mp,
1184 struct vfs_attr *vfa)
1185 {
1186 kauth_cred_t cred;
1187 int error;
1188
1189 if (!mac_vnode_enforce ||
1190 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1191 return (0);
1192
1193 cred = vfs_context_ucred(ctx);
1194 MAC_CHECK(mount_check_getattr, cred, mp, mp->mnt_mntlabel, vfa);
1195 return (error);
1196 }
1197
1198 int
1199 mac_mount_check_setattr(vfs_context_t ctx, struct mount *mp,
1200 struct vfs_attr *vfa)
1201 {
1202 kauth_cred_t cred;
1203 int error;
1204
1205 if (!mac_vnode_enforce ||
1206 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1207 return (0);
1208
1209 cred = vfs_context_ucred(ctx);
1210 MAC_CHECK(mount_check_setattr, cred, mp, mp->mnt_mntlabel, vfa);
1211 return (error);
1212 }
1213
1214 int
1215 mac_mount_check_stat(vfs_context_t ctx, struct mount *mount)
1216 {
1217 kauth_cred_t cred;
1218 int error;
1219
1220 if (!mac_vnode_enforce ||
1221 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1222 return (0);
1223
1224 cred = vfs_context_ucred(ctx);
1225 MAC_CHECK(mount_check_stat, cred, mount, mount->mnt_mntlabel);
1226
1227 return (error);
1228 }
1229
1230 int
1231 mac_mount_check_label_update(vfs_context_t ctx, struct mount *mount)
1232 {
1233 kauth_cred_t cred;
1234 int error;
1235
1236 if (!mac_vnode_enforce ||
1237 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1238 return (0);
1239
1240 cred = vfs_context_ucred(ctx);
1241 MAC_CHECK(mount_check_label_update, cred, mount, mount->mnt_mntlabel);
1242
1243 return (error);
1244 }
1245
1246 int
1247 mac_mount_check_fsctl(vfs_context_t ctx, struct mount *mp, u_int cmd)
1248 {
1249 kauth_cred_t cred;
1250 int error;
1251
1252 if (!mac_vnode_enforce ||
1253 !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1254 return (0);
1255
1256 cred = vfs_context_ucred(ctx);
1257 MAC_CHECK(mount_check_fsctl, cred, mp, mp->mnt_mntlabel, cmd);
1258
1259 return (error);
1260 }
1261
1262 void
1263 mac_devfs_label_associate_device(dev_t dev, struct devnode *de,
1264 const char *fullpath)
1265 {
1266 if (!mac_device_enforce)
1267 return;
1268
1269 MAC_PERFORM(devfs_label_associate_device, dev, de, de->dn_label,
1270 fullpath);
1271 }
1272
1273 void
1274 mac_devfs_label_associate_directory(const char *dirname, int dirnamelen,
1275 struct devnode *de, const char *fullpath)
1276 {
1277 if (!mac_device_enforce)
1278 return;
1279
1280 MAC_PERFORM(devfs_label_associate_directory, dirname, dirnamelen, de,
1281 de->dn_label, fullpath);
1282 }
1283
1284 int
1285 vn_setlabel(struct vnode *vp, struct label *intlabel, vfs_context_t context)
1286 {
1287 int error;
1288
1289 if (!mac_vnode_enforce)
1290 return (0);
1291
1292 if (vp->v_mount == NULL) {
1293 printf("vn_setlabel: null v_mount\n");
1294 if (vp->v_type != VNON)
1295 printf("vn_setlabel: null v_mount with non-VNON\n");
1296 return (EBADF);
1297 }
1298
1299 if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
1300 return (ENOTSUP);
1301
1302 /*
1303 * Multi-phase commit. First check the policies to confirm the
1304 * change is OK. Then commit via the filesystem. Finally,
1305 * update the actual vnode label. Question: maybe the filesystem
1306 * should update the vnode at the end as part of VNOP_SETLABEL()?
1307 */
1308 error = mac_vnode_check_label_update(context, vp, intlabel);
1309 if (error)
1310 return (error);
1311
1312 error = VNOP_SETLABEL(vp, intlabel, context);
1313 if (error == ENOTSUP) {
1314 error = mac_vnode_label_store(context, vp,
1315 intlabel);
1316 if (error) {
1317 printf("%s: mac_vnode_label_store failed %d\n",
1318 __func__, error);
1319 return (error);
1320 }
1321 mac_vnode_label_update(context, vp, intlabel);
1322 } else
1323 if (error) {
1324 printf("vn_setlabel: vop setlabel failed %d\n", error);
1325 return (error);
1326 }
1327
1328 return (0);
1329 }
1330
1331 int
1332 mac_vnode_label_associate_fdesc(struct mount *mp, struct fdescnode *fnp,
1333 struct vnode *vp, vfs_context_t ctx)
1334 {
1335 struct fileproc *fp;
1336 struct socket *so;
1337 struct pipe *cpipe;
1338 struct vnode *fvp;
1339 struct proc *p;
1340 int error;
1341
1342 error = 0;
1343
1344 /*
1345 * If no backing file, let the policy choose which label to use.
1346 */
1347 if (fnp->fd_fd == -1) {
1348 MAC_PERFORM(vnode_label_associate_file, vfs_context_ucred(ctx),
1349 mp, mp->mnt_mntlabel, NULL, NULL, vp, vp->v_label);
1350 return (0);
1351 }
1352
1353 p = vfs_context_proc(ctx);
1354 error = fp_lookup(p, fnp->fd_fd, &fp, 0);
1355 if (error)
1356 return (error);
1357
1358 if (fp->f_fglob == NULL) {
1359 error = EBADF;
1360 goto out;
1361 }
1362
1363 switch (fp->f_fglob->fg_type) {
1364 case DTYPE_VNODE:
1365 fvp = (struct vnode *)fp->f_fglob->fg_data;
1366 if ((error = vnode_getwithref(fvp)))
1367 goto out;
1368 MAC_PERFORM(vnode_label_copy, fvp->v_label, vp->v_label);
1369 (void)vnode_put(fvp);
1370 break;
1371 case DTYPE_SOCKET:
1372 so = (struct socket *)fp->f_fglob->fg_data;
1373 socket_lock(so, 1);
1374 MAC_PERFORM(vnode_label_associate_socket,
1375 vfs_context_ucred(ctx), (socket_t)so, so->so_label,
1376 vp, vp->v_label);
1377 socket_unlock(so, 1);
1378 break;
1379 case DTYPE_PSXSHM:
1380 pshm_label_associate(fp, vp, ctx);
1381 break;
1382 case DTYPE_PSXSEM:
1383 psem_label_associate(fp, vp, ctx);
1384 break;
1385 case DTYPE_PIPE:
1386 cpipe = (struct pipe *)fp->f_fglob->fg_data;
1387 /* kern/sys_pipe.c:pipe_select() suggests this test. */
1388 if (cpipe == (struct pipe *)-1) {
1389 error = EINVAL;
1390 goto out;
1391 }
1392 PIPE_LOCK(cpipe);
1393 MAC_PERFORM(vnode_label_associate_pipe, vfs_context_ucred(ctx),
1394 cpipe, cpipe->pipe_label, vp, vp->v_label);
1395 PIPE_UNLOCK(cpipe);
1396 break;
1397 case DTYPE_KQUEUE:
1398 case DTYPE_FSEVENTS:
1399 default:
1400 MAC_PERFORM(vnode_label_associate_file, vfs_context_ucred(ctx),
1401 mp, mp->mnt_mntlabel, fp->f_fglob, fp->f_fglob->fg_label,
1402 vp, vp->v_label);
1403 break;
1404 }
1405 out:
1406 fp_drop(p, fnp->fd_fd, fp, 0);
1407 return (error);
1408 }