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