xref: /freebsd/sys/security/mac/mac_vfs.c (revision 9162f64b58d01ec01481d60b6cdc06ffd8e8c7fc)
1 /*-
2  * Copyright (c) 1999-2002 Robert N. M. Watson
3  * Copyright (c) 2001 Ilmar S. Habibulin
4  * Copyright (c) 2001-2005 McAfee, Inc.
5  * Copyright (c) 2005-2006 SPARTA, Inc.
6  * Copyright (c) 2008 Apple Inc.
7  * All rights reserved.
8  *
9  * This software was developed by Robert Watson and Ilmar Habibulin for the
10  * TrustedBSD Project.
11  *
12  * This software was developed for the FreeBSD Project in part by McAfee
13  * Research, the Security Research Division of McAfee, Inc. under
14  * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
15  * CHATS research program.
16  *
17  * This software was enhanced by SPARTA ISSO under SPAWAR contract
18  * N66001-04-C-6019 ("SEFOS").
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 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include "opt_mac.h"
46 
47 #include <sys/param.h>
48 #include <sys/condvar.h>
49 #include <sys/extattr.h>
50 #include <sys/imgact.h>
51 #include <sys/kernel.h>
52 #include <sys/lock.h>
53 #include <sys/malloc.h>
54 #include <sys/mutex.h>
55 #include <sys/proc.h>
56 #include <sys/sbuf.h>
57 #include <sys/systm.h>
58 #include <sys/vnode.h>
59 #include <sys/mount.h>
60 #include <sys/file.h>
61 #include <sys/namei.h>
62 #include <sys/sysctl.h>
63 
64 #include <vm/vm.h>
65 #include <vm/pmap.h>
66 #include <vm/vm_map.h>
67 #include <vm/vm_object.h>
68 
69 #include <fs/devfs/devfs.h>
70 
71 #include <security/mac/mac_framework.h>
72 #include <security/mac/mac_internal.h>
73 #include <security/mac/mac_policy.h>
74 
75 /*
76  * Warn about EA transactions only the first time they happen.  No locking on
77  * this variable.
78  */
79 static int	ea_warn_once = 0;
80 
81 static int	mac_vnode_setlabel_extattr(struct ucred *cred,
82 		    struct vnode *vp, struct label *intlabel);
83 
84 static struct label *
85 mac_devfs_label_alloc(void)
86 {
87 	struct label *label;
88 
89 	label = mac_labelzone_alloc(M_WAITOK);
90 	MAC_PERFORM(devfs_init_label, label);
91 	return (label);
92 }
93 
94 void
95 mac_devfs_init(struct devfs_dirent *de)
96 {
97 
98 	if (mac_labeled & MPC_OBJECT_DEVFS)
99 		de->de_label = mac_devfs_label_alloc();
100 	else
101 		de->de_label = NULL;
102 }
103 
104 static struct label *
105 mac_mount_label_alloc(void)
106 {
107 	struct label *label;
108 
109 	label = mac_labelzone_alloc(M_WAITOK);
110 	MAC_PERFORM(mount_init_label, label);
111 	return (label);
112 }
113 
114 void
115 mac_mount_init(struct mount *mp)
116 {
117 
118 	if (mac_labeled & MPC_OBJECT_MOUNT)
119 		mp->mnt_label = mac_mount_label_alloc();
120 	else
121 		mp->mnt_label = NULL;
122 }
123 
124 struct label *
125 mac_vnode_label_alloc(void)
126 {
127 	struct label *label;
128 
129 	label = mac_labelzone_alloc(M_WAITOK);
130 	MAC_PERFORM(vnode_init_label, label);
131 	return (label);
132 }
133 
134 void
135 mac_vnode_init(struct vnode *vp)
136 {
137 
138 	if (mac_labeled & MPC_OBJECT_VNODE)
139 		vp->v_label = mac_vnode_label_alloc();
140 	else
141 		vp->v_label = NULL;
142 }
143 
144 static void
145 mac_devfs_label_free(struct label *label)
146 {
147 
148 	MAC_PERFORM(devfs_destroy_label, label);
149 	mac_labelzone_free(label);
150 }
151 
152 void
153 mac_devfs_destroy(struct devfs_dirent *de)
154 {
155 
156 	if (de->de_label != NULL) {
157 		mac_devfs_label_free(de->de_label);
158 		de->de_label = NULL;
159 	}
160 }
161 
162 static void
163 mac_mount_label_free(struct label *label)
164 {
165 
166 	MAC_PERFORM(mount_destroy_label, label);
167 	mac_labelzone_free(label);
168 }
169 
170 void
171 mac_mount_destroy(struct mount *mp)
172 {
173 
174 	if (mp->mnt_label != NULL) {
175 		mac_mount_label_free(mp->mnt_label);
176 		mp->mnt_label = NULL;
177 	}
178 }
179 
180 void
181 mac_vnode_label_free(struct label *label)
182 {
183 
184 	MAC_PERFORM(vnode_destroy_label, label);
185 	mac_labelzone_free(label);
186 }
187 
188 void
189 mac_vnode_destroy(struct vnode *vp)
190 {
191 
192 	if (vp->v_label != NULL) {
193 		mac_vnode_label_free(vp->v_label);
194 		vp->v_label = NULL;
195 	}
196 }
197 
198 void
199 mac_vnode_copy_label(struct label *src, struct label *dest)
200 {
201 
202 	MAC_PERFORM(vnode_copy_label, src, dest);
203 }
204 
205 int
206 mac_vnode_externalize_label(struct label *label, char *elements,
207     char *outbuf, size_t outbuflen)
208 {
209 	int error;
210 
211 	MAC_EXTERNALIZE(vnode, label, elements, outbuf, outbuflen);
212 
213 	return (error);
214 }
215 
216 int
217 mac_vnode_internalize_label(struct label *label, char *string)
218 {
219 	int error;
220 
221 	MAC_INTERNALIZE(vnode, label, string);
222 
223 	return (error);
224 }
225 
226 void
227 mac_devfs_update(struct mount *mp, struct devfs_dirent *de, struct vnode *vp)
228 {
229 
230 	MAC_PERFORM(devfs_update, mp, de, de->de_label, vp, vp->v_label);
231 }
232 
233 void
234 mac_devfs_vnode_associate(struct mount *mp, struct devfs_dirent *de,
235     struct vnode *vp)
236 {
237 
238 	MAC_PERFORM(devfs_vnode_associate, mp, mp->mnt_label, de,
239 	    de->de_label, vp, vp->v_label);
240 }
241 
242 int
243 mac_vnode_associate_extattr(struct mount *mp, struct vnode *vp)
244 {
245 	int error;
246 
247 	ASSERT_VOP_LOCKED(vp, "mac_vnode_associate_extattr");
248 
249 	MAC_CHECK(vnode_associate_extattr, mp, mp->mnt_label, vp,
250 	    vp->v_label);
251 
252 	return (error);
253 }
254 
255 void
256 mac_vnode_associate_singlelabel(struct mount *mp, struct vnode *vp)
257 {
258 
259 	MAC_PERFORM(vnode_associate_singlelabel, mp, mp->mnt_label, vp,
260 	    vp->v_label);
261 }
262 
263 /*
264  * Functions implementing extended-attribute backed labels for file systems
265  * that support it.
266  *
267  * Where possible, we use EA transactions to make writes to multiple
268  * attributes across difference policies mutually atomic.  We allow work to
269  * continue on file systems not supporting EA transactions, but generate a
270  * printf warning.
271  */
272 int
273 mac_vnode_create_extattr(struct ucred *cred, struct mount *mp,
274     struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
275 {
276 	int error;
277 
278 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_create_extattr");
279 	ASSERT_VOP_LOCKED(vp, "mac_vnode_create_extattr");
280 
281 	error = VOP_OPENEXTATTR(vp, cred, curthread);
282 	if (error == EOPNOTSUPP) {
283 		if (ea_warn_once == 0) {
284 			printf("Warning: transactions not supported "
285 			    "in EA write.\n");
286 			ea_warn_once = 1;
287 		}
288 	} else if (error)
289 		return (error);
290 
291 	MAC_CHECK(vnode_create_extattr, cred, mp, mp->mnt_label, dvp,
292 	    dvp->v_label, vp, vp->v_label, cnp);
293 
294 	if (error) {
295 		VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread);
296 		return (error);
297 	}
298 
299 	error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread);
300 	if (error == EOPNOTSUPP)
301 		error = 0;
302 
303 	return (error);
304 }
305 
306 static int
307 mac_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
308     struct label *intlabel)
309 {
310 	int error;
311 
312 	ASSERT_VOP_LOCKED(vp, "mac_vnode_setlabel_extattr");
313 
314 	error = VOP_OPENEXTATTR(vp, cred, curthread);
315 	if (error == EOPNOTSUPP) {
316 		if (ea_warn_once == 0) {
317 			printf("Warning: transactions not supported "
318 			    "in EA write.\n");
319 			ea_warn_once = 1;
320 		}
321 	} else if (error)
322 		return (error);
323 
324 	MAC_CHECK(vnode_setlabel_extattr, cred, vp, vp->v_label, intlabel);
325 
326 	if (error) {
327 		VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread);
328 		return (error);
329 	}
330 
331 	error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread);
332 	if (error == EOPNOTSUPP)
333 		error = 0;
334 
335 	return (error);
336 }
337 
338 void
339 mac_vnode_execve_transition(struct ucred *old, struct ucred *new,
340     struct vnode *vp, struct label *interpvplabel, struct image_params *imgp)
341 {
342 
343 	ASSERT_VOP_LOCKED(vp, "mac_vnode_execve_transition");
344 
345 	MAC_PERFORM(vnode_execve_transition, old, new, vp, vp->v_label,
346 	    interpvplabel, imgp, imgp->execlabel);
347 }
348 
349 int
350 mac_vnode_execve_will_transition(struct ucred *old, struct vnode *vp,
351     struct label *interpvplabel, struct image_params *imgp)
352 {
353 	int result;
354 
355 	ASSERT_VOP_LOCKED(vp, "mac_vnode_execve_will_transition");
356 
357 	result = 0;
358 	MAC_BOOLEAN(vnode_execve_will_transition, ||, old, vp, vp->v_label,
359 	    interpvplabel, imgp, imgp->execlabel);
360 
361 	return (result);
362 }
363 
364 int
365 mac_vnode_check_access(struct ucred *cred, struct vnode *vp, accmode_t accmode)
366 {
367 	int error;
368 
369 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_access");
370 
371 	MAC_CHECK(vnode_check_access, cred, vp, vp->v_label, accmode);
372 	return (error);
373 }
374 
375 int
376 mac_vnode_check_chdir(struct ucred *cred, struct vnode *dvp)
377 {
378 	int error;
379 
380 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_chdir");
381 
382 	MAC_CHECK(vnode_check_chdir, cred, dvp, dvp->v_label);
383 	return (error);
384 }
385 
386 int
387 mac_vnode_check_chroot(struct ucred *cred, struct vnode *dvp)
388 {
389 	int error;
390 
391 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_chroot");
392 
393 	MAC_CHECK(vnode_check_chroot, cred, dvp, dvp->v_label);
394 	return (error);
395 }
396 
397 int
398 mac_vnode_check_create(struct ucred *cred, struct vnode *dvp,
399     struct componentname *cnp, struct vattr *vap)
400 {
401 	int error;
402 
403 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_create");
404 
405 	MAC_CHECK(vnode_check_create, cred, dvp, dvp->v_label, cnp, vap);
406 	return (error);
407 }
408 
409 int
410 mac_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
411     acl_type_t type)
412 {
413 	int error;
414 
415 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_deleteacl");
416 
417 	MAC_CHECK(vnode_check_deleteacl, cred, vp, vp->v_label, type);
418 	return (error);
419 }
420 
421 int
422 mac_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
423     int attrnamespace, const char *name)
424 {
425 	int error;
426 
427 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_deleteextattr");
428 
429 	MAC_CHECK(vnode_check_deleteextattr, cred, vp, vp->v_label,
430 	    attrnamespace, name);
431 	return (error);
432 }
433 
434 int
435 mac_vnode_check_exec(struct ucred *cred, struct vnode *vp,
436     struct image_params *imgp)
437 {
438 	int error;
439 
440 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_exec");
441 
442 	MAC_CHECK(vnode_check_exec, cred, vp, vp->v_label, imgp,
443 	    imgp->execlabel);
444 
445 	return (error);
446 }
447 
448 int
449 mac_vnode_check_getacl(struct ucred *cred, struct vnode *vp, acl_type_t type)
450 {
451 	int error;
452 
453 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_getacl");
454 
455 	MAC_CHECK(vnode_check_getacl, cred, vp, vp->v_label, type);
456 	return (error);
457 }
458 
459 int
460 mac_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
461     int attrnamespace, const char *name, struct uio *uio)
462 {
463 	int error;
464 
465 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_getextattr");
466 
467 	MAC_CHECK(vnode_check_getextattr, cred, vp, vp->v_label,
468 	    attrnamespace, name, uio);
469 	return (error);
470 }
471 
472 int
473 mac_vnode_check_link(struct ucred *cred, struct vnode *dvp,
474     struct vnode *vp, struct componentname *cnp)
475 {
476 	int error;
477 
478 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_link");
479 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_link");
480 
481 	MAC_CHECK(vnode_check_link, cred, dvp, dvp->v_label, vp,
482 	    vp->v_label, cnp);
483 	return (error);
484 }
485 
486 int
487 mac_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
488     int attrnamespace)
489 {
490 	int error;
491 
492 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_listextattr");
493 
494 	MAC_CHECK(vnode_check_listextattr, cred, vp, vp->v_label,
495 	    attrnamespace);
496 	return (error);
497 }
498 
499 int
500 mac_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
501     struct componentname *cnp)
502 {
503 	int error;
504 
505 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_lookup");
506 
507 	MAC_CHECK(vnode_check_lookup, cred, dvp, dvp->v_label, cnp);
508 	return (error);
509 }
510 
511 int
512 mac_vnode_check_mmap(struct ucred *cred, struct vnode *vp, int prot,
513     int flags)
514 {
515 	int error;
516 
517 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_mmap");
518 
519 	MAC_CHECK(vnode_check_mmap, cred, vp, vp->v_label, prot, flags);
520 	return (error);
521 }
522 
523 void
524 mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
525     int *prot)
526 {
527 	int result = *prot;
528 
529 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_mmap_downgrade");
530 
531 	MAC_PERFORM(vnode_check_mmap_downgrade, cred, vp, vp->v_label,
532 	    &result);
533 
534 	*prot = result;
535 }
536 
537 int
538 mac_vnode_check_mprotect(struct ucred *cred, struct vnode *vp, int prot)
539 {
540 	int error;
541 
542 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_mprotect");
543 
544 	MAC_CHECK(vnode_check_mprotect, cred, vp, vp->v_label, prot);
545 	return (error);
546 }
547 
548 int
549 mac_vnode_check_open(struct ucred *cred, struct vnode *vp, accmode_t accmode)
550 {
551 	int error;
552 
553 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_open");
554 
555 	MAC_CHECK(vnode_check_open, cred, vp, vp->v_label, accmode);
556 	return (error);
557 }
558 
559 int
560 mac_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
561     struct vnode *vp)
562 {
563 	int error;
564 
565 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_poll");
566 
567 	MAC_CHECK(vnode_check_poll, active_cred, file_cred, vp,
568 	    vp->v_label);
569 
570 	return (error);
571 }
572 
573 int
574 mac_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
575     struct vnode *vp)
576 {
577 	int error;
578 
579 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_read");
580 
581 	MAC_CHECK(vnode_check_read, active_cred, file_cred, vp,
582 	    vp->v_label);
583 
584 	return (error);
585 }
586 
587 int
588 mac_vnode_check_readdir(struct ucred *cred, struct vnode *dvp)
589 {
590 	int error;
591 
592 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_readdir");
593 
594 	MAC_CHECK(vnode_check_readdir, cred, dvp, dvp->v_label);
595 	return (error);
596 }
597 
598 int
599 mac_vnode_check_readlink(struct ucred *cred, struct vnode *vp)
600 {
601 	int error;
602 
603 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_readlink");
604 
605 	MAC_CHECK(vnode_check_readlink, cred, vp, vp->v_label);
606 	return (error);
607 }
608 
609 static int
610 mac_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
611     struct label *newlabel)
612 {
613 	int error;
614 
615 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_relabel");
616 
617 	MAC_CHECK(vnode_check_relabel, cred, vp, vp->v_label, newlabel);
618 
619 	return (error);
620 }
621 
622 int
623 mac_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
624     struct vnode *vp, struct componentname *cnp)
625 {
626 	int error;
627 
628 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_rename_from");
629 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_rename_from");
630 
631 	MAC_CHECK(vnode_check_rename_from, cred, dvp, dvp->v_label, vp,
632 	    vp->v_label, cnp);
633 	return (error);
634 }
635 
636 int
637 mac_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
638     struct vnode *vp, int samedir, struct componentname *cnp)
639 {
640 	int error;
641 
642 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_rename_to");
643 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_rename_to");
644 
645 	MAC_CHECK(vnode_check_rename_to, cred, dvp, dvp->v_label, vp,
646 	    vp != NULL ? vp->v_label : NULL, samedir, cnp);
647 	return (error);
648 }
649 
650 int
651 mac_vnode_check_revoke(struct ucred *cred, struct vnode *vp)
652 {
653 	int error;
654 
655 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_revoke");
656 
657 	MAC_CHECK(vnode_check_revoke, cred, vp, vp->v_label);
658 	return (error);
659 }
660 
661 int
662 mac_vnode_check_setacl(struct ucred *cred, struct vnode *vp, acl_type_t type,
663     struct acl *acl)
664 {
665 	int error;
666 
667 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setacl");
668 
669 	MAC_CHECK(vnode_check_setacl, cred, vp, vp->v_label, type, acl);
670 	return (error);
671 }
672 
673 int
674 mac_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
675     int attrnamespace, const char *name, struct uio *uio)
676 {
677 	int error;
678 
679 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setextattr");
680 
681 	MAC_CHECK(vnode_check_setextattr, cred, vp, vp->v_label,
682 	    attrnamespace, name, uio);
683 	return (error);
684 }
685 
686 int
687 mac_vnode_check_setflags(struct ucred *cred, struct vnode *vp, u_long flags)
688 {
689 	int error;
690 
691 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setflags");
692 
693 	MAC_CHECK(vnode_check_setflags, cred, vp, vp->v_label, flags);
694 	return (error);
695 }
696 
697 int
698 mac_vnode_check_setmode(struct ucred *cred, struct vnode *vp, mode_t mode)
699 {
700 	int error;
701 
702 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setmode");
703 
704 	MAC_CHECK(vnode_check_setmode, cred, vp, vp->v_label, mode);
705 	return (error);
706 }
707 
708 int
709 mac_vnode_check_setowner(struct ucred *cred, struct vnode *vp, uid_t uid,
710     gid_t gid)
711 {
712 	int error;
713 
714 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setowner");
715 
716 	MAC_CHECK(vnode_check_setowner, cred, vp, vp->v_label, uid, gid);
717 	return (error);
718 }
719 
720 int
721 mac_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
722     struct timespec atime, struct timespec mtime)
723 {
724 	int error;
725 
726 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setutimes");
727 
728 	MAC_CHECK(vnode_check_setutimes, cred, vp, vp->v_label, atime,
729 	    mtime);
730 	return (error);
731 }
732 
733 int
734 mac_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
735     struct vnode *vp)
736 {
737 	int error;
738 
739 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_stat");
740 
741 	MAC_CHECK(vnode_check_stat, active_cred, file_cred, vp,
742 	    vp->v_label);
743 	return (error);
744 }
745 
746 int
747 mac_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
748     struct vnode *vp, struct componentname *cnp)
749 {
750 	int error;
751 
752 	ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_unlink");
753 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_unlink");
754 
755 	MAC_CHECK(vnode_check_unlink, cred, dvp, dvp->v_label, vp,
756 	    vp->v_label, cnp);
757 	return (error);
758 }
759 
760 int
761 mac_vnode_check_write(struct ucred *active_cred, struct ucred *file_cred,
762     struct vnode *vp)
763 {
764 	int error;
765 
766 	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_write");
767 
768 	MAC_CHECK(vnode_check_write, active_cred, file_cred, vp,
769 	    vp->v_label);
770 
771 	return (error);
772 }
773 
774 void
775 mac_vnode_relabel(struct ucred *cred, struct vnode *vp,
776     struct label *newlabel)
777 {
778 
779 	MAC_PERFORM(vnode_relabel, cred, vp, vp->v_label, newlabel);
780 }
781 
782 void
783 mac_mount_create(struct ucred *cred, struct mount *mp)
784 {
785 
786 	MAC_PERFORM(mount_create, cred, mp, mp->mnt_label);
787 }
788 
789 int
790 mac_mount_check_stat(struct ucred *cred, struct mount *mount)
791 {
792 	int error;
793 
794 	MAC_CHECK(mount_check_stat, cred, mount, mount->mnt_label);
795 
796 	return (error);
797 }
798 
799 void
800 mac_devfs_create_device(struct ucred *cred, struct mount *mp,
801     struct cdev *dev, struct devfs_dirent *de)
802 {
803 
804 	MAC_PERFORM(devfs_create_device, cred, mp, dev, de, de->de_label);
805 }
806 
807 void
808 mac_devfs_create_symlink(struct ucred *cred, struct mount *mp,
809     struct devfs_dirent *dd, struct devfs_dirent *de)
810 {
811 
812 	MAC_PERFORM(devfs_create_symlink, cred, mp, dd, dd->de_label, de,
813 	    de->de_label);
814 }
815 
816 void
817 mac_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
818     struct devfs_dirent *de)
819 {
820 
821 	MAC_PERFORM(devfs_create_directory, mp, dirname, dirnamelen, de,
822 	    de->de_label);
823 }
824 
825 /*
826  * Implementation of VOP_SETLABEL() that relies on extended attributes to
827  * store label data.  Can be referenced by filesystems supporting extended
828  * attributes.
829  */
830 int
831 vop_stdsetlabel_ea(struct vop_setlabel_args *ap)
832 {
833 	struct vnode *vp = ap->a_vp;
834 	struct label *intlabel = ap->a_label;
835 	int error;
836 
837 	ASSERT_VOP_LOCKED(vp, "vop_stdsetlabel_ea");
838 
839 	if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
840 		return (EOPNOTSUPP);
841 
842 	error = mac_vnode_setlabel_extattr(ap->a_cred, vp, intlabel);
843 	if (error)
844 		return (error);
845 
846 	mac_vnode_relabel(ap->a_cred, vp, intlabel);
847 
848 	return (0);
849 }
850 
851 int
852 vn_setlabel(struct vnode *vp, struct label *intlabel, struct ucred *cred)
853 {
854 	int error;
855 
856 	if (vp->v_mount == NULL) {
857 		/* printf("vn_setlabel: null v_mount\n"); */
858 		if (vp->v_type != VNON)
859 			printf("vn_setlabel: null v_mount with non-VNON\n");
860 		return (EBADF);
861 	}
862 
863 	if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
864 		return (EOPNOTSUPP);
865 
866 	/*
867 	 * Multi-phase commit.  First check the policies to confirm the
868 	 * change is OK.  Then commit via the filesystem.  Finally, update
869 	 * the actual vnode label.
870 	 *
871 	 * Question: maybe the filesystem should update the vnode at the end
872 	 * as part of VOP_SETLABEL()?
873 	 */
874 	error = mac_vnode_check_relabel(cred, vp, intlabel);
875 	if (error)
876 		return (error);
877 
878 	/*
879 	 * VADMIN provides the opportunity for the filesystem to make
880 	 * decisions about who is and is not able to modify labels and
881 	 * protections on files.  This might not be right.  We can't assume
882 	 * VOP_SETLABEL() will do it, because we might implement that as part
883 	 * of vop_stdsetlabel_ea().
884 	 */
885 	error = VOP_ACCESS(vp, VADMIN, cred, curthread);
886 	if (error)
887 		return (error);
888 
889 	error = VOP_SETLABEL(vp, intlabel, cred, curthread);
890 	if (error)
891 		return (error);
892 
893 	return (0);
894 }
895