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
89static struct label *
90mac_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
101void
102mac_devfs_label_init(struct devnode *de)
103{
104
105	de->dn_label = mac_devfsdirent_label_alloc();
106}
107
108static struct label *
109mac_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
120void
121mac_mount_label_init(struct mount *mp)
122{
123
124	mp->mnt_mntlabel = mac_mount_label_alloc();
125}
126
127struct label *
128mac_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
139void
140mac_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*/
151void
152mac_vnode_label_recycle(vnode_t vp)
153{
154
155	MAC_PERFORM(vnode_label_recycle, vp->v_label);
156}
157
158static void
159mac_devfs_label_free(struct label *label)
160{
161	MAC_PERFORM(devfs_label_destroy, label);
162	mac_labelzone_free(label);
163}
164
165void
166mac_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
174static void
175mac_mount_label_free(struct label *label)
176{
177
178	MAC_PERFORM(mount_label_destroy, label);
179	mac_labelzone_free(label);
180}
181
182void
183mac_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
193void
194mac_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__
202void
203mac_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
211void
212mac_vnode_label_copy(struct label *src, struct label *dest)
213{
214
215	MAC_PERFORM(vnode_label_copy, src, dest);
216}
217
218int
219mac_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
230int
231mac_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
241int
242mac_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
251int
252mac_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
261int
262mac_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
272void
273mac_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
281void
282mac_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
293int
294mac_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
321void
322mac_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
334int
335mac_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
345void
346mac_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
356int
357mac_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 */
379void
380mac_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
399static int
400mac_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
416int
417mac_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	int disjoint = 0;
422
423	if (!mac_proc_enforce && !mac_vnode_enforce)
424		return disjoint;
425
426	/* mark the new cred to indicate "matching" includes the label */
427	new->cr_flags |= CRF_MAC_ENFORCE;
428
429	cred = vfs_context_ucred(ctx);
430	MAC_PERFORM(cred_label_update_execve, cred, new, vp, vp->v_label,
431	    scriptvnodelabel, execl, &disjoint);
432
433	return (disjoint);
434}
435
436int
437mac_cred_check_label_update_execve(vfs_context_t ctx, struct vnode *vp,
438    struct label *scriptvnodelabel, struct label *execlabel, struct proc *p)
439{
440	kauth_cred_t cred;
441	int result = 0;
442
443	if (!mac_proc_enforce && !mac_vnode_enforce)
444		return result;
445
446	cred = vfs_context_ucred(ctx);
447	MAC_BOOLEAN(cred_check_label_update_execve, ||, cred, vp, vp->v_label,
448		    scriptvnodelabel, execlabel, p);
449
450	return (result);
451}
452
453int
454mac_vnode_check_access(vfs_context_t ctx, struct vnode *vp,
455    int acc_mode)
456{
457	kauth_cred_t cred;
458	int error;
459	int mask;
460
461	if (!mac_vnode_enforce ||
462	    !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
463		return 0;
464
465	cred = vfs_context_ucred(ctx);
466	/* Convert {R,W,X}_OK values to V{READ,WRITE,EXEC} for entry points */
467	mask = ACCESS_MODE_TO_VNODE_MASK(acc_mode);
468	MAC_CHECK(vnode_check_access, cred, vp, vp->v_label, mask);
469	return (error);
470 }
471
472int
473mac_vnode_check_chdir(vfs_context_t ctx, struct vnode *dvp)
474{
475	kauth_cred_t cred;
476	int error;
477
478	if (!mac_vnode_enforce ||
479	    !mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
480		return (0);
481
482	cred = vfs_context_ucred(ctx);
483	MAC_CHECK(vnode_check_chdir, cred, dvp, dvp->v_label);
484	return (error);
485}
486
487int
488mac_vnode_check_chroot(vfs_context_t ctx, struct vnode *dvp,
489    struct componentname *cnp)
490{
491	kauth_cred_t cred;
492	int error;
493
494	if (!mac_vnode_enforce ||
495		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
496		return (0);
497
498	cred = vfs_context_ucred(ctx);
499	MAC_CHECK(vnode_check_chroot, cred, dvp, dvp->v_label, cnp);
500	return (error);
501}
502
503int
504mac_vnode_check_create(vfs_context_t ctx, struct vnode *dvp,
505    struct componentname *cnp, struct vnode_attr *vap)
506{
507	kauth_cred_t cred;
508	int error;
509
510	if (!mac_vnode_enforce ||
511		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
512		return (0);
513
514	cred = vfs_context_ucred(ctx);
515	MAC_CHECK(vnode_check_create, cred, dvp, dvp->v_label, cnp, vap);
516	return (error);
517}
518
519int
520mac_vnode_check_unlink(vfs_context_t ctx, struct vnode *dvp, struct vnode *vp,
521    struct componentname *cnp)
522{
523	kauth_cred_t cred;
524	int error;
525
526	if (!mac_vnode_enforce ||
527		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
528		return (0);
529
530	cred = vfs_context_ucred(ctx);
531	MAC_CHECK(vnode_check_unlink, cred, dvp, dvp->v_label, vp,
532	    vp->v_label, cnp);
533	return (error);
534}
535#if 0
536int
537mac_vnode_check_deleteacl(vfs_context_t ctx, struct vnode *vp,
538    acl_type_t type)
539{
540	kauth_cred_t cred;
541	int error;
542
543	if (!mac_vnode_enforce ||
544		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
545		return (0);
546
547	cred = vfs_context_ucred(ctx);
548	MAC_CHECK(vnode_check_deleteacl, cred, vp, vp->v_label, type);
549	return (error);
550}
551#endif
552
553int
554mac_vnode_check_deleteextattr(vfs_context_t ctx, struct vnode *vp,
555    const char *name)
556{
557	kauth_cred_t cred;
558	int error;
559
560	if (!mac_vnode_enforce ||
561		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
562		return (0);
563
564	cred = vfs_context_ucred(ctx);
565	MAC_CHECK(vnode_check_deleteextattr, cred, vp, vp->v_label, name);
566	return (error);
567}
568int
569mac_vnode_check_exchangedata(vfs_context_t ctx,
570    struct vnode *v1, struct vnode *v2)
571{
572	kauth_cred_t cred;
573	int error;
574
575	if (!mac_vnode_enforce ||
576		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
577		return (0);
578
579	cred = vfs_context_ucred(ctx);
580	MAC_CHECK(vnode_check_exchangedata, cred, v1, v1->v_label,
581	    v2, v2->v_label);
582
583	return (error);
584}
585
586#if 0
587int
588mac_vnode_check_getacl(vfs_context_t ctx, struct vnode *vp, acl_type_t type)
589{
590	kauth_cred_t cred;
591	int error;
592
593	if (!mac_vnode_enforce ||
594		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
595		return (0);
596
597	cred = vfs_context_ucred(ctx);
598	MAC_CHECK(vnode_check_getacl, cred, vp, vp->v_label, type);
599	return (error);
600}
601#endif
602
603int
604mac_vnode_check_getattrlist(vfs_context_t ctx, struct vnode *vp,
605    struct attrlist *alist)
606{
607	kauth_cred_t cred;
608	int error;
609
610	if (!mac_vnode_enforce ||
611		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
612		return (0);
613
614	cred = vfs_context_ucred(ctx);
615	MAC_CHECK(vnode_check_getattrlist, cred, vp, vp->v_label, alist);
616
617	/* Falsify results instead of returning error? */
618	return (error);
619}
620
621int
622mac_vnode_check_exec(vfs_context_t ctx, struct vnode *vp,
623    struct image_params *imgp)
624{
625	kauth_cred_t cred;
626	int error;
627
628	if (!mac_vnode_enforce || !mac_proc_enforce)
629		return (0);
630
631	cred = vfs_context_ucred(ctx);
632	MAC_CHECK(vnode_check_exec, cred, vp, vp->v_label,
633		  (imgp != NULL) ? imgp->ip_execlabelp : NULL,
634		  (imgp != NULL) ? &imgp->ip_ndp->ni_cnd : NULL,
635		  (imgp != NULL) ? &imgp->ip_csflags : NULL);
636	return (error);
637}
638
639int
640mac_vnode_check_signature(struct vnode *vp, unsigned char *sha1,
641			  void * signature, size_t size)
642{
643	int error;
644
645	if (!mac_vnode_enforce || !mac_proc_enforce)
646		return (0);
647
648	MAC_CHECK(vnode_check_signature, vp, vp->v_label, sha1, signature, size);
649	return (error);
650}
651
652#if 0
653int
654mac_vnode_check_getacl(vfs_context_t ctx, struct vnode *vp, acl_type_t type)
655{
656	kauth_cred_t cred;
657	int error;
658
659	if (!mac_vnode_enforce ||
660		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
661		return (0);
662
663	cred = vfs_context_ucred(ctx);
664	MAC_CHECK(vnode_check_getacl, cred, vp, vp->v_label, type);
665	return (error);
666}
667#endif
668
669int
670mac_vnode_check_getextattr(vfs_context_t ctx, struct vnode *vp,
671    const char *name, struct uio *uio)
672{
673	kauth_cred_t cred;
674	int error;
675
676	if (!mac_vnode_enforce ||
677		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
678		return (0);
679
680	cred = vfs_context_ucred(ctx);
681	MAC_CHECK(vnode_check_getextattr, cred, vp, vp->v_label,
682	    name, uio);
683	return (error);
684}
685
686int
687mac_vnode_check_ioctl(vfs_context_t ctx, struct vnode *vp, u_int cmd)
688{
689	kauth_cred_t cred;
690	int error;
691
692	if (!mac_vnode_enforce ||
693		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
694		return (0);
695
696	cred = vfs_context_ucred(ctx);
697	MAC_CHECK(vnode_check_ioctl, cred, vp, vp->v_label, cmd);
698	return (error);
699}
700
701int
702mac_vnode_check_kqfilter(vfs_context_t ctx, kauth_cred_t file_cred,
703    struct knote *kn, struct vnode *vp)
704{
705	kauth_cred_t cred;
706	int error;
707
708	if (!mac_vnode_enforce ||
709		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
710		return (0);
711
712	cred = vfs_context_ucred(ctx);
713	MAC_CHECK(vnode_check_kqfilter, cred, file_cred, kn, vp,
714	    vp->v_label);
715
716	return (error);
717}
718
719int
720mac_vnode_check_link(vfs_context_t ctx, struct vnode *dvp,
721    struct vnode *vp, struct componentname *cnp)
722{
723	kauth_cred_t cred;
724	int error;
725
726	if (!mac_vnode_enforce ||
727		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
728		return (0);
729
730	cred = vfs_context_ucred(ctx);
731	MAC_CHECK(vnode_check_link, cred, dvp, dvp->v_label, vp,
732	    vp->v_label, cnp);
733	return (error);
734}
735
736int
737mac_vnode_check_listextattr(vfs_context_t ctx, struct vnode *vp)
738{
739	kauth_cred_t cred;
740	int error;
741
742	if (!mac_vnode_enforce ||
743		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
744		return (0);
745
746	cred = vfs_context_ucred(ctx);
747	MAC_CHECK(vnode_check_listextattr, cred, vp, vp->v_label);
748	return (error);
749}
750
751int
752mac_vnode_check_lookup(vfs_context_t ctx, struct vnode *dvp,
753    struct componentname *cnp)
754{
755	kauth_cred_t cred;
756	int error;
757
758	if (!mac_vnode_enforce ||
759		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
760		return (0);
761
762	cred = vfs_context_ucred(ctx);
763	MAC_CHECK(vnode_check_lookup, cred, dvp, dvp->v_label, cnp);
764	return (error);
765}
766
767int
768mac_vnode_check_open(vfs_context_t ctx, struct vnode *vp, int acc_mode)
769{
770	kauth_cred_t cred;
771	int error;
772
773	if (!mac_vnode_enforce ||
774		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
775		return (0);
776
777	cred = vfs_context_ucred(ctx);
778	MAC_CHECK(vnode_check_open, cred, vp, vp->v_label, acc_mode);
779	return (error);
780}
781
782int
783mac_vnode_check_read(vfs_context_t ctx, struct ucred *file_cred,
784    struct vnode *vp)
785{
786	kauth_cred_t cred;
787	int error;
788
789	if (!mac_vnode_enforce ||
790		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
791		return (0);
792
793	cred = vfs_context_ucred(ctx);
794	MAC_CHECK(vnode_check_read, cred, file_cred, vp,
795	    vp->v_label);
796
797	return (error);
798}
799
800int
801mac_vnode_check_readdir(vfs_context_t ctx, struct vnode *dvp)
802{
803	kauth_cred_t cred;
804	int error;
805
806	if (!mac_vnode_enforce ||
807		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
808		return (0);
809
810	cred = vfs_context_ucred(ctx);
811	MAC_CHECK(vnode_check_readdir, cred, dvp, dvp->v_label);
812	return (error);
813}
814
815int
816mac_vnode_check_readlink(vfs_context_t ctx, struct vnode *vp)
817{
818	kauth_cred_t cred;
819	int error;
820
821	if (!mac_vnode_enforce ||
822		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
823		return (0);
824
825	cred = vfs_context_ucred(ctx);
826	MAC_CHECK(vnode_check_readlink, cred, vp, vp->v_label);
827	return (error);
828}
829
830int
831mac_vnode_check_label_update(vfs_context_t ctx, struct vnode *vp,
832    struct label *newlabel)
833{
834	kauth_cred_t cred;
835	int error;
836
837	if (!mac_vnode_enforce ||
838		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
839		return (0);
840
841	cred = vfs_context_ucred(ctx);
842	MAC_CHECK(vnode_check_label_update, cred, vp, vp->v_label, newlabel);
843
844	return (error);
845}
846
847int
848mac_vnode_check_rename_from(vfs_context_t ctx, struct vnode *dvp,
849    struct vnode *vp, struct componentname *cnp)
850{
851	kauth_cred_t cred;
852	int error;
853
854	if (!mac_vnode_enforce ||
855		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
856		return (0);
857
858	cred = vfs_context_ucred(ctx);
859	MAC_CHECK(vnode_check_rename_from, cred, dvp, dvp->v_label, vp,
860	    vp->v_label, cnp);
861	return (error);
862}
863
864int
865mac_vnode_check_rename_to(vfs_context_t ctx, struct vnode *dvp,
866    struct vnode *vp, int samedir, struct componentname *cnp)
867{
868	kauth_cred_t cred;
869	int error;
870
871	if (!mac_vnode_enforce ||
872		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
873		return (0);
874
875	cred = vfs_context_ucred(ctx);
876	MAC_CHECK(vnode_check_rename_to, cred, dvp, dvp->v_label, vp,
877	    vp != NULL ? vp->v_label : NULL, samedir, cnp);
878	return (error);
879}
880
881int
882mac_vnode_check_revoke(vfs_context_t ctx, struct vnode *vp)
883{
884	kauth_cred_t cred;
885	int error;
886
887	if (!mac_vnode_enforce ||
888		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
889		return (0);
890
891	cred = vfs_context_ucred(ctx);
892	MAC_CHECK(vnode_check_revoke, cred, vp, vp->v_label);
893	return (error);
894}
895
896int
897mac_vnode_check_select(vfs_context_t ctx, struct vnode *vp, int which)
898{
899	kauth_cred_t cred;
900	int error;
901
902	if (!mac_vnode_enforce ||
903		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
904		return (0);
905
906	cred = vfs_context_ucred(ctx);
907	MAC_CHECK(vnode_check_select, cred, vp, vp->v_label, which);
908	return (error);
909}
910
911#if 0
912int
913mac_vnode_check_setacl(vfs_context_t ctx, struct vnode *vp, acl_type_t type,
914    struct acl *acl)
915{
916	kauth_cred_t cred;
917	int error;
918
919	if (!mac_vnode_enforce ||
920		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
921		return (0);
922
923	cred = vfs_context_ucred(ctx);
924	MAC_CHECK(vnode_check_setacl, cred, vp, vp->v_label, type, acl);
925	return (error);
926}
927#endif
928
929int
930mac_vnode_check_setattrlist(vfs_context_t ctx, struct vnode *vp,
931    struct attrlist *alist)
932{
933	kauth_cred_t cred;
934	int error;
935
936	if (!mac_vnode_enforce ||
937		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
938		return (0);
939
940	cred = vfs_context_ucred(ctx);
941	MAC_CHECK(vnode_check_setattrlist, cred, vp, vp->v_label, alist);
942	return (error);
943}
944
945int
946mac_vnode_check_setextattr(vfs_context_t ctx, struct vnode *vp,
947    const char *name, struct uio *uio)
948{
949	kauth_cred_t cred;
950	int error;
951
952	if (!mac_vnode_enforce ||
953		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
954		return (0);
955
956	cred = vfs_context_ucred(ctx);
957	MAC_CHECK(vnode_check_setextattr, cred, vp, vp->v_label,
958	    name, uio);
959	return (error);
960}
961
962int
963mac_vnode_check_setflags(vfs_context_t ctx, struct vnode *vp, u_long flags)
964{
965	kauth_cred_t cred;
966	int error;
967
968	if (!mac_vnode_enforce ||
969		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
970		return (0);
971
972	cred = vfs_context_ucred(ctx);
973	MAC_CHECK(vnode_check_setflags, cred, vp, vp->v_label, flags);
974	return (error);
975}
976
977int
978mac_vnode_check_setmode(vfs_context_t ctx, struct vnode *vp, mode_t mode)
979{
980	kauth_cred_t cred;
981	int error;
982
983	if (!mac_vnode_enforce ||
984		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
985		return (0);
986
987	cred = vfs_context_ucred(ctx);
988	MAC_CHECK(vnode_check_setmode, cred, vp, vp->v_label, mode);
989	return (error);
990}
991
992int
993mac_vnode_check_setowner(vfs_context_t ctx, struct vnode *vp, uid_t uid,
994    gid_t gid)
995{
996	kauth_cred_t cred;
997	int error;
998
999	if (!mac_vnode_enforce ||
1000		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1001		return (0);
1002
1003	cred = vfs_context_ucred(ctx);
1004	MAC_CHECK(vnode_check_setowner, cred, vp, vp->v_label, uid, gid);
1005	return (error);
1006}
1007
1008int
1009mac_vnode_check_setutimes(vfs_context_t ctx, struct vnode *vp,
1010    struct timespec atime, struct timespec mtime)
1011{
1012	kauth_cred_t cred;
1013	int error;
1014
1015	if (!mac_vnode_enforce ||
1016		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1017		return (0);
1018
1019	cred = vfs_context_ucred(ctx);
1020	MAC_CHECK(vnode_check_setutimes, cred, vp, vp->v_label, atime,
1021	    mtime);
1022	return (error);
1023}
1024
1025int
1026mac_vnode_check_stat(vfs_context_t ctx, struct ucred *file_cred,
1027    struct vnode *vp)
1028{
1029	kauth_cred_t cred;
1030	int error;
1031
1032	if (!mac_vnode_enforce ||
1033		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1034		return (0);
1035
1036	cred = vfs_context_ucred(ctx);
1037	MAC_CHECK(vnode_check_stat, cred, file_cred, vp,
1038	    vp->v_label);
1039	return (error);
1040}
1041
1042int
1043mac_vnode_check_truncate(vfs_context_t ctx, struct ucred *file_cred,
1044    struct vnode *vp)
1045{
1046	kauth_cred_t cred;
1047	int error;
1048
1049	if (!mac_vnode_enforce ||
1050		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1051		return (0);
1052
1053	cred = vfs_context_ucred(ctx);
1054	MAC_CHECK(vnode_check_truncate, cred, file_cred, vp,
1055	    vp->v_label);
1056
1057	return (error);
1058}
1059
1060int
1061mac_vnode_check_write(vfs_context_t ctx, struct ucred *file_cred,
1062    struct vnode *vp)
1063{
1064	kauth_cred_t cred;
1065	int error;
1066
1067	if (!mac_vnode_enforce ||
1068		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1069		return (0);
1070
1071	cred = vfs_context_ucred(ctx);
1072	MAC_CHECK(vnode_check_write, cred, file_cred, vp, vp->v_label);
1073
1074	return (error);
1075}
1076
1077void
1078mac_vnode_label_update(vfs_context_t ctx, struct vnode *vp, struct label *newlabel)
1079{
1080	kauth_cred_t cred = vfs_context_ucred(ctx);
1081
1082	vnode_lock(vp);
1083	MAC_PERFORM(vnode_label_update, cred, vp, vp->v_label, newlabel);
1084	vnode_unlock(vp);
1085}
1086
1087void
1088mac_mount_label_associate(vfs_context_t ctx, struct mount *mp)
1089{
1090	kauth_cred_t cred = vfs_context_ucred(ctx);
1091
1092	/* XXX: eventually this logic may be handled by the policy? */
1093
1094	/* We desire MULTILABEL for the root filesystem. */
1095	if ((mp->mnt_flag & MNT_ROOTFS) &&
1096	    (strcmp(mp->mnt_vfsstat.f_fstypename, "hfs") == 0))
1097		mp->mnt_flag |= MNT_MULTILABEL;
1098
1099	/* MULTILABEL on DEVFS. */
1100	if (strcmp(mp->mnt_vfsstat.f_fstypename, "devfs") == 0)
1101		mp->mnt_flag |= MNT_MULTILABEL;
1102
1103	/* MULTILABEL on FDESC pseudo-filesystem. */
1104	if (strcmp(mp->mnt_vfsstat.f_fstypename, "fdesc") == 0)
1105		mp->mnt_flag |= MNT_MULTILABEL;
1106
1107	/* MULTILABEL on all NFS filesystems. */
1108	if (strcmp(mp->mnt_vfsstat.f_fstypename, "nfs") == 0)
1109		mp->mnt_flag |= MNT_MULTILABEL;
1110
1111	/* MULTILABEL on all AFP filesystems. */
1112	if (strcmp(mp->mnt_vfsstat.f_fstypename, "afpfs") == 0)
1113		mp->mnt_flag |= MNT_MULTILABEL;
1114
1115	if (mp->mnt_vtable != NULL) {
1116		/* Any filesystem that supports native XATTRs. */
1117		if ((mp->mnt_vtable->vfc_vfsflags & VFC_VFSNATIVEXATTR))
1118			mp->mnt_flag |= MNT_MULTILABEL;
1119
1120		/* Filesystem does not support multilabel. */
1121		if ((mp->mnt_vtable->vfc_vfsflags & VFC_VFSNOMACLABEL) &&
1122		    (mp->mnt_flag & MNT_MULTILABEL))
1123			mp->mnt_flag &= ~MNT_MULTILABEL;
1124	}
1125
1126	MAC_PERFORM(mount_label_associate, cred, mp, mp->mnt_mntlabel);
1127#if MAC_DEBUG
1128	printf("MAC Framework enabling %s support: %s -> %s (%s)\n",
1129		mp->mnt_flag & MNT_MULTILABEL ? "multilabel" : "singlelabel",
1130		mp->mnt_vfsstat.f_mntfromname,
1131		mp->mnt_vfsstat.f_mntonname,
1132		mp->mnt_vfsstat.f_fstypename);
1133#endif
1134}
1135
1136int
1137mac_mount_check_mount(vfs_context_t ctx, struct vnode *vp,
1138    struct componentname *cnp, const char *vfc_name)
1139{
1140	kauth_cred_t cred;
1141	int error;
1142
1143	if (!mac_vnode_enforce ||
1144		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1145		return (0);
1146
1147	cred = vfs_context_ucred(ctx);
1148	MAC_CHECK(mount_check_mount, cred, vp, vp->v_label, cnp, vfc_name);
1149
1150	return (error);
1151}
1152
1153int
1154mac_mount_check_remount(vfs_context_t ctx, struct mount *mp)
1155{
1156	kauth_cred_t cred;
1157	int error;
1158
1159	if (!mac_vnode_enforce ||
1160		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1161		return (0);
1162
1163	cred = vfs_context_ucred(ctx);
1164	MAC_CHECK(mount_check_remount, cred, mp, mp->mnt_mntlabel);
1165
1166	return (error);
1167}
1168
1169int
1170mac_mount_check_umount(vfs_context_t ctx, struct mount *mp)
1171{
1172	kauth_cred_t cred;
1173	int error;
1174
1175	if (!mac_vnode_enforce ||
1176		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1177		return (0);
1178
1179	cred = vfs_context_ucred(ctx);
1180	MAC_CHECK(mount_check_umount, cred, mp, mp->mnt_mntlabel);
1181
1182	return (error);
1183}
1184
1185int
1186mac_mount_check_getattr(vfs_context_t ctx, struct mount *mp,
1187    struct vfs_attr *vfa)
1188{
1189	kauth_cred_t cred;
1190	int error;
1191
1192	if (!mac_vnode_enforce ||
1193		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1194		return (0);
1195
1196	cred = vfs_context_ucred(ctx);
1197	MAC_CHECK(mount_check_getattr, cred, mp, mp->mnt_mntlabel, vfa);
1198	return (error);
1199}
1200
1201int
1202mac_mount_check_setattr(vfs_context_t ctx, struct mount *mp,
1203    struct vfs_attr *vfa)
1204{
1205	kauth_cred_t cred;
1206	int error;
1207
1208	if (!mac_vnode_enforce ||
1209		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1210		return (0);
1211
1212	cred = vfs_context_ucred(ctx);
1213	MAC_CHECK(mount_check_setattr, cred, mp, mp->mnt_mntlabel, vfa);
1214	return (error);
1215}
1216
1217int
1218mac_mount_check_stat(vfs_context_t ctx, struct mount *mount)
1219{
1220	kauth_cred_t cred;
1221	int error;
1222
1223	if (!mac_vnode_enforce ||
1224		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1225		return (0);
1226
1227	cred = vfs_context_ucred(ctx);
1228	MAC_CHECK(mount_check_stat, cred, mount, mount->mnt_mntlabel);
1229
1230	return (error);
1231}
1232
1233int
1234mac_mount_check_label_update(vfs_context_t ctx, struct mount *mount)
1235{
1236	kauth_cred_t cred;
1237	int error;
1238
1239	if (!mac_vnode_enforce ||
1240		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1241		return (0);
1242
1243	cred = vfs_context_ucred(ctx);
1244	MAC_CHECK(mount_check_label_update, cred, mount, mount->mnt_mntlabel);
1245
1246	return (error);
1247}
1248
1249int
1250mac_mount_check_fsctl(vfs_context_t ctx, struct mount *mp, u_int cmd)
1251{
1252	kauth_cred_t cred;
1253	int error;
1254
1255	if (!mac_vnode_enforce ||
1256		!mac_context_check_enforce(ctx, MAC_VNODE_ENFORCE))
1257		return (0);
1258
1259	cred = vfs_context_ucred(ctx);
1260	MAC_CHECK(mount_check_fsctl, cred, mp, mp->mnt_mntlabel, cmd);
1261
1262	return (error);
1263}
1264
1265void
1266mac_devfs_label_associate_device(dev_t dev, struct devnode *de,
1267    const char *fullpath)
1268{
1269	if (!mac_device_enforce)
1270		return;
1271
1272	MAC_PERFORM(devfs_label_associate_device, dev, de, de->dn_label,
1273	    fullpath);
1274}
1275
1276void
1277mac_devfs_label_associate_directory(const char *dirname, int dirnamelen,
1278    struct devnode *de, const char *fullpath)
1279{
1280	if (!mac_device_enforce)
1281		return;
1282
1283	MAC_PERFORM(devfs_label_associate_directory, dirname, dirnamelen, de,
1284	    de->dn_label, fullpath);
1285}
1286
1287int
1288vn_setlabel(struct vnode *vp, struct label *intlabel, vfs_context_t context)
1289{
1290	int error;
1291
1292	if (!mac_vnode_enforce)
1293		return (0);
1294
1295	if (vp->v_mount == NULL) {
1296		printf("vn_setlabel: null v_mount\n");
1297		if (vp->v_type != VNON)
1298			printf("vn_setlabel: null v_mount with non-VNON\n");
1299		return (EBADF);
1300	}
1301
1302	if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
1303		return (ENOTSUP);
1304
1305	/*
1306	 * Multi-phase commit.  First check the policies to confirm the
1307	 * change is OK.  Then commit via the filesystem.  Finally,
1308	 * update the actual vnode label.  Question: maybe the filesystem
1309	 * should update the vnode at the end as part of VNOP_SETLABEL()?
1310	 */
1311	error = mac_vnode_check_label_update(context, vp, intlabel);
1312	if (error)
1313		return (error);
1314
1315	error = VNOP_SETLABEL(vp, intlabel, context);
1316	if (error == ENOTSUP) {
1317		error = mac_vnode_label_store(context, vp,
1318						   intlabel);
1319		if (error) {
1320			printf("%s: mac_vnode_label_store failed %d\n",
1321				__func__, error);
1322			return (error);
1323		}
1324		mac_vnode_label_update(context, vp, intlabel);
1325	} else
1326	if (error) {
1327		printf("vn_setlabel: vop setlabel failed %d\n", error);
1328		return (error);
1329	}
1330
1331	return (0);
1332}
1333
1334int
1335mac_vnode_label_associate_fdesc(struct mount *mp, struct fdescnode *fnp,
1336    struct vnode *vp, vfs_context_t ctx)
1337{
1338	struct fileproc *fp;
1339	struct socket *so;
1340	struct pipe *cpipe;
1341	struct vnode *fvp;
1342	struct proc *p;
1343	int error;
1344
1345	error = 0;
1346
1347	/*
1348	 * If no backing file, let the policy choose which label to use.
1349	 */
1350	if (fnp->fd_fd == -1) {
1351		MAC_PERFORM(vnode_label_associate_file, vfs_context_ucred(ctx),
1352		    mp, mp->mnt_mntlabel, NULL, NULL, vp, vp->v_label);
1353		return (0);
1354	}
1355
1356	p = vfs_context_proc(ctx);
1357	error = fp_lookup(p, fnp->fd_fd, &fp, 0);
1358	if (error)
1359		return (error);
1360
1361	if (fp->f_fglob == NULL) {
1362		error = EBADF;
1363		goto out;
1364	}
1365
1366	switch (fp->f_fglob->fg_type) {
1367	case DTYPE_VNODE:
1368		fvp = (struct vnode *)fp->f_fglob->fg_data;
1369		if ((error = vnode_getwithref(fvp)))
1370			goto out;
1371		MAC_PERFORM(vnode_label_copy, fvp->v_label, vp->v_label);
1372		(void)vnode_put(fvp);
1373		break;
1374	case DTYPE_SOCKET:
1375		so = (struct socket *)fp->f_fglob->fg_data;
1376		socket_lock(so, 1);
1377		MAC_PERFORM(vnode_label_associate_socket,
1378			    vfs_context_ucred(ctx), (socket_t)so, so->so_label,
1379		    vp, vp->v_label);
1380		socket_unlock(so, 1);
1381		break;
1382	case DTYPE_PSXSHM:
1383		pshm_label_associate(fp, vp, ctx);
1384		break;
1385	case DTYPE_PSXSEM:
1386		psem_label_associate(fp, vp, ctx);
1387		break;
1388	case DTYPE_PIPE:
1389		cpipe = (struct pipe *)fp->f_fglob->fg_data;
1390		/* kern/sys_pipe.c:pipe_select() suggests this test. */
1391		if (cpipe == (struct pipe *)-1) {
1392			error = EINVAL;
1393			goto out;
1394		}
1395		PIPE_LOCK(cpipe);
1396		MAC_PERFORM(vnode_label_associate_pipe, vfs_context_ucred(ctx),
1397		    cpipe, cpipe->pipe_label, vp, vp->v_label);
1398		PIPE_UNLOCK(cpipe);
1399		break;
1400	case DTYPE_KQUEUE:
1401	case DTYPE_FSEVENTS:
1402	default:
1403		MAC_PERFORM(vnode_label_associate_file, vfs_context_ucred(ctx),
1404		    mp, mp->mnt_mntlabel, fp->f_fglob, fp->f_fglob->fg_label,
1405		    vp, vp->v_label);
1406		break;
1407	}
1408out:
1409	fp_drop(p, fnp->fd_fd, fp, 0);
1410	return (error);
1411}
1412