mac_vfs.c revision 122524
1/*-
2 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc.
5 * All rights reserved.
6 *
7 * This software was developed by Robert Watson and Ilmar Habibulin for the
8 * TrustedBSD Project.
9 *
10 * This software was developed for the FreeBSD Project in part by Network
11 * Associates Laboratories, the Security Research Division of Network
12 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13 * as part of the DARPA CHATS research program.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/security/mac/mac_vfs.c 122524 2003-11-12 03:14:31Z rwatson $");
39
40#include "opt_mac.h"
41#include "opt_devfs.h"
42
43#include <sys/param.h>
44#include <sys/condvar.h>
45#include <sys/extattr.h>
46#include <sys/imgact.h>
47#include <sys/kernel.h>
48#include <sys/lock.h>
49#include <sys/malloc.h>
50#include <sys/mutex.h>
51#include <sys/mac.h>
52#include <sys/proc.h>
53#include <sys/sbuf.h>
54#include <sys/systm.h>
55#include <sys/vnode.h>
56#include <sys/mount.h>
57#include <sys/file.h>
58#include <sys/namei.h>
59#include <sys/sysctl.h>
60
61#include <vm/vm.h>
62#include <vm/pmap.h>
63#include <vm/vm_map.h>
64#include <vm/vm_object.h>
65
66#include <sys/mac_policy.h>
67
68#include <fs/devfs/devfs.h>
69
70#include <security/mac/mac_internal.h>
71
72/*
73 * Warn about EA transactions only the first time they happen.
74 * Weak coherency, no locking.
75 */
76static int	ea_warn_once = 0;
77
78static int	mac_enforce_fs = 1;
79SYSCTL_INT(_security_mac, OID_AUTO, enforce_fs, CTLFLAG_RW,
80    &mac_enforce_fs, 0, "Enforce MAC policy on file system objects");
81TUNABLE_INT("security.mac.enforce_fs", &mac_enforce_fs);
82
83#ifdef MAC_DEBUG
84static int	mac_debug_label_fallback = 0;
85SYSCTL_INT(_security_mac_debug, OID_AUTO, label_fallback, CTLFLAG_RW,
86    &mac_debug_label_fallback, 0, "Filesystems should fall back to fs label"
87    "when label is corrupted.");
88TUNABLE_INT("security.mac.debug_label_fallback",
89    &mac_debug_label_fallback);
90
91static unsigned int nmacmounts, nmacvnodes, nmacdevfsdirents;
92SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, mounts, CTLFLAG_RD,
93    &nmacmounts, 0, "number of mounts in use");
94SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, vnodes, CTLFLAG_RD,
95    &nmacvnodes, 0, "number of vnodes in use");
96SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, devfsdirents, CTLFLAG_RD,
97    &nmacdevfsdirents, 0, "number of devfs dirents inuse");
98#endif
99
100static int	mac_setlabel_vnode_extattr(struct ucred *cred,
101		    struct vnode *vp, struct label *intlabel);
102
103static struct label *
104mac_devfsdirent_label_alloc(void)
105{
106	struct label *label;
107
108	label = mac_labelzone_alloc(M_WAITOK);
109	MAC_PERFORM(init_devfsdirent_label, label);
110	MAC_DEBUG_COUNTER_INC(&nmacdevfsdirents);
111	return (label);
112}
113
114void
115mac_init_devfsdirent(struct devfs_dirent *de)
116{
117
118	de->de_label = mac_devfsdirent_label_alloc();
119}
120
121static struct label *
122mac_mount_label_alloc(void)
123{
124	struct label *label;
125
126	label = mac_labelzone_alloc(M_WAITOK);
127	MAC_PERFORM(init_mount_label, label);
128	MAC_DEBUG_COUNTER_INC(&nmacmounts);
129	return (label);
130}
131
132static struct label *
133mac_mount_fs_label_alloc(void)
134{
135	struct label *label;
136
137	label = mac_labelzone_alloc(M_WAITOK);
138	MAC_PERFORM(init_mount_fs_label, label);
139	MAC_DEBUG_COUNTER_INC(&nmacmounts);
140	return (label);
141}
142
143void
144mac_init_mount(struct mount *mp)
145{
146
147	mp->mnt_mntlabel = mac_mount_label_alloc();
148	mp->mnt_fslabel = mac_mount_fs_label_alloc();
149}
150
151struct label *
152mac_vnode_label_alloc(void)
153{
154	struct label *label;
155
156	label = mac_labelzone_alloc(M_WAITOK);
157	MAC_PERFORM(init_vnode_label, label);
158	MAC_DEBUG_COUNTER_INC(&nmacvnodes);
159	return (label);
160}
161
162void
163mac_init_vnode(struct vnode *vp)
164{
165
166	vp->v_label = mac_vnode_label_alloc();
167}
168
169static void
170mac_devfsdirent_label_free(struct label *label)
171{
172
173	MAC_PERFORM(destroy_devfsdirent_label, label);
174	mac_labelzone_free(label);
175	MAC_DEBUG_COUNTER_DEC(&nmacdevfsdirents);
176}
177
178void
179mac_destroy_devfsdirent(struct devfs_dirent *de)
180{
181
182	mac_devfsdirent_label_free(de->de_label);
183	de->de_label = NULL;
184}
185
186static void
187mac_mount_label_free(struct label *label)
188{
189
190	MAC_PERFORM(destroy_mount_label, label);
191	mac_labelzone_free(label);
192	MAC_DEBUG_COUNTER_DEC(&nmacmounts);
193}
194
195static void
196mac_mount_fs_label_free(struct label *label)
197{
198
199	MAC_PERFORM(destroy_mount_fs_label, label);
200	mac_labelzone_free(label);
201	MAC_DEBUG_COUNTER_DEC(&nmacmounts);
202}
203
204void
205mac_destroy_mount(struct mount *mp)
206{
207
208	mac_mount_fs_label_free(mp->mnt_fslabel);
209	mp->mnt_fslabel = NULL;
210	mac_mount_label_free(mp->mnt_mntlabel);
211	mp->mnt_mntlabel = NULL;
212}
213
214void
215mac_vnode_label_free(struct label *label)
216{
217
218	MAC_PERFORM(destroy_vnode_label, label);
219	mac_labelzone_free(label);
220	MAC_DEBUG_COUNTER_DEC(&nmacvnodes);
221}
222
223void
224mac_destroy_vnode(struct vnode *vp)
225{
226
227	mac_vnode_label_free(vp->v_label);
228	vp->v_label = NULL;
229}
230
231void
232mac_copy_vnode_label(struct label *src, struct label *dest)
233{
234
235	MAC_PERFORM(copy_vnode_label, src, dest);
236}
237
238int
239mac_externalize_vnode_label(struct label *label, char *elements,
240    char *outbuf, size_t outbuflen)
241{
242	int error;
243
244	MAC_EXTERNALIZE(vnode, label, elements, outbuf, outbuflen);
245
246	return (error);
247}
248
249int
250mac_internalize_vnode_label(struct label *label, char *string)
251{
252	int error;
253
254	MAC_INTERNALIZE(vnode, label, string);
255
256	return (error);
257}
258
259void
260mac_update_devfsdirent(struct mount *mp, struct devfs_dirent *de,
261    struct vnode *vp)
262{
263
264	MAC_PERFORM(update_devfsdirent, mp, de, de->de_label, vp,
265	    vp->v_label);
266}
267
268void
269mac_associate_vnode_devfs(struct mount *mp, struct devfs_dirent *de,
270    struct vnode *vp)
271{
272
273	MAC_PERFORM(associate_vnode_devfs, mp, mp->mnt_fslabel, de,
274	    de->de_label, vp, vp->v_label);
275}
276
277int
278mac_associate_vnode_extattr(struct mount *mp, struct vnode *vp)
279{
280	int error;
281
282	ASSERT_VOP_LOCKED(vp, "mac_associate_vnode_extattr");
283
284	MAC_CHECK(associate_vnode_extattr, mp, mp->mnt_fslabel, vp,
285	    vp->v_label);
286
287	return (error);
288}
289
290void
291mac_associate_vnode_singlelabel(struct mount *mp, struct vnode *vp)
292{
293
294	MAC_PERFORM(associate_vnode_singlelabel, mp, mp->mnt_fslabel, vp,
295	    vp->v_label);
296}
297
298int
299mac_create_vnode_extattr(struct ucred *cred, struct mount *mp,
300    struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
301{
302	int error;
303
304	ASSERT_VOP_LOCKED(dvp, "mac_create_vnode_extattr");
305	ASSERT_VOP_LOCKED(vp, "mac_create_vnode_extattr");
306
307	error = VOP_OPENEXTATTR(vp, cred, curthread);
308	if (error == EOPNOTSUPP) {
309		/* XXX: Optionally abort if transactions not supported. */
310		if (ea_warn_once == 0) {
311			printf("Warning: transactions not supported "
312			    "in EA write.\n");
313			ea_warn_once = 1;
314		}
315	} else if (error)
316		return (error);
317
318	MAC_CHECK(create_vnode_extattr, cred, mp, mp->mnt_fslabel,
319	    dvp, dvp->v_label, vp, vp->v_label, cnp);
320
321	if (error) {
322		VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread);
323		return (error);
324	}
325
326	error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread);
327
328	if (error == EOPNOTSUPP)
329		error = 0;				/* XXX */
330
331	return (error);
332}
333
334static int
335mac_setlabel_vnode_extattr(struct ucred *cred, struct vnode *vp,
336    struct label *intlabel)
337{
338	int error;
339
340	ASSERT_VOP_LOCKED(vp, "mac_setlabel_vnode_extattr");
341
342	error = VOP_OPENEXTATTR(vp, cred, curthread);
343	if (error == EOPNOTSUPP) {
344		/* XXX: Optionally abort if transactions not supported. */
345		if (ea_warn_once == 0) {
346			printf("Warning: transactions not supported "
347			    "in EA write.\n");
348			ea_warn_once = 1;
349		}
350	} else if (error)
351		return (error);
352
353	MAC_CHECK(setlabel_vnode_extattr, cred, vp, vp->v_label, intlabel);
354
355	if (error) {
356		VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread);
357		return (error);
358	}
359
360	error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread);
361
362	if (error == EOPNOTSUPP)
363		error = 0;				/* XXX */
364
365	return (error);
366}
367
368void
369mac_execve_transition(struct ucred *old, struct ucred *new, struct vnode *vp,
370    struct label *interpvnodelabel, struct image_params *imgp)
371{
372
373	ASSERT_VOP_LOCKED(vp, "mac_execve_transition");
374
375	if (!mac_enforce_process && !mac_enforce_fs)
376		return;
377
378	MAC_PERFORM(execve_transition, old, new, vp, vp->v_label,
379	    interpvnodelabel, imgp, imgp->execlabel);
380}
381
382int
383mac_execve_will_transition(struct ucred *old, struct vnode *vp,
384    struct label *interpvnodelabel, struct image_params *imgp)
385{
386	int result;
387
388	ASSERT_VOP_LOCKED(vp, "mac_execve_will_transition");
389
390	if (!mac_enforce_process && !mac_enforce_fs)
391		return (0);
392
393	result = 0;
394	MAC_BOOLEAN(execve_will_transition, ||, old, vp, vp->v_label,
395	    interpvnodelabel, imgp, imgp->execlabel);
396
397	return (result);
398}
399
400int
401mac_check_vnode_access(struct ucred *cred, struct vnode *vp, int acc_mode)
402{
403	int error;
404
405	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_access");
406
407	if (!mac_enforce_fs)
408		return (0);
409
410	MAC_CHECK(check_vnode_access, cred, vp, vp->v_label, acc_mode);
411	return (error);
412}
413
414int
415mac_check_vnode_chdir(struct ucred *cred, struct vnode *dvp)
416{
417	int error;
418
419	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_chdir");
420
421	if (!mac_enforce_fs)
422		return (0);
423
424	MAC_CHECK(check_vnode_chdir, cred, dvp, dvp->v_label);
425	return (error);
426}
427
428int
429mac_check_vnode_chroot(struct ucred *cred, struct vnode *dvp)
430{
431	int error;
432
433	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_chroot");
434
435	if (!mac_enforce_fs)
436		return (0);
437
438	MAC_CHECK(check_vnode_chroot, cred, dvp, dvp->v_label);
439	return (error);
440}
441
442int
443mac_check_vnode_create(struct ucred *cred, struct vnode *dvp,
444    struct componentname *cnp, struct vattr *vap)
445{
446	int error;
447
448	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_create");
449
450	if (!mac_enforce_fs)
451		return (0);
452
453	MAC_CHECK(check_vnode_create, cred, dvp, dvp->v_label, cnp, vap);
454	return (error);
455}
456
457int
458mac_check_vnode_delete(struct ucred *cred, struct vnode *dvp, struct vnode *vp,
459    struct componentname *cnp)
460{
461	int error;
462
463	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_delete");
464	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_delete");
465
466	if (!mac_enforce_fs)
467		return (0);
468
469	MAC_CHECK(check_vnode_delete, cred, dvp, dvp->v_label, vp,
470	    vp->v_label, cnp);
471	return (error);
472}
473
474int
475mac_check_vnode_deleteacl(struct ucred *cred, struct vnode *vp,
476    acl_type_t type)
477{
478	int error;
479
480	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_deleteacl");
481
482	if (!mac_enforce_fs)
483		return (0);
484
485	MAC_CHECK(check_vnode_deleteacl, cred, vp, vp->v_label, type);
486	return (error);
487}
488
489int
490mac_check_vnode_deleteextattr(struct ucred *cred, struct vnode *vp,
491    int attrnamespace, const char *name)
492{
493	int error;
494
495	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_deleteextattr");
496
497	if (!mac_enforce_fs)
498		return (0);
499
500	MAC_CHECK(check_vnode_deleteextattr, cred, vp, vp->v_label,
501	    attrnamespace, name);
502	return (error);
503}
504
505int
506mac_check_vnode_exec(struct ucred *cred, struct vnode *vp,
507    struct image_params *imgp)
508{
509	int error;
510
511	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_exec");
512
513	if (!mac_enforce_process && !mac_enforce_fs)
514		return (0);
515
516	MAC_CHECK(check_vnode_exec, cred, vp, vp->v_label, imgp,
517	    imgp->execlabel);
518
519	return (error);
520}
521
522int
523mac_check_vnode_getacl(struct ucred *cred, struct vnode *vp, acl_type_t type)
524{
525	int error;
526
527	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_getacl");
528
529	if (!mac_enforce_fs)
530		return (0);
531
532	MAC_CHECK(check_vnode_getacl, cred, vp, vp->v_label, type);
533	return (error);
534}
535
536int
537mac_check_vnode_getextattr(struct ucred *cred, struct vnode *vp,
538    int attrnamespace, const char *name, struct uio *uio)
539{
540	int error;
541
542	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_getextattr");
543
544	if (!mac_enforce_fs)
545		return (0);
546
547	MAC_CHECK(check_vnode_getextattr, cred, vp, vp->v_label,
548	    attrnamespace, name, uio);
549	return (error);
550}
551
552int
553mac_check_vnode_link(struct ucred *cred, struct vnode *dvp,
554    struct vnode *vp, struct componentname *cnp)
555{
556	int error;
557
558	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_link");
559	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_link");
560
561	if (!mac_enforce_fs)
562		return (0);
563
564	MAC_CHECK(check_vnode_link, cred, dvp, dvp->v_label, vp,
565	    vp->v_label, cnp);
566	return (error);
567}
568
569int
570mac_check_vnode_listextattr(struct ucred *cred, struct vnode *vp,
571    int attrnamespace)
572{
573	int error;
574
575	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_listextattr");
576
577	if (!mac_enforce_fs)
578		return (0);
579
580	MAC_CHECK(check_vnode_listextattr, cred, vp, vp->v_label,
581	    attrnamespace);
582	return (error);
583}
584
585int
586mac_check_vnode_lookup(struct ucred *cred, struct vnode *dvp,
587    struct componentname *cnp)
588{
589	int error;
590
591	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_lookup");
592
593	if (!mac_enforce_fs)
594		return (0);
595
596	MAC_CHECK(check_vnode_lookup, cred, dvp, dvp->v_label, cnp);
597	return (error);
598}
599
600int
601mac_check_vnode_mmap(struct ucred *cred, struct vnode *vp, int prot)
602{
603	int error;
604
605	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_mmap");
606
607	if (!mac_enforce_fs || !mac_enforce_vm)
608		return (0);
609
610	MAC_CHECK(check_vnode_mmap, cred, vp, vp->v_label, prot);
611	return (error);
612}
613
614void
615mac_check_vnode_mmap_downgrade(struct ucred *cred, struct vnode *vp, int *prot)
616{
617	int result = *prot;
618
619	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_mmap_downgrade");
620
621	if (!mac_enforce_fs || !mac_enforce_vm)
622		return;
623
624	MAC_PERFORM(check_vnode_mmap_downgrade, cred, vp, vp->v_label,
625	    &result);
626
627	*prot = result;
628}
629
630int
631mac_check_vnode_mprotect(struct ucred *cred, struct vnode *vp, int prot)
632{
633	int error;
634
635	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_mprotect");
636
637	if (!mac_enforce_fs || !mac_enforce_vm)
638		return (0);
639
640	MAC_CHECK(check_vnode_mprotect, cred, vp, vp->v_label, prot);
641	return (error);
642}
643
644int
645mac_check_vnode_open(struct ucred *cred, struct vnode *vp, int acc_mode)
646{
647	int error;
648
649	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_open");
650
651	if (!mac_enforce_fs)
652		return (0);
653
654	MAC_CHECK(check_vnode_open, cred, vp, vp->v_label, acc_mode);
655	return (error);
656}
657
658int
659mac_check_vnode_poll(struct ucred *active_cred, struct ucred *file_cred,
660    struct vnode *vp)
661{
662	int error;
663
664	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_poll");
665
666	if (!mac_enforce_fs)
667		return (0);
668
669	MAC_CHECK(check_vnode_poll, active_cred, file_cred, vp,
670	    vp->v_label);
671
672	return (error);
673}
674
675int
676mac_check_vnode_read(struct ucred *active_cred, struct ucred *file_cred,
677    struct vnode *vp)
678{
679	int error;
680
681	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_read");
682
683	if (!mac_enforce_fs)
684		return (0);
685
686	MAC_CHECK(check_vnode_read, active_cred, file_cred, vp,
687	    vp->v_label);
688
689	return (error);
690}
691
692int
693mac_check_vnode_readdir(struct ucred *cred, struct vnode *dvp)
694{
695	int error;
696
697	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_readdir");
698
699	if (!mac_enforce_fs)
700		return (0);
701
702	MAC_CHECK(check_vnode_readdir, cred, dvp, dvp->v_label);
703	return (error);
704}
705
706int
707mac_check_vnode_readlink(struct ucred *cred, struct vnode *vp)
708{
709	int error;
710
711	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_readlink");
712
713	if (!mac_enforce_fs)
714		return (0);
715
716	MAC_CHECK(check_vnode_readlink, cred, vp, vp->v_label);
717	return (error);
718}
719
720static int
721mac_check_vnode_relabel(struct ucred *cred, struct vnode *vp,
722    struct label *newlabel)
723{
724	int error;
725
726	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_relabel");
727
728	MAC_CHECK(check_vnode_relabel, cred, vp, vp->v_label, newlabel);
729
730	return (error);
731}
732
733int
734mac_check_vnode_rename_from(struct ucred *cred, struct vnode *dvp,
735    struct vnode *vp, struct componentname *cnp)
736{
737	int error;
738
739	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_rename_from");
740	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_rename_from");
741
742	if (!mac_enforce_fs)
743		return (0);
744
745	MAC_CHECK(check_vnode_rename_from, cred, dvp, dvp->v_label, vp,
746	    vp->v_label, cnp);
747	return (error);
748}
749
750int
751mac_check_vnode_rename_to(struct ucred *cred, struct vnode *dvp,
752    struct vnode *vp, int samedir, struct componentname *cnp)
753{
754	int error;
755
756	ASSERT_VOP_LOCKED(dvp, "mac_check_vnode_rename_to");
757	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_rename_to");
758
759	if (!mac_enforce_fs)
760		return (0);
761
762	MAC_CHECK(check_vnode_rename_to, cred, dvp, dvp->v_label, vp,
763	    vp != NULL ? vp->v_label : NULL, samedir, cnp);
764	return (error);
765}
766
767int
768mac_check_vnode_revoke(struct ucred *cred, struct vnode *vp)
769{
770	int error;
771
772	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_revoke");
773
774	if (!mac_enforce_fs)
775		return (0);
776
777	MAC_CHECK(check_vnode_revoke, cred, vp, vp->v_label);
778	return (error);
779}
780
781int
782mac_check_vnode_setacl(struct ucred *cred, struct vnode *vp, acl_type_t type,
783    struct acl *acl)
784{
785	int error;
786
787	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setacl");
788
789	if (!mac_enforce_fs)
790		return (0);
791
792	MAC_CHECK(check_vnode_setacl, cred, vp, vp->v_label, type, acl);
793	return (error);
794}
795
796int
797mac_check_vnode_setextattr(struct ucred *cred, struct vnode *vp,
798    int attrnamespace, const char *name, struct uio *uio)
799{
800	int error;
801
802	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setextattr");
803
804	if (!mac_enforce_fs)
805		return (0);
806
807	MAC_CHECK(check_vnode_setextattr, cred, vp, vp->v_label,
808	    attrnamespace, name, uio);
809	return (error);
810}
811
812int
813mac_check_vnode_setflags(struct ucred *cred, struct vnode *vp, u_long flags)
814{
815	int error;
816
817	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setflags");
818
819	if (!mac_enforce_fs)
820		return (0);
821
822	MAC_CHECK(check_vnode_setflags, cred, vp, vp->v_label, flags);
823	return (error);
824}
825
826int
827mac_check_vnode_setmode(struct ucred *cred, struct vnode *vp, mode_t mode)
828{
829	int error;
830
831	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setmode");
832
833	if (!mac_enforce_fs)
834		return (0);
835
836	MAC_CHECK(check_vnode_setmode, cred, vp, vp->v_label, mode);
837	return (error);
838}
839
840int
841mac_check_vnode_setowner(struct ucred *cred, struct vnode *vp, uid_t uid,
842    gid_t gid)
843{
844	int error;
845
846	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setowner");
847
848	if (!mac_enforce_fs)
849		return (0);
850
851	MAC_CHECK(check_vnode_setowner, cred, vp, vp->v_label, uid, gid);
852	return (error);
853}
854
855int
856mac_check_vnode_setutimes(struct ucred *cred, struct vnode *vp,
857    struct timespec atime, struct timespec mtime)
858{
859	int error;
860
861	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_setutimes");
862
863	if (!mac_enforce_fs)
864		return (0);
865
866	MAC_CHECK(check_vnode_setutimes, cred, vp, vp->v_label, atime,
867	    mtime);
868	return (error);
869}
870
871int
872mac_check_vnode_stat(struct ucred *active_cred, struct ucred *file_cred,
873    struct vnode *vp)
874{
875	int error;
876
877	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_stat");
878
879	if (!mac_enforce_fs)
880		return (0);
881
882	MAC_CHECK(check_vnode_stat, active_cred, file_cred, vp,
883	    vp->v_label);
884	return (error);
885}
886
887int
888mac_check_vnode_write(struct ucred *active_cred, struct ucred *file_cred,
889    struct vnode *vp)
890{
891	int error;
892
893	ASSERT_VOP_LOCKED(vp, "mac_check_vnode_write");
894
895	if (!mac_enforce_fs)
896		return (0);
897
898	MAC_CHECK(check_vnode_write, active_cred, file_cred, vp,
899	    vp->v_label);
900
901	return (error);
902}
903
904void
905mac_relabel_vnode(struct ucred *cred, struct vnode *vp, struct label *newlabel)
906{
907
908	MAC_PERFORM(relabel_vnode, cred, vp, vp->v_label, newlabel);
909}
910
911void
912mac_create_mount(struct ucred *cred, struct mount *mp)
913{
914
915	MAC_PERFORM(create_mount, cred, mp, mp->mnt_mntlabel,
916	    mp->mnt_fslabel);
917}
918
919void
920mac_create_root_mount(struct ucred *cred, struct mount *mp)
921{
922
923	MAC_PERFORM(create_root_mount, cred, mp, mp->mnt_mntlabel,
924	    mp->mnt_fslabel);
925}
926
927int
928mac_check_mount_stat(struct ucred *cred, struct mount *mount)
929{
930	int error;
931
932	if (!mac_enforce_fs)
933		return (0);
934
935	MAC_CHECK(check_mount_stat, cred, mount, mount->mnt_mntlabel);
936
937	return (error);
938}
939
940void
941mac_create_devfs_device(struct mount *mp, dev_t dev, struct devfs_dirent *de)
942{
943
944	MAC_PERFORM(create_devfs_device, mp, dev, de, de->de_label);
945}
946
947void
948mac_create_devfs_symlink(struct ucred *cred, struct mount *mp,
949    struct devfs_dirent *dd, struct devfs_dirent *de)
950{
951
952	MAC_PERFORM(create_devfs_symlink, cred, mp, dd, dd->de_label, de,
953	    de->de_label);
954}
955
956void
957mac_create_devfs_directory(struct mount *mp, char *dirname, int dirnamelen,
958    struct devfs_dirent *de)
959{
960
961	MAC_PERFORM(create_devfs_directory, mp, dirname, dirnamelen, de,
962	    de->de_label);
963}
964
965/*
966 * Implementation of VOP_SETLABEL() that relies on extended attributes
967 * to store label data.  Can be referenced by filesystems supporting
968 * extended attributes.
969 */
970int
971vop_stdsetlabel_ea(struct vop_setlabel_args *ap)
972{
973	struct vnode *vp = ap->a_vp;
974	struct label *intlabel = ap->a_label;
975	int error;
976
977	ASSERT_VOP_LOCKED(vp, "vop_stdsetlabel_ea");
978
979	if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
980		return (EOPNOTSUPP);
981
982	error = mac_setlabel_vnode_extattr(ap->a_cred, vp, intlabel);
983	if (error)
984		return (error);
985
986	mac_relabel_vnode(ap->a_cred, vp, intlabel);
987
988	return (0);
989}
990
991int
992vn_setlabel(struct vnode *vp, struct label *intlabel, struct ucred *cred)
993{
994	int error;
995
996	if (vp->v_mount == NULL) {
997		/* printf("vn_setlabel: null v_mount\n"); */
998		if (vp->v_type != VNON)
999			printf("vn_setlabel: null v_mount with non-VNON\n");
1000		return (EBADF);
1001	}
1002
1003	if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
1004		return (EOPNOTSUPP);
1005
1006	/*
1007	 * Multi-phase commit.  First check the policies to confirm the
1008	 * change is OK.  Then commit via the filesystem.  Finally,
1009	 * update the actual vnode label.  Question: maybe the filesystem
1010	 * should update the vnode at the end as part of VOP_SETLABEL()?
1011	 */
1012	error = mac_check_vnode_relabel(cred, vp, intlabel);
1013	if (error)
1014		return (error);
1015
1016	/*
1017	 * VADMIN provides the opportunity for the filesystem to make
1018	 * decisions about who is and is not able to modify labels
1019	 * and protections on files.  This might not be right.  We can't
1020	 * assume VOP_SETLABEL() will do it, because we might implement
1021	 * that as part of vop_stdsetlabel_ea().
1022	 */
1023	error = VOP_ACCESS(vp, VADMIN, cred, curthread);
1024	if (error)
1025		return (error);
1026
1027	error = VOP_SETLABEL(vp, intlabel, cred, curthread);
1028	if (error)
1029		return (error);
1030
1031	return (0);
1032}
1033