1/*
2 * $FreeBSD$
3 *
4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30
31#include "opt_capsicum.h"
32#include "opt_mac.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/capsicum.h>
37#include <sys/eventhandler.h>
38#include <sys/fcntl.h>
39#include <sys/file.h>
40#include <sys/filedesc.h>
41#include <sys/imgact.h>
42#include <sys/jail.h>
43#include <sys/kernel.h>
44#include <sys/mac.h>
45#include <sys/mount.h>
46#include <sys/namei.h>
47#include <sys/priv.h>
48#include <sys/proc.h>
49#include <sys/sbuf.h>
50#include <sys/stat.h>
51#include <sys/sysctl.h>
52#include <sys/vnode.h>
53#include <fs/nullfs/null.h>
54#include <security/mac/mac_policy.h>
55
56#include "mac_veriexec.h"
57#include "mac_veriexec_internal.h"
58
59#define	SLOT(l) \
60	mac_label_get((l), mac_veriexec_slot)
61#define	SLOT_SET(l, v) \
62	mac_label_set((l), mac_veriexec_slot, (v))
63
64#ifdef MAC_DEBUG
65#define	MAC_VERIEXEC_DBG(_lvl, _fmt, ...)				\
66	do {								\
67		VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt	\
68		     "\n", ##__VA_ARGS__));				\
69	} while(0)
70#else
71#define	MAC_VERIEXEC_DBG(_lvl, _fmt, ...)
72#endif
73
74static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
75static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
76
77SYSCTL_DECL(_security_mac);
78
79SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW, 0,
80    "MAC/veriexec policy controls");
81
82int	mac_veriexec_debug;
83SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
84    &mac_veriexec_debug, 0, "Debug level");
85
86static int	mac_veriexec_state;
87SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state,
88    CTLTYPE_STRING | CTLFLAG_RD, 0, 0, sysctl_mac_veriexec_state, "A",
89    "Verified execution subsystem state");
90
91SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db,
92    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP, 0, 0, sysctl_mac_veriexec_db,
93    "A", "Verified execution fingerprint database");
94
95static int mac_veriexec_slot;
96
97MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
98
99/**
100 * @internal
101 * @brief Handler for security.mac.veriexec.db sysctl
102 *
103 * Display a human-readable form of the current fingerprint database.
104 */
105static int
106sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
107{
108	struct sbuf sb;
109	int error;
110
111	error = sysctl_wire_old_buffer(req, 0);
112	if (error != 0)
113		return (error);
114
115	sbuf_new_for_sysctl(&sb, NULL, 1024, req);
116	mac_veriexec_metadata_print_db(&sb);
117	error = sbuf_finish(&sb);
118	sbuf_delete(&sb);
119
120	return (error);
121}
122
123/**
124 * @internal
125 * @brief Generate human-readable output about the current verified execution
126 *        state.
127 *
128 * @param sbp		sbuf to write output to
129 */
130static void
131mac_veriexec_print_state(struct sbuf *sbp)
132{
133
134	if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE)
135		sbuf_printf(sbp, "inactive ");
136	if (mac_veriexec_state & VERIEXEC_STATE_LOADED)
137		sbuf_printf(sbp, "loaded ");
138	if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE)
139		sbuf_printf(sbp, "active ");
140	if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE)
141		sbuf_printf(sbp, "enforce ");
142	if (mac_veriexec_state & VERIEXEC_STATE_LOCKED)
143		sbuf_printf(sbp, "locked ");
144	if (mac_veriexec_state != 0)
145		sbuf_trim(sbp);
146}
147
148/**
149 * @internal
150 * @brief Handler for security.mac.veriexec.state sysctl
151 *
152 * Display a human-readable form of the current verified execution subsystem
153 * state.
154 */
155static int
156sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
157{
158	struct sbuf sb;
159	int error;
160
161	sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
162	mac_veriexec_print_state(&sb);
163	sbuf_finish(&sb);
164
165	error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
166	sbuf_delete(&sb);
167	return (error);
168}
169
170/**
171 * @internal
172 * @brief Event handler called when a virtual file system is mounted.
173 *
174 * We need to record the file system identifier in the MAC per-policy slot
175 * assigned to veriexec, so we have a key to use in order to reference the
176 * mount point in the meta-data store.
177 *
178 * @param arg		unused argument
179 * @param mp		mount point that is being mounted
180 * @param fsrootvp	vnode of the file system root
181 * @param td		calling thread
182 */
183static void
184mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
185    struct vnode *fsrootvp, struct thread *td)
186{
187	struct vattr va;
188	int error;
189
190	error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
191	if (error)
192		return;
193
194	SLOT_SET(mp->mnt_label, va.va_fsid);
195#ifdef MAC_DEBUG
196	MAC_VERIEXEC_DBG(3, "set fsid to %u for mount %p", va.va_fsid, mp);
197#endif
198}
199
200/**
201 * @internal
202 * @brief Event handler called when a virtual file system is unmounted.
203 *
204 * If we recorded a file system identifier in the MAC per-policy slot assigned
205 * to veriexec, then we need to tell the meta-data store to clean up.
206 *
207 * @param arg		unused argument
208 * @param mp		mount point that is being unmounted
209 * @param td		calling thread
210 */
211static void
212mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
213    struct thread *td)
214{
215	dev_t fsid;
216
217	fsid = SLOT(mp->mnt_label);
218	if (fsid) {
219		MAC_VERIEXEC_DBG(3, "fsid %u, cleaning up mount", fsid);
220		mac_veriexec_metadata_unmounted(fsid, td);
221	}
222}
223
224/**
225 * @internal
226 * @brief The mount point is being initialized, set the value in the MAC
227 *     per-policy slot for veriexec to zero.
228 *
229 * @note A value of zero in this slot indicates no file system identifier
230 *     is assigned.
231 *
232 * @param label the label that is being initialized
233 */
234static void
235mac_veriexec_mount_init_label(struct label *label)
236{
237
238	SLOT_SET(label, 0);
239}
240
241/**
242 * @internal
243 * @brief The mount-point is being destroyed, reset the value in the MAC
244 *     per-policy slot for veriexec back to zero.
245 *
246 * @note A value of zero in this slot indicates no file system identifier
247 *     is assigned.
248 *
249 * @param label the label that is being destroyed
250 */
251static void
252mac_veriexec_mount_destroy_label(struct label *label)
253{
254
255	SLOT_SET(label, 0);
256}
257
258/**
259 * @internal
260 * @brief The vnode label is being initialized, set the value in the MAC
261 *     per-policy slot for veriexec to @c FINGERPRINT_INVALID
262 *
263 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
264 *
265 * @param label		the label that is being initialized
266 */
267static void
268mac_veriexec_vnode_init_label(struct label *label)
269{
270
271	SLOT_SET(label, FINGERPRINT_INVALID);
272}
273
274/**
275 * @internal
276 * @brief The vnode label is being destroyed, reset the value in the MAC
277 *        per-policy slot for veriexec back to @c FINGERPRINT_INVALID
278 *
279 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
280 *
281 * @param label		the label that is being destroyed
282 */
283static void
284mac_veriexec_vnode_destroy_label(struct label *label)
285{
286
287	SLOT_SET(label, FINGERPRINT_INVALID);
288}
289
290/**
291 * @internal
292 * @brief Copy the value in the MAC per-policy slot assigned to veriexec from
293 *        the @p src label to the @p dest label
294 */
295static void
296mac_veriexec_copy_label(struct label *src, struct label *dest)
297{
298
299	SLOT_SET(dest, SLOT(src));
300}
301
302/**
303 * @internal
304 * @brief Check if the requested process can be debugged
305 *
306 * @param cred		credentials to use
307 * @param p		process to debug
308 *
309 * @return 0 if debugging is allowed, otherwise an error code.
310 */
311static int
312mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
313{
314	int error, flags;
315
316	/* If we are not enforcing veriexec, nothing for us to check */
317	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
318		return (0);
319
320	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
321	if (error != 0)
322		return (0);
323
324	return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0);
325}
326
327/**
328 * @internal
329 * @brief A KLD load has been requested and needs to be validated.
330 *
331 * @param cred		credentials to use
332 * @param vp		vnode of the KLD that has been requested
333 * @param vlabel	vnode label assigned to the vnode
334 *
335 * @return 0 if the KLD load is allowed, otherwise an error code.
336 */
337static int
338mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
339    struct label *vlabel)
340{
341	struct vattr va;
342	struct thread *td = curthread;
343	fingerprint_status_t status;
344	int error;
345
346	/*
347	 * If we are not actively enforcing, allow it
348	 */
349	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
350		return (0);
351
352	/* Get vnode attributes */
353	error = VOP_GETATTR(vp, &va, cred);
354	if (error)
355		return (error);
356
357	/*
358	 * Fetch the fingerprint status for the vnode
359	 * (starting with files first)
360	 */
361	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
362	    VERIEXEC_FILES_FIRST);
363	if (error && error != EAUTH)
364		return (error);
365
366	/*
367	 * By now we should have status...
368	 */
369	status = mac_veriexec_get_fingerprint_status(vp);
370	switch (status) {
371	case FINGERPRINT_FILE:
372	case FINGERPRINT_VALID:
373	case FINGERPRINT_INDIRECT:
374		if (error)
375			return (error);
376		break;
377	default:
378		/*
379		 * kldload should fail unless there is a valid fingerprint
380		 * registered.
381		 */
382		MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %u, "
383			"file %lu.%lu\n", status, va.va_fsid, va.va_fileid,
384			 va.va_gen);
385		return (EAUTH);
386	}
387
388	/* Everything is good, allow the KLD to be loaded */
389	return (0);
390}
391
392/**
393 * @internal
394 * @brief Check privileges that veriexec needs to be concerned about.
395 *
396 * The following privileges are checked by this function:
397 *  - PRIV_KMEM_WRITE\n
398 *    Check if writes to /dev/mem and /dev/kmem are allowed\n
399 *    (Only trusted processes are allowed)
400 *
401 * @param cred		credentials to use
402 * @param priv		privilege to check
403 *
404 * @return 0 if the privilege is allowed, error code otherwise.
405 */
406static int
407mac_veriexec_priv_check(struct ucred *cred, int priv)
408{
409
410	/* If we are not enforcing veriexec, nothing for us to check */
411	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
412		return (0);
413
414	switch (priv) {
415	case PRIV_KMEM_WRITE:
416		if (!mac_veriexec_proc_is_trusted(cred, curproc))
417			return (EPERM);
418		break;
419	default:
420		break;
421	}
422	return (0);
423}
424
425/**
426 * @internal
427 * @brief A program is being executed and needs to be validated.
428 *
429 * @param cred		credentials to use
430 * @param vp		vnode of the program that is being executed
431 * @param label		vnode label assigned to the vnode
432 * @param imgp		parameters for the image to be executed
433 * @param execlabel	optional exec label
434 *
435 * @return 0 if the program should be allowed to execute, otherwise an error
436 *     code.
437 */
438static int
439mac_veriexec_vnode_check_exec(struct ucred *cred __unused,
440    struct vnode *vp __unused, struct label *label __unused,
441    struct image_params *imgp, struct label *execlabel __unused)
442{
443	struct thread *td = curthread;
444	int error;
445
446	error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
447	return (error);
448}
449
450/**
451 * @brief Check fingerprint for the specified vnode and validate it
452 *
453 * @param cred		credentials to use
454 * @param vp		vnode of the file
455 * @param accmode	access mode to check (read, write, append, create,
456 *			verify, etc.)
457 *
458 * @return 0 if the file validated, otherwise an error code.
459 */
460static int
461mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
462{
463	struct vattr va;
464	struct thread *td = curthread;
465	fingerprint_status_t status;
466	int error;
467
468	/* Get vnode attributes */
469	error = VOP_GETATTR(vp, &va, cred);
470	if (error)
471		return (error);
472
473	/* Get the fingerprint status for the file */
474	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
475	    VERIEXEC_FILES_FIRST);
476	if (error && error != EAUTH)
477		return (error);
478
479	/*
480	 * By now we should have status...
481	 */
482	status = mac_veriexec_get_fingerprint_status(vp);
483	if (accmode & VWRITE) {
484		/*
485		 * If file has a fingerprint then deny the write request,
486		 * otherwise invalidate the status so we don't keep checking
487		 * for the file having a fingerprint.
488		 */
489		switch (status) {
490		case FINGERPRINT_FILE:
491		case FINGERPRINT_VALID:
492		case FINGERPRINT_INDIRECT:
493			MAC_VERIEXEC_DBG(2,
494			    "attempted write to fingerprinted file for dev "
495			    "%u, file %lu.%lu\n", va.va_fsid,
496			    va.va_fileid, va.va_gen);
497			return (EPERM);
498		default:
499			break;
500		}
501	}
502	if (accmode & VVERIFY) {
503		switch (status) {
504		case FINGERPRINT_FILE:
505		case FINGERPRINT_VALID:
506		case FINGERPRINT_INDIRECT:
507			if (error)
508				return (error);
509			break;
510		default:
511			/*
512			 * Caller wants open to fail unless there is a valid
513			 * fingerprint registered.
514			 */
515			MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev "
516			    "%u, file %lu.%lu\n", status, va.va_fsid,
517			    va.va_fileid, va.va_gen);
518			return (EAUTH);
519		}
520	}
521	return (0);
522}
523
524/**
525 * @brief Opening a file has been requested and may need to be validated.
526 *
527 * @param cred		credentials to use
528 * @param vp		vnode of the file to open
529 * @param label		vnode label assigned to the vnode
530 * @param accmode	access mode to use for opening the file (read, write,
531 * 			append, create, verify, etc.)
532 *
533 * @return 0 if opening the file should be allowed, otherwise an error code.
534 */
535static int
536mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
537	struct label *label __unused, accmode_t accmode)
538{
539	int error;
540
541	/*
542	 * Look for the file on the fingerprint lists iff it has not been seen
543	 * before.
544	 */
545	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
546		return (0);
547
548	error = mac_veriexec_check_vp(cred, vp, accmode);
549	return (error);
550}
551
552/**
553 * @brief Check mode changes on file to ensure they should be allowed.
554 *
555 * We cannot allow chmod of SUID or SGID on verified files.
556 *
557 * @param cred		credentials to use
558 * @param vp		vnode of the file to open
559 * @param label		vnode label assigned to the vnode
560 * @param mode		mode flags to set
561 *
562 * @return 0 if the mode change should be allowed, EAUTH otherwise.
563 */
564static int
565mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
566    struct label *label __unused, mode_t mode)
567{
568	int error;
569
570	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
571		return (0);
572
573	/*
574	 * Do not allow chmod (set-[gu]id) of verified file
575	 */
576	error = mac_veriexec_check_vp(cred, vp, VVERIFY);
577	if (error == EAUTH)             /* it isn't verified */
578		return (0);
579	if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
580		return (EAUTH);
581	return (0);
582}
583
584/**
585 * @internal
586 * @brief Initialize the mac_veriexec MAC policy
587 *
588 * @param mpc		MAC policy configuration
589 */
590static void
591mac_veriexec_init(struct mac_policy_conf *mpc __unused)
592{
593	/* Initialize state */
594	mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
595
596	/* Initialize meta-data storage */
597	mac_veriexec_metadata_init();
598
599	/* Initialize fingerprint ops */
600	mac_veriexec_fingerprint_init();
601
602	/* Register event handlers */
603	EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL,
604	    EVENTHANDLER_PRI_FIRST);
605	EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL,
606	    EVENTHANDLER_PRI_LAST);
607}
608
609/**
610 * @internal
611 * @brief MAC policy-specific syscall for mac_veriexec
612 *
613 * The following syscalls are implemented:
614 *   - @c MAC_VERIEXEC_CHECK_SYSCALL
615 *        Check if the file referenced by a file descriptor has a fingerprint
616 *        registered in the meta-data store.
617 *
618 * @param td		calling thread
619 * @param call		system call number
620 * @param arg		arugments to the syscall
621 *
622 * @return 0 on success, otherwise an error code.
623 */
624static int
625mac_veriexec_syscall(struct thread *td, int call, void *arg)
626{
627	struct image_params img;
628	struct nameidata nd;
629	cap_rights_t rights;
630	struct vattr va;
631	struct file *fp;
632	int error;
633
634	switch (call) {
635	case MAC_VERIEXEC_CHECK_FD_SYSCALL:
636		/* Get the vnode associated with the file descriptor passed */
637		error = getvnode(td, (uintptr_t) arg, cap_rights_init(&rights,
638		    CAP_READ), &fp);
639		if (error)
640			return (error);
641		if (fp->f_type != DTYPE_VNODE) {
642			MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: "
643			    "file is not vnode type (type=0x%x)",
644			    fp->f_type);
645			error = EINVAL;
646			goto cleanup_file;
647		}
648
649		/*
650		 * setup the bits of image_params that are used by
651		 * mac_veriexec_check_fingerprint().
652		 */
653		bzero(&img, sizeof(img));
654		img.proc = td->td_proc;
655		img.vp = fp->f_vnode;
656		img.attr = &va;
657
658		/*
659		 * Get vnode attributes
660		 * (need to obtain a lock on the vnode first)
661		 */
662		vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
663		error = VOP_GETATTR(fp->f_vnode, &va,  td->td_ucred);
664		if (error)
665			goto check_done;
666
667		MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: "
668		    "va_mode=%o, check_files=%d\n", va.va_mode,
669		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0));
670		error = mac_veriexec_fingerprint_check_image(&img,
671		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td);
672check_done:
673		/* Release the lock we obtained earlier */
674		VOP_UNLOCK(img.vp, 0);
675cleanup_file:
676		fdrop(fp, td);
677		break;
678	case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
679		/* Look up the path to get the vnode */
680		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
681		    UIO_USERSPACE, arg, td);
682		error = namei(&nd);
683		if (error != 0)
684			break;
685		NDFREE(&nd, NDF_ONLY_PNBUF);
686
687		/* Check the fingerprint status of the vnode */
688		error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
689		vput(nd.ni_vp);
690		break;
691	default:
692		error = EOPNOTSUPP;
693	}
694	return (error);
695}
696
697static struct mac_policy_ops mac_veriexec_ops =
698{
699	.mpo_init = mac_veriexec_init,
700	.mpo_syscall = mac_veriexec_syscall,
701	.mpo_kld_check_load = mac_veriexec_kld_check_load,
702	.mpo_mount_destroy_label = mac_veriexec_mount_destroy_label,
703	.mpo_mount_init_label = mac_veriexec_mount_init_label,
704	.mpo_priv_check = mac_veriexec_priv_check,
705	.mpo_proc_check_debug = mac_veriexec_proc_check_debug,
706	.mpo_vnode_check_exec = mac_veriexec_vnode_check_exec,
707	.mpo_vnode_check_open = mac_veriexec_vnode_check_open,
708	.mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode,
709	.mpo_vnode_copy_label = mac_veriexec_copy_label,
710	.mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,
711	.mpo_vnode_init_label = mac_veriexec_vnode_init_label,
712};
713
714MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
715    MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
716MODULE_VERSION(mac_veriexec, 1);
717
718/**
719 * @brief Get the fingerprint status set on a vnode.
720 *
721 * @param vp		vnode to obtain fingerprint status from
722 *
723 * @return Fingerprint status assigned to the vnode.
724 */
725fingerprint_status_t
726mac_veriexec_get_fingerprint_status(struct vnode *vp)
727{
728	fingerprint_status_t fps;
729
730	fps = SLOT(vp->v_label);
731	switch (fps) {
732	case FINGERPRINT_VALID:
733	case FINGERPRINT_INDIRECT:
734	case FINGERPRINT_FILE:
735		break;
736	default:
737		/* we may need to recurse */
738		if (strcmp(vp->v_tag, "null") == 0) {
739			struct vnode *ldvp;
740
741			ldvp = NULLVPTOLOWERVP(vp);
742			return mac_veriexec_get_fingerprint_status(ldvp);
743		}
744		break;
745	}
746	return fps;
747}
748
749/**
750 * @brief Get the current verified execution subsystem state.
751 *
752 * @return Current set of verified execution subsystem state flags.
753 */
754int
755mac_veriexec_get_state(void)
756{
757
758	return (mac_veriexec_state);
759}
760
761/**
762 * @brief Determine if the verified execution subsystem state has specific
763 *     flags set.
764 *
765 * @param state		mask of flags to check
766 *
767 * @return State flags set within the masked bits
768 */
769int
770mac_veriexec_in_state(int state)
771{
772
773	return (mac_veriexec_state & state);
774}
775
776/**
777 * @brief Set the fingerprint status for a vnode
778 *
779 * Fingerprint status is stored in the MAC per-policy slot assigned to
780 * mac_veriexec.
781 *
782 * @param vp		vnode to store the fingerprint status on
783 * @param fp_status	fingerprint status to store
784 */
785void
786mac_veriexec_set_fingerprint_status(struct vnode *vp,
787    fingerprint_status_t fp_status)
788{
789
790	/* recurse until we find the real storage */
791	if (strcmp(vp->v_tag, "null") == 0) {
792		struct vnode *ldvp;
793
794		ldvp = NULLVPTOLOWERVP(vp);
795		mac_veriexec_set_fingerprint_status(ldvp, fp_status);
796		return;
797	}
798	SLOT_SET(vp->v_label, fp_status);
799}
800
801/**
802 * @brief Set verified execution subsystem state flags
803 *
804 * @note Flags can only be added to the current state, not removed.
805 *
806 * @param state		state flags to add to the current state
807 */
808void
809mac_veriexec_set_state(int state)
810{
811
812	mac_veriexec_state |= state;
813}
814
815/**
816 * @brief Determine if the process is trusted
817 *
818 * @param cred		credentials to use
819 * @param p		the process in question
820 *
821 * @return 1 if the process is trusted, otherwise 0.
822 */
823int
824mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
825{
826	int error, flags;
827
828	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
829
830	/* Any errors, deny access */
831	if (error != 0)
832		return (0);
833
834	/* Check that the trusted flag is set */
835	return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);
836}
837