xref: /freebsd/sys/security/mac_veriexec/mac_veriexec.c (revision bc7512cc58af2e8bbe5bbf5ca0059b1daa1da897)
1 /*
2  * $FreeBSD$
3  *
4  * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019 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 | CTLFLAG_MPSAFE, 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 | CTLFLAG_NEEDGIANT,
89     0, 0, sysctl_mac_veriexec_state, "A",
90     "Verified execution subsystem state");
91 
92 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db,
93     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT,
94     0, 0, sysctl_mac_veriexec_db,
95     "A", "Verified execution fingerprint database");
96 
97 static int mac_veriexec_slot;
98 
99 MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
100 
101 /**
102  * @internal
103  * @brief Handler for security.mac.veriexec.db sysctl
104  *
105  * Display a human-readable form of the current fingerprint database.
106  */
107 static int
108 sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
109 {
110 	struct sbuf sb;
111 	int error;
112 
113 	error = sysctl_wire_old_buffer(req, 0);
114 	if (error != 0)
115 		return (error);
116 
117 	sbuf_new_for_sysctl(&sb, NULL, 1024, req);
118 	mac_veriexec_metadata_print_db(&sb);
119 	error = sbuf_finish(&sb);
120 	sbuf_delete(&sb);
121 
122 	return (error);
123 }
124 
125 /**
126  * @internal
127  * @brief Generate human-readable output about the current verified execution
128  *        state.
129  *
130  * @param sbp		sbuf to write output to
131  */
132 static void
133 mac_veriexec_print_state(struct sbuf *sbp)
134 {
135 
136 	if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE)
137 		sbuf_printf(sbp, "inactive ");
138 	if (mac_veriexec_state & VERIEXEC_STATE_LOADED)
139 		sbuf_printf(sbp, "loaded ");
140 	if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE)
141 		sbuf_printf(sbp, "active ");
142 	if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE)
143 		sbuf_printf(sbp, "enforce ");
144 	if (mac_veriexec_state & VERIEXEC_STATE_LOCKED)
145 		sbuf_printf(sbp, "locked ");
146 	if (mac_veriexec_state != 0)
147 		sbuf_trim(sbp);
148 }
149 
150 /**
151  * @internal
152  * @brief Handler for security.mac.veriexec.state sysctl
153  *
154  * Display a human-readable form of the current verified execution subsystem
155  * state.
156  */
157 static int
158 sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
159 {
160 	struct sbuf sb;
161 	int error;
162 
163 	sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
164 	mac_veriexec_print_state(&sb);
165 	sbuf_finish(&sb);
166 
167 	error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
168 	sbuf_delete(&sb);
169 	return (error);
170 }
171 
172 /**
173  * @internal
174  * @brief Event handler called when a virtual file system is mounted.
175  *
176  * We need to record the file system identifier in the MAC per-policy slot
177  * assigned to veriexec, so we have a key to use in order to reference the
178  * mount point in the meta-data store.
179  *
180  * @param arg		unused argument
181  * @param mp		mount point that is being mounted
182  * @param fsrootvp	vnode of the file system root
183  * @param td		calling thread
184  */
185 static void
186 mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
187     struct vnode *fsrootvp, struct thread *td)
188 {
189 	struct vattr va;
190 	int error;
191 
192 	error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
193 	if (error)
194 		return;
195 
196 	SLOT_SET(mp->mnt_label, va.va_fsid);
197 #ifdef MAC_DEBUG
198 	MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p",
199 	    (uintmax_t)va.va_fsid, mp);
200 #endif
201 }
202 
203 /**
204  * @internal
205  * @brief Event handler called when a virtual file system is unmounted.
206  *
207  * If we recorded a file system identifier in the MAC per-policy slot assigned
208  * to veriexec, then we need to tell the meta-data store to clean up.
209  *
210  * @param arg		unused argument
211  * @param mp		mount point that is being unmounted
212  * @param td		calling thread
213  */
214 static void
215 mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
216     struct thread *td)
217 {
218 	dev_t fsid;
219 
220 	fsid = SLOT(mp->mnt_label);
221 	if (fsid) {
222 		MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount",
223 		    (uintmax_t)fsid);
224 		mac_veriexec_metadata_unmounted(fsid, td);
225 	}
226 }
227 
228 /**
229  * @internal
230  * @brief The mount point is being initialized, set the value in the MAC
231  *     per-policy slot for veriexec to zero.
232  *
233  * @note A value of zero in this slot indicates no file system identifier
234  *     is assigned.
235  *
236  * @param label the label that is being initialized
237  */
238 static void
239 mac_veriexec_mount_init_label(struct label *label)
240 {
241 
242 	SLOT_SET(label, 0);
243 }
244 
245 /**
246  * @internal
247  * @brief The mount-point is being destroyed, reset the value in the MAC
248  *     per-policy slot for veriexec back to zero.
249  *
250  * @note A value of zero in this slot indicates no file system identifier
251  *     is assigned.
252  *
253  * @param label the label that is being destroyed
254  */
255 static void
256 mac_veriexec_mount_destroy_label(struct label *label)
257 {
258 
259 	SLOT_SET(label, 0);
260 }
261 
262 /**
263  * @internal
264  * @brief The vnode label is being initialized, set the value in the MAC
265  *     per-policy slot for veriexec to @c FINGERPRINT_INVALID
266  *
267  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
268  *
269  * @param label		the label that is being initialized
270  */
271 static void
272 mac_veriexec_vnode_init_label(struct label *label)
273 {
274 
275 	SLOT_SET(label, FINGERPRINT_INVALID);
276 }
277 
278 /**
279  * @internal
280  * @brief The vnode label is being destroyed, reset the value in the MAC
281  *        per-policy slot for veriexec back to @c FINGERPRINT_INVALID
282  *
283  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
284  *
285  * @param label		the label that is being destroyed
286  */
287 static void
288 mac_veriexec_vnode_destroy_label(struct label *label)
289 {
290 
291 	SLOT_SET(label, FINGERPRINT_INVALID);
292 }
293 
294 /**
295  * @internal
296  * @brief Copy the value in the MAC per-policy slot assigned to veriexec from
297  *        the @p src label to the @p dest label
298  */
299 static void
300 mac_veriexec_copy_label(struct label *src, struct label *dest)
301 {
302 
303 	SLOT_SET(dest, SLOT(src));
304 }
305 
306 /**
307  * @internal
308  * @brief Check if the requested process can be debugged
309  *
310  * @param cred		credentials to use
311  * @param p		process to debug
312  *
313  * @return 0 if debugging is allowed, otherwise an error code.
314  */
315 static int
316 mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
317 {
318 	int error, flags;
319 
320 	/* If we are not enforcing veriexec, nothing for us to check */
321 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
322 		return (0);
323 
324 	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
325 	if (error != 0)
326 		return (0);
327 
328 	return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0);
329 }
330 
331 /**
332  * @internal
333  * @brief A KLD load has been requested and needs to be validated.
334  *
335  * @param cred		credentials to use
336  * @param vp		vnode of the KLD that has been requested
337  * @param vlabel	vnode label assigned to the vnode
338  *
339  * @return 0 if the KLD load is allowed, otherwise an error code.
340  */
341 static int
342 mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
343     struct label *vlabel)
344 {
345 	struct vattr va;
346 	struct thread *td = curthread;
347 	fingerprint_status_t status;
348 	int error;
349 
350 	/*
351 	 * If we are not actively enforcing, allow it
352 	 */
353 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
354 		return (0);
355 
356 	/* Get vnode attributes */
357 	error = VOP_GETATTR(vp, &va, cred);
358 	if (error)
359 		return (error);
360 
361 	/*
362 	 * Fetch the fingerprint status for the vnode
363 	 * (starting with files first)
364 	 */
365 	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
366 	    VERIEXEC_FILES_FIRST);
367 	if (error && error != EAUTH)
368 		return (error);
369 
370 	/*
371 	 * By now we should have status...
372 	 */
373 	status = mac_veriexec_get_fingerprint_status(vp);
374 	switch (status) {
375 	case FINGERPRINT_FILE:
376 	case FINGERPRINT_VALID:
377 	case FINGERPRINT_INDIRECT:
378 		if (error)
379 			return (error);
380 		break;
381 	default:
382 		/*
383 		 * kldload should fail unless there is a valid fingerprint
384 		 * registered.
385 		 */
386 		MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, "
387 		    "file %ju.%ju\n", status, (uintmax_t)va.va_fsid,
388 		    (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
389 		return (EAUTH);
390 	}
391 
392 	/* Everything is good, allow the KLD to be loaded */
393 	return (0);
394 }
395 
396 /**
397  * @internal
398  * @brief Check privileges that veriexec needs to be concerned about.
399  *
400  * The following privileges are checked by this function:
401  *  - PRIV_KMEM_WRITE\n
402  *    Check if writes to /dev/mem and /dev/kmem are allowed\n
403  *    (Only trusted processes are allowed)
404  *
405  * @param cred		credentials to use
406  * @param priv		privilege to check
407  *
408  * @return 0 if the privilege is allowed, error code otherwise.
409  */
410 static int
411 mac_veriexec_priv_check(struct ucred *cred, int priv)
412 {
413 
414 	/* If we are not enforcing veriexec, nothing for us to check */
415 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
416 		return (0);
417 
418 	switch (priv) {
419 	case PRIV_KMEM_WRITE:
420 		if (!mac_veriexec_proc_is_trusted(cred, curproc))
421 			return (EPERM);
422 		break;
423 	default:
424 		break;
425 	}
426 	return (0);
427 }
428 
429 static int
430 mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp,
431     void *arg1, int arg2, struct sysctl_req *req)
432 {
433 	struct sysctl_oid *oid;
434 
435 	/* If we are not enforcing veriexec, nothing for us to check */
436 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
437 		return (0);
438 
439 	oid = oidp;
440 	if (oid->oid_kind & CTLFLAG_SECURE) {
441 		return (EPERM);		/* XXX call mac_veriexec_priv_check? */
442 	}
443 	return 0;
444 }
445 
446 /**
447  * @internal
448  * @brief A program is being executed and needs to be validated.
449  *
450  * @param cred		credentials to use
451  * @param vp		vnode of the program that is being executed
452  * @param label		vnode label assigned to the vnode
453  * @param imgp		parameters for the image to be executed
454  * @param execlabel	optional exec label
455  *
456  * @return 0 if the program should be allowed to execute, otherwise an error
457  *     code.
458  */
459 static int
460 mac_veriexec_vnode_check_exec(struct ucred *cred __unused,
461     struct vnode *vp __unused, struct label *label __unused,
462     struct image_params *imgp, struct label *execlabel __unused)
463 {
464 	struct thread *td = curthread;
465 	int error;
466 
467 	error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
468 	return (error);
469 }
470 
471 /**
472  * @brief Check fingerprint for the specified vnode and validate it
473  *
474  * @param cred		credentials to use
475  * @param vp		vnode of the file
476  * @param accmode	access mode to check (read, write, append, create,
477  *			verify, etc.)
478  *
479  * @return 0 if the file validated, otherwise an error code.
480  */
481 static int
482 mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
483 {
484 	struct vattr va;
485 	struct thread *td = curthread;
486 	fingerprint_status_t status;
487 	int error;
488 
489 	/* Get vnode attributes */
490 	error = VOP_GETATTR(vp, &va, cred);
491 	if (error)
492 		return (error);
493 
494 	/* Get the fingerprint status for the file */
495 	error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
496 	    VERIEXEC_FILES_FIRST);
497 	if (error && error != EAUTH)
498 		return (error);
499 
500 	/*
501 	 * By now we should have status...
502 	 */
503 	status = mac_veriexec_get_fingerprint_status(vp);
504 	if (accmode & VWRITE) {
505 		/*
506 		 * If file has a fingerprint then deny the write request,
507 		 * otherwise invalidate the status so we don't keep checking
508 		 * for the file having a fingerprint.
509 		 */
510 		switch (status) {
511 		case FINGERPRINT_FILE:
512 		case FINGERPRINT_VALID:
513 		case FINGERPRINT_INDIRECT:
514 			MAC_VERIEXEC_DBG(2,
515 			    "attempted write to fingerprinted file for dev "
516 			    "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid,
517 			    (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
518 			return (EPERM);
519 		default:
520 			break;
521 		}
522 	}
523 	if (accmode & VVERIFY) {
524 		switch (status) {
525 		case FINGERPRINT_FILE:
526 		case FINGERPRINT_VALID:
527 		case FINGERPRINT_INDIRECT:
528 			if (error)
529 				return (error);
530 			break;
531 		default:
532 			/*
533 			 * Caller wants open to fail unless there is a valid
534 			 * fingerprint registered.
535 			 */
536 			MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev "
537 			    "%ju, file %ju.%ju\n", status,
538 			    (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid,
539 			    (uintmax_t)va.va_gen);
540 			return (EAUTH);
541 		}
542 	}
543 	return (0);
544 }
545 
546 /**
547  * @brief Opening a file has been requested and may need to be validated.
548  *
549  * @param cred		credentials to use
550  * @param vp		vnode of the file to open
551  * @param label		vnode label assigned to the vnode
552  * @param accmode	access mode to use for opening the file (read, write,
553  * 			append, create, verify, etc.)
554  *
555  * @return 0 if opening the file should be allowed, otherwise an error code.
556  */
557 static int
558 mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
559 	struct label *label __unused, accmode_t accmode)
560 {
561 	int error;
562 
563 	/*
564 	 * Look for the file on the fingerprint lists iff it has not been seen
565 	 * before.
566 	 */
567 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
568 		return (0);
569 
570 	error = mac_veriexec_check_vp(cred, vp, accmode);
571 	return (error);
572 }
573 
574 /**
575  * @brief Check mode changes on file to ensure they should be allowed.
576  *
577  * We cannot allow chmod of SUID or SGID on verified files.
578  *
579  * @param cred		credentials to use
580  * @param vp		vnode of the file to open
581  * @param label		vnode label assigned to the vnode
582  * @param mode		mode flags to set
583  *
584  * @return 0 if the mode change should be allowed, EAUTH otherwise.
585  */
586 static int
587 mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
588     struct label *label __unused, mode_t mode)
589 {
590 	int error;
591 
592 	if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
593 		return (0);
594 
595 	/*
596 	 * Do not allow chmod (set-[gu]id) of verified file
597 	 */
598 	error = mac_veriexec_check_vp(cred, vp, VVERIFY);
599 	if (error == EAUTH)             /* it isn't verified */
600 		return (0);
601 	if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
602 		return (EAUTH);
603 	return (0);
604 }
605 
606 /**
607  * @internal
608  * @brief Initialize the mac_veriexec MAC policy
609  *
610  * @param mpc		MAC policy configuration
611  */
612 static void
613 mac_veriexec_init(struct mac_policy_conf *mpc __unused)
614 {
615 	/* Initialize state */
616 	mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
617 
618 	/* Initialize meta-data storage */
619 	mac_veriexec_metadata_init();
620 
621 	/* Initialize fingerprint ops */
622 	mac_veriexec_fingerprint_init();
623 
624 	/* Register event handlers */
625 	EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL,
626 	    EVENTHANDLER_PRI_FIRST);
627 	EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL,
628 	    EVENTHANDLER_PRI_LAST);
629 }
630 
631 /**
632  * @internal
633  * @brief MAC policy-specific syscall for mac_veriexec
634  *
635  * The following syscalls are implemented:
636  *   - @c MAC_VERIEXEC_CHECK_SYSCALL
637  *        Check if the file referenced by a file descriptor has a fingerprint
638  *        registered in the meta-data store.
639  *
640  * @param td		calling thread
641  * @param call		system call number
642  * @param arg		arugments to the syscall
643  *
644  * @return 0 on success, otherwise an error code.
645  */
646 static int
647 mac_veriexec_syscall(struct thread *td, int call, void *arg)
648 {
649 	struct image_params img;
650 	struct nameidata nd;
651 	cap_rights_t rights;
652 	struct vattr va;
653 	struct file *fp;
654 	int error;
655 
656 	switch (call) {
657 	case MAC_VERIEXEC_CHECK_FD_SYSCALL:
658 		/* Get the vnode associated with the file descriptor passed */
659 		error = getvnode(td, (uintptr_t) arg,
660 		    cap_rights_init_one(&rights, CAP_READ), &fp);
661 		if (error)
662 			return (error);
663 		if (fp->f_type != DTYPE_VNODE) {
664 			MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: "
665 			    "file is not vnode type (type=0x%x)",
666 			    fp->f_type);
667 			error = EINVAL;
668 			goto cleanup_file;
669 		}
670 
671 		/*
672 		 * setup the bits of image_params that are used by
673 		 * mac_veriexec_check_fingerprint().
674 		 */
675 		bzero(&img, sizeof(img));
676 		img.proc = td->td_proc;
677 		img.vp = fp->f_vnode;
678 		img.attr = &va;
679 
680 		/*
681 		 * Get vnode attributes
682 		 * (need to obtain a lock on the vnode first)
683 		 */
684 		vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
685 		error = VOP_GETATTR(fp->f_vnode, &va,  td->td_ucred);
686 		if (error)
687 			goto check_done;
688 
689 		MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: "
690 		    "va_mode=%o, check_files=%d\n", va.va_mode,
691 		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0));
692 		error = mac_veriexec_fingerprint_check_image(&img,
693 		    ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td);
694 check_done:
695 		/* Release the lock we obtained earlier */
696 		VOP_UNLOCK(img.vp);
697 cleanup_file:
698 		fdrop(fp, td);
699 		break;
700 	case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
701 		/* Look up the path to get the vnode */
702 		NDINIT(&nd, LOOKUP,
703 		    FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1,
704 		    UIO_USERSPACE, arg);
705 		error = namei(&nd);
706 		if (error != 0)
707 			break;
708 		NDFREE_PNBUF(&nd);
709 
710 		/* Check the fingerprint status of the vnode */
711 		error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
712 		vput(nd.ni_vp);
713 		break;
714 	default:
715 		error = EOPNOTSUPP;
716 	}
717 	return (error);
718 }
719 
720 static struct mac_policy_ops mac_veriexec_ops =
721 {
722 	.mpo_init = mac_veriexec_init,
723 	.mpo_kld_check_load = mac_veriexec_kld_check_load,
724 	.mpo_mount_destroy_label = mac_veriexec_mount_destroy_label,
725 	.mpo_mount_init_label = mac_veriexec_mount_init_label,
726 	.mpo_priv_check = mac_veriexec_priv_check,
727 	.mpo_proc_check_debug = mac_veriexec_proc_check_debug,
728 	.mpo_syscall = mac_veriexec_syscall,
729 	.mpo_system_check_sysctl = mac_veriexec_sysctl_check,
730 	.mpo_vnode_check_exec = mac_veriexec_vnode_check_exec,
731 	.mpo_vnode_check_open = mac_veriexec_vnode_check_open,
732 	.mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode,
733 	.mpo_vnode_copy_label = mac_veriexec_copy_label,
734 	.mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,
735 	.mpo_vnode_init_label = mac_veriexec_vnode_init_label,
736 };
737 
738 MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
739     MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
740 MODULE_VERSION(mac_veriexec, MAC_VERIEXEC_VERSION);
741 
742 static struct vnode *
743 mac_veriexec_bottom_vnode(struct vnode *vp)
744 {
745 	struct vnode *ldvp = NULL;
746 
747 	/*
748 	 * XXX This code is bogus. nullfs is not the only stacking
749 	 * filesystem. Less bogus code would add a VOP to reach bottom
750 	 * vnode and would not make assumptions how to get there.
751 	 */
752 	if (vp->v_mount != NULL &&
753 	    strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0)
754 		ldvp = NULLVPTOLOWERVP(vp);
755 	return (ldvp);
756 }
757 
758 /**
759  * @brief Get the fingerprint status set on a vnode.
760  *
761  * @param vp		vnode to obtain fingerprint status from
762  *
763  * @return Fingerprint status assigned to the vnode.
764  */
765 fingerprint_status_t
766 mac_veriexec_get_fingerprint_status(struct vnode *vp)
767 {
768 	fingerprint_status_t fps;
769 	struct vnode *ldvp;
770 
771 	fps = SLOT(vp->v_label);
772 	switch (fps) {
773 	case FINGERPRINT_VALID:
774 	case FINGERPRINT_INDIRECT:
775 	case FINGERPRINT_FILE:
776 		break;
777 	default:
778 		/* we may need to recurse */
779 		ldvp = mac_veriexec_bottom_vnode(vp);
780 		if (ldvp != NULL)
781 			return mac_veriexec_get_fingerprint_status(ldvp);
782 		break;
783 	}
784 	return fps;
785 }
786 
787 /**
788  * @brief Get the current verified execution subsystem state.
789  *
790  * @return Current set of verified execution subsystem state flags.
791  */
792 int
793 mac_veriexec_get_state(void)
794 {
795 
796 	return (mac_veriexec_state);
797 }
798 
799 /**
800  * @brief Determine if the verified execution subsystem state has specific
801  *     flags set.
802  *
803  * @param state		mask of flags to check
804  *
805  * @return State flags set within the masked bits
806  */
807 int
808 mac_veriexec_in_state(int state)
809 {
810 
811 	return (mac_veriexec_state & state);
812 }
813 
814 /**
815  * @brief Set the fingerprint status for a vnode
816  *
817  * Fingerprint status is stored in the MAC per-policy slot assigned to
818  * mac_veriexec.
819  *
820  * @param vp		vnode to store the fingerprint status on
821  * @param fp_status	fingerprint status to store
822  */
823 void
824 mac_veriexec_set_fingerprint_status(struct vnode *vp,
825     fingerprint_status_t fp_status)
826 {
827 	struct vnode *ldvp;
828 
829 	/* recurse until we find the real storage */
830 	ldvp = mac_veriexec_bottom_vnode(vp);
831 	if (ldvp != NULL) {
832 		mac_veriexec_set_fingerprint_status(ldvp, fp_status);
833 		return;
834 	}
835 	SLOT_SET(vp->v_label, fp_status);
836 }
837 
838 /**
839  * @brief Set verified execution subsystem state flags
840  *
841  * @note Flags can only be added to the current state, not removed.
842  *
843  * @param state		state flags to add to the current state
844  */
845 void
846 mac_veriexec_set_state(int state)
847 {
848 
849 	mac_veriexec_state |= state;
850 }
851 
852 /**
853  * @brief Determine if the process is trusted
854  *
855  * @param cred		credentials to use
856  * @param p		the process in question
857  *
858  * @return 1 if the process is trusted, otherwise 0.
859  */
860 int
861 mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
862 {
863 	int already_locked, error, flags;
864 
865 	/* Make sure we lock the process if we do not already have the lock */
866 	already_locked = PROC_LOCKED(p);
867 	if (!already_locked)
868 		PROC_LOCK(p);
869 
870 	error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
871 
872 	/* Unlock the process if we locked it previously */
873 	if (!already_locked)
874 		PROC_UNLOCK(p);
875 
876 	/* Any errors, deny access */
877 	if (error != 0)
878 		return (0);
879 
880 	/* Check that the trusted flag is set */
881 	return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);
882 }
883