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 
74 static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
75 static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
76 
77 SYSCTL_DECL(_security_mac);
78 
79 SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW, 0,
80     "MAC/veriexec policy controls");
81 
82 int	mac_veriexec_debug;
83 SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
84     &mac_veriexec_debug, 0, "Debug level");
85 
86 static int	mac_veriexec_state;
87 SYSCTL_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 
91 SYSCTL_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 
95 static int mac_veriexec_slot;
96 
97 MALLOC_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  */
105 static int
106 sysctl_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  */
130 static void
131 mac_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  */
155 static int
156 sysctl_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  */
183 static void
184 mac_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  */
211 static void
212 mac_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  */
234 static void
235 mac_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  */
251 static void
252 mac_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  */
267 static void
268 mac_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  */
283 static void
284 mac_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  */
295 static void
296 mac_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  */
311 static int
312 mac_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  */
337 static int
338 mac_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  */
406 static int
407 mac_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  */
438 static int
439 mac_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  */
460 static int
461 mac_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  */
535 static int
536 mac_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  */
564 static int
565 mac_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  */
590 static void
591 mac_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  */
624 static int
625 mac_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);
672 check_done:
673 		/* Release the lock we obtained earlier */
674 		VOP_UNLOCK(img.vp, 0);
675 cleanup_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 
697 static 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 
714 MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
715     MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
716 MODULE_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  */
725 fingerprint_status_t
726 mac_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  */
754 int
755 mac_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  */
769 int
770 mac_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  */
785 void
786 mac_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  */
808 void
809 mac_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  */
823 int
824 mac_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