2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2011-2023 Juniper Networks, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
31 #include "opt_capsicum.h"
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>
40 #include <sys/filedesc.h>
41 #include <sys/imgact.h>
43 #include <sys/kernel.h>
45 #include <sys/mount.h>
46 #include <sys/namei.h>
51 #include <sys/sysctl.h>
52 #include <sys/vnode.h>
53 #ifdef COMPAT_FREEBSD32
54 #include <sys/sysent.h>
55 #include <sys/stdint.h>
56 #include <sys/abi_compat.h>
58 #include <fs/nullfs/null.h>
59 #include <security/mac/mac_framework.h>
60 #include <security/mac/mac_policy.h>
62 #include "mac_veriexec.h"
63 #include "mac_veriexec_internal.h"
66 mac_label_get((l), mac_veriexec_slot)
67 #define SLOT_SET(l, v) \
68 mac_label_set((l), mac_veriexec_slot, (v))
70 #ifdef MAC_VERIEXEC_DEBUG
71 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) \
73 VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt \
74 "\n", ##__VA_ARGS__)); \
77 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...)
80 static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
81 static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
82 static struct mac_policy_ops mac_veriexec_ops;
84 SYSCTL_DECL(_security_mac);
86 SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
87 "MAC/veriexec policy controls");
89 int mac_veriexec_debug;
90 SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
91 &mac_veriexec_debug, 0, "Debug level");
93 static int mac_veriexec_state;
94 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state,
95 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
96 0, 0, sysctl_mac_veriexec_state, "A",
97 "Verified execution subsystem state");
99 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db,
100 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT,
101 0, 0, sysctl_mac_veriexec_db,
102 "A", "Verified execution fingerprint database");
105 static int mac_veriexec_slot;
107 static int mac_veriexec_block_unlink;
109 MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
113 * @brief Handler for security.mac.veriexec.db sysctl
115 * Display a human-readable form of the current fingerprint database.
118 sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
123 error = sysctl_wire_old_buffer(req, 0);
127 sbuf_new_for_sysctl(&sb, NULL, 1024, req);
128 mac_veriexec_metadata_print_db(&sb);
129 error = sbuf_finish(&sb);
137 * @brief Generate human-readable output about the current verified execution
140 * @param sbp sbuf to write output to
143 mac_veriexec_print_state(struct sbuf *sbp)
146 if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE)
147 sbuf_printf(sbp, "inactive ");
148 if (mac_veriexec_state & VERIEXEC_STATE_LOADED)
149 sbuf_printf(sbp, "loaded ");
150 if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE)
151 sbuf_printf(sbp, "active ");
152 if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE)
153 sbuf_printf(sbp, "enforce ");
154 if (mac_veriexec_state & VERIEXEC_STATE_LOCKED)
155 sbuf_printf(sbp, "locked ");
156 if (mac_veriexec_state != 0)
162 * @brief Handler for security.mac.veriexec.state sysctl
164 * Display a human-readable form of the current verified execution subsystem
168 sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
173 sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
174 mac_veriexec_print_state(&sb);
177 error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
184 * @brief Event handler called when a virtual file system is mounted.
186 * We need to record the file system identifier in the MAC per-policy slot
187 * assigned to veriexec, so we have a key to use in order to reference the
188 * mount point in the meta-data store.
190 * @param arg unused argument
191 * @param mp mount point that is being mounted
192 * @param fsrootvp vnode of the file system root
193 * @param td calling thread
196 mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
197 struct vnode *fsrootvp, struct thread *td)
202 error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
206 SLOT_SET(mp->mnt_label, va.va_fsid);
207 MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p",
208 (uintmax_t)va.va_fsid, mp);
213 * @brief Event handler called when a virtual file system is unmounted.
215 * If we recorded a file system identifier in the MAC per-policy slot assigned
216 * to veriexec, then we need to tell the meta-data store to clean up.
218 * @param arg unused argument
219 * @param mp mount point that is being unmounted
220 * @param td calling thread
223 mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
228 fsid = SLOT(mp->mnt_label);
230 MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount",
232 mac_veriexec_metadata_unmounted(fsid, td);
238 * @brief The mount point is being initialized, set the value in the MAC
239 * per-policy slot for veriexec to zero.
241 * @note A value of zero in this slot indicates no file system identifier
244 * @param label the label that is being initialized
247 mac_veriexec_mount_init_label(struct label *label)
255 * @brief The mount-point is being destroyed, reset the value in the MAC
256 * per-policy slot for veriexec back to zero.
258 * @note A value of zero in this slot indicates no file system identifier
261 * @param label the label that is being destroyed
264 mac_veriexec_mount_destroy_label(struct label *label)
272 * @brief The vnode label is being initialized, set the value in the MAC
273 * per-policy slot for veriexec to @c FINGERPRINT_INVALID
275 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
277 * @param label the label that is being initialized
280 mac_veriexec_vnode_init_label(struct label *label)
283 SLOT_SET(label, FINGERPRINT_INVALID);
288 * @brief The vnode label is being destroyed, reset the value in the MAC
289 * per-policy slot for veriexec back to @c FINGERPRINT_INVALID
291 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
293 * @param label the label that is being destroyed
296 mac_veriexec_vnode_destroy_label(struct label *label)
299 SLOT_SET(label, FINGERPRINT_INVALID);
304 * @brief Copy the value in the MAC per-policy slot assigned to veriexec from
305 * the @p src label to the @p dest label
308 mac_veriexec_copy_label(struct label *src, struct label *dest)
311 SLOT_SET(dest, SLOT(src));
316 * @brief Check if the requested process can be debugged
318 * @param cred credentials to use
319 * @param p process to debug
321 * @return 0 if debugging is allowed, otherwise an error code.
324 mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
328 /* If we are not enforcing veriexec, nothing for us to check */
329 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
332 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
336 error = (flags & (VERIEXEC_NOTRACE|VERIEXEC_TRUSTED)) ? EACCES : 0;
337 MAC_VERIEXEC_DBG(4, "%s flags=%#x error=%d", __func__, flags, error);
344 * @brief A KLD load has been requested and needs to be validated.
346 * @param cred credentials to use
347 * @param vp vnode of the KLD that has been requested
348 * @param vlabel vnode label assigned to the vnode
350 * @return 0 if the KLD load is allowed, otherwise an error code.
353 mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
354 struct label *vlabel)
357 struct thread *td = curthread;
358 fingerprint_status_t status;
362 * If we are not actively enforcing, allow it
364 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
367 /* Get vnode attributes */
368 error = VOP_GETATTR(vp, &va, cred);
373 * Fetch the fingerprint status for the vnode
374 * (starting with files first)
376 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
377 VERIEXEC_FILES_FIRST);
378 if (error && error != EAUTH)
382 * By now we should have status...
384 status = mac_veriexec_get_fingerprint_status(vp);
386 case FINGERPRINT_FILE:
387 case FINGERPRINT_VALID:
388 case FINGERPRINT_INDIRECT:
394 * kldload should fail unless there is a valid fingerprint
397 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, "
398 "file %ju.%ju\n", status, (uintmax_t)va.va_fsid,
399 (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
403 /* Everything is good, allow the KLD to be loaded */
409 * @brief Check privileges that veriexec needs to be concerned about.
411 * The following privileges are checked by this function:
412 * - PRIV_KMEM_WRITE\n
413 * Check if writes to /dev/mem and /dev/kmem are allowed\n
414 * (Only trusted processes are allowed)
415 * - PRIV_VERIEXEC_CONTROL\n
416 * Check if manipulating veriexec is allowed\n
417 * (only trusted processes are allowed)
419 * @param cred credentials to use
420 * @param priv privilege to check
422 * @return 0 if the privilege is allowed, error code otherwise.
425 mac_veriexec_priv_check(struct ucred *cred, int priv)
429 /* If we are not enforcing veriexec, nothing for us to check */
430 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
435 case PRIV_KMEM_WRITE:
436 case PRIV_VERIEXEC_CONTROL:
438 * Do not allow writing to memory or manipulating veriexec,
441 if (mac_veriexec_proc_is_trusted(cred, curproc) == 0 &&
442 mac_priv_grant(cred, priv) != 0)
444 MAC_VERIEXEC_DBG(4, "%s priv=%d error=%d", __func__, priv,
455 * @brief Check if the requested sysctl should be allowed
457 * @param cred credentials to use
458 * @param oidp sysctl OID
459 * @param arg1 first sysctl argument
460 * @param arg2 second sysctl argument
461 * @param req sysctl request information
463 * @return 0 if the sysctl should be allowed, otherwise an error code.
466 mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp,
467 void *arg1, int arg2, struct sysctl_req *req)
469 struct sysctl_oid *oid;
471 /* If we are not enforcing veriexec, nothing for us to check */
472 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
476 if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
477 return (EPERM); /* XXX call mac_veriexec_priv_check? */
484 * @brief A program is being executed and needs to be validated.
486 * @param cred credentials to use
487 * @param vp vnode of the program that is being executed
488 * @param label vnode label assigned to the vnode
489 * @param imgp parameters for the image to be executed
490 * @param execlabel optional exec label
492 * @return 0 if the program should be allowed to execute, otherwise an error
496 mac_veriexec_vnode_check_exec(struct ucred *cred __unused,
497 struct vnode *vp __unused, struct label *label __unused,
498 struct image_params *imgp, struct label *execlabel __unused)
500 struct thread *td = curthread;
503 error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
508 * @brief Check fingerprint for the specified vnode and validate it
510 * @param cred credentials to use
511 * @param vp vnode of the file
512 * @param accmode access mode to check (read, write, append, create,
515 * @return 0 if the file validated, otherwise an error code.
518 mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
521 struct thread *td = curthread;
522 fingerprint_status_t status;
525 /* Get vnode attributes */
526 error = VOP_GETATTR(vp, &va, cred);
530 /* Get the fingerprint status for the file */
531 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
532 VERIEXEC_FILES_FIRST);
533 if (error && error != EAUTH)
537 * By now we should have status...
539 status = mac_veriexec_get_fingerprint_status(vp);
540 if (accmode & VWRITE) {
542 * If file has a fingerprint then deny the write request,
543 * otherwise invalidate the status so we don't keep checking
544 * for the file having a fingerprint.
547 case FINGERPRINT_FILE:
548 case FINGERPRINT_VALID:
549 case FINGERPRINT_INDIRECT:
551 "attempted write to fingerprinted file for dev "
552 "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid,
553 (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
559 if (accmode & VVERIFY) {
561 case FINGERPRINT_FILE:
562 case FINGERPRINT_VALID:
563 case FINGERPRINT_INDIRECT:
568 /* Allow for overriding verification requirement */
569 if (mac_priv_grant(cred, PRIV_VERIEXEC_NOVERIFY) == 0)
572 * Caller wants open to fail unless there is a valid
573 * fingerprint registered.
575 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev "
576 "%ju, file %ju.%ju\n", status,
577 (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid,
578 (uintmax_t)va.va_gen);
586 * @brief Opening a file has been requested and may need to be validated.
588 * @param cred credentials to use
589 * @param vp vnode of the file to open
590 * @param label vnode label assigned to the vnode
591 * @param accmode access mode to use for opening the file (read, write,
592 * append, create, verify, etc.)
594 * @return 0 if opening the file should be allowed, otherwise an error code.
597 mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
598 struct label *label __unused, accmode_t accmode)
603 * Look for the file on the fingerprint lists iff it has not been seen
606 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
609 error = mac_veriexec_check_vp(cred, vp, accmode);
614 * @brief Unlink on a file has been requested and may need to be validated.
616 * @param cred credentials to use
617 * @param dvp parent directory for file vnode vp
618 * @param dlabel vnode label assigned to the directory vnode
619 * @param vp vnode of the file to unlink
620 * @param label vnode label assigned to the vnode
621 * @param cnp component name for vp
624 * @return 0 if opening the file should be allowed, otherwise an error code.
627 mac_veriexec_vnode_check_unlink(struct ucred *cred, struct vnode *dvp __unused,
628 struct label *dvplabel __unused, struct vnode *vp,
629 struct label *label __unused, struct componentname *cnp __unused)
634 * Look for the file on the fingerprint lists iff it has not been seen
637 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
640 error = mac_veriexec_check_vp(cred, vp, VVERIFY);
643 * The target is verified, so disallow replacement.
646 "(UNLINK) attempted to unlink a protected file (euid: %u)", cred->cr_uid);
654 * @brief Rename the file has been requested and may need to be validated.
656 * @param cred credentials to use
657 * @param dvp parent directory for file vnode vp
658 * @param dlabel vnode label assigned to the directory vnode
659 * @param vp vnode of the file to rename
660 * @param label vnode label assigned to the vnode
661 * @param cnp component name for vp
664 * @return 0 if opening the file should be allowed, otherwise an error code.
667 mac_veriexec_vnode_check_rename_from(struct ucred *cred,
668 struct vnode *dvp __unused, struct label *dvplabel __unused,
669 struct vnode *vp, struct label *label __unused,
670 struct componentname *cnp __unused)
675 * Look for the file on the fingerprint lists iff it has not been seen
678 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
681 error = mac_veriexec_check_vp(cred, vp, VVERIFY);
684 * The target is verified, so disallow replacement.
687 "(RENAME_FROM) attempted to rename a protected file (euid: %u)", cred->cr_uid);
695 * @brief Rename to file into the directory (overwrite the file name) has been
696 * requested and may need to be validated.
698 * @param cred credentials to use
699 * @param dvp parent directory for file vnode vp
700 * @param dlabel vnode label assigned to the directory vnode
701 * @param vp vnode of the overwritten file
702 * @param label vnode label assigned to the vnode
703 * @param samedir 1 if the source and destination directories are the same
704 * @param cnp component name for vp
707 * @return 0 if opening the file should be allowed, otherwise an error code.
710 mac_veriexec_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp __unused,
711 struct label *dvplabel __unused, struct vnode *vp,
712 struct label *label __unused, int samedir __unused,
713 struct componentname *cnp __unused)
717 * If there is no existing file to overwrite, vp and label will be
724 * Look for the file on the fingerprint lists iff it has not been seen
727 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
730 error = mac_veriexec_check_vp(cred, vp, VVERIFY);
733 * The target is verified, so disallow replacement.
736 "(RENAME_TO) attempted to overwrite a protected file (euid: %u)", cred->cr_uid);
744 * @brief Check mode changes on file to ensure they should be allowed.
746 * We cannot allow chmod of SUID or SGID on verified files.
748 * @param cred credentials to use
749 * @param vp vnode of the file to open
750 * @param label vnode label assigned to the vnode
751 * @param mode mode flags to set
753 * @return 0 if the mode change should be allowed, EAUTH otherwise.
756 mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
757 struct label *label __unused, mode_t mode)
761 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
765 * Prohibit chmod of verified set-[gu]id file.
767 error = mac_veriexec_check_vp(cred, vp, VVERIFY);
768 if (error == EAUTH) /* target not verified */
770 if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
778 * @brief Initialize the mac_veriexec MAC policy
780 * @param mpc MAC policy configuration
783 mac_veriexec_init(struct mac_policy_conf *mpc __unused)
785 /* Initialize state */
786 mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
788 /* Initialize meta-data storage */
789 mac_veriexec_metadata_init();
791 /* Initialize fingerprint ops */
792 mac_veriexec_fingerprint_init();
794 /* Register event handlers */
795 EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL,
796 EVENTHANDLER_PRI_FIRST);
797 EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL,
798 EVENTHANDLER_PRI_LAST);
800 /* Fetch tunable value in kernel env and define a corresponding read-only sysctl */
801 mac_veriexec_block_unlink = 0;
802 TUNABLE_INT_FETCH("security.mac.veriexec.block_unlink", &mac_veriexec_block_unlink);
803 SYSCTL_INT(_security_mac_veriexec, OID_AUTO, block_unlink,
804 CTLFLAG_RDTUN, &mac_veriexec_block_unlink, 0, "Veriexec unlink protection");
806 /* Check if unlink control is activated via tunable value */
807 if (!mac_veriexec_block_unlink)
808 mac_veriexec_ops.mpo_vnode_check_unlink = NULL;
811 #ifdef COMPAT_FREEBSD32
812 struct mac_veriexec_syscall_params32 {
813 char fp_type[VERIEXEC_FPTYPELEN];
814 unsigned char fingerprint[MAXFINGERPRINTLEN];
815 char label[MAXLABELLEN];
820 struct mac_veriexec_syscall_params_args32 {
824 } u; /* input only */
825 uint32_t params; /* result */
831 * @brief MAC policy-specific syscall for mac_veriexec
833 * The following syscalls are implemented:
834 * - @c MAC_VERIEXEC_CHECK_SYSCALL
835 * Check if the file referenced by a file descriptor has a fingerprint
836 * registered in the meta-data store.
838 * @param td calling thread
839 * @param call system call number
840 * @param arg arugments to the syscall
842 * @return 0 on success, otherwise an error code.
845 mac_veriexec_syscall(struct thread *td, int call, void *arg)
847 struct image_params img;
852 struct mac_veriexec_syscall_params_args pargs;
853 struct mac_veriexec_syscall_params result;
854 #ifdef COMPAT_FREEBSD32
855 struct mac_veriexec_syscall_params_args32 pargs32;
856 struct mac_veriexec_syscall_params32 result32;
858 struct mac_veriexec_file_info *ip;
860 struct vnode *textvp;
861 int error, flags, proc_locked;
867 case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
868 case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
869 #ifdef COMPAT_FREEBSD32
870 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
871 error = copyin(arg, &pargs32, sizeof(pargs32));
874 bzero(&pargs, sizeof(pargs));
876 case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
877 CP(pargs32, pargs, u.pid);
879 case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
880 PTRIN_CP(pargs32, pargs, u.filename);
883 PTRIN_CP(pargs32, pargs, params);
886 error = copyin(arg, &pargs, sizeof(pargs));
893 case MAC_VERIEXEC_CHECK_FD_SYSCALL:
894 /* Get the vnode associated with the file descriptor passed */
895 error = getvnode(td, (uintptr_t) arg,
896 cap_rights_init_one(&rights, CAP_READ), &fp);
899 if (fp->f_type != DTYPE_VNODE) {
900 MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: "
901 "file is not vnode type (type=0x%x)",
908 * setup the bits of image_params that are used by
909 * mac_veriexec_check_fingerprint().
911 bzero(&img, sizeof(img));
912 img.proc = td->td_proc;
913 img.vp = fp->f_vnode;
917 * Get vnode attributes
918 * (need to obtain a lock on the vnode first)
920 vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
921 error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred);
925 MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: "
926 "va_mode=%o, check_files=%d\n", va.va_mode,
927 ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0));
928 error = mac_veriexec_fingerprint_check_image(&img,
929 ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td);
931 /* Release the lock we obtained earlier */
936 case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
937 /* Look up the path to get the vnode */
939 FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1,
942 error = vn_open(&nd, &flags, 0, NULL);
947 /* Check the fingerprint status of the vnode */
948 error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
949 /* nd.ni_vp cleaned up below */
951 case MAC_VERIEXEC_GET_PARAMS_PID_SYSCALL:
952 if (pargs.u.pid == 0 || pargs.u.pid == curproc->p_pid) {
955 proc = pfind(pargs.u.pid);
960 textvp = proc->p_textvp;
962 case MAC_VERIEXEC_GET_PARAMS_PATH_SYSCALL:
963 if (textvp == NULL) {
964 /* Look up the path to get the vnode */
965 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
966 UIO_USERSPACE, pargs.u.filename);
968 error = vn_open(&nd, &flags, 0, NULL);
975 error = VOP_GETATTR(textvp, &va, curproc->p_ucred);
981 error = mac_veriexec_metadata_get_file_info(va.va_fsid,
982 va.va_fileid, va.va_gen, NULL, &ip, FALSE);
986 #ifdef COMPAT_FREEBSD32
987 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
988 bzero(&result32, sizeof(result32));
989 result32.flags = ip->flags;
990 strlcpy(result32.fp_type, ip->ops->type, sizeof(result32.fp_type));
991 result.labellen = ip->labellen;
992 CP(result, result32, labellen);
993 if (ip->labellen > 0)
994 strlcpy(result32.label, ip->label, sizeof(result32.label));
995 result32.label[result.labellen] = '\0';
996 memcpy(result32.fingerprint, ip->fingerprint,
997 ip->ops->digest_len);
999 error = copyout(&result32, pargs.params, sizeof(result32));
1003 bzero(&result, sizeof(result));
1004 result.flags = ip->flags;
1005 strlcpy(result.fp_type, ip->ops->type, sizeof(result.fp_type));
1006 result.labellen = ip->labellen;
1007 if (ip->labellen > 0)
1008 strlcpy(result.label, ip->label, sizeof(result.label));
1009 result.label[result.labellen] = '\0';
1010 memcpy(result.fingerprint, ip->fingerprint,
1011 ip->ops->digest_len);
1013 error = copyout(&result, pargs.params, sizeof(result));
1018 if (nd.ni_vp != NULL) {
1019 VOP_UNLOCK(nd.ni_vp);
1020 vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
1025 static struct mac_policy_ops mac_veriexec_ops =
1027 .mpo_init = mac_veriexec_init,
1028 .mpo_kld_check_load = mac_veriexec_kld_check_load,
1029 .mpo_mount_destroy_label = mac_veriexec_mount_destroy_label,
1030 .mpo_mount_init_label = mac_veriexec_mount_init_label,
1031 .mpo_priv_check = mac_veriexec_priv_check,
1032 .mpo_proc_check_debug = mac_veriexec_proc_check_debug,
1033 .mpo_syscall = mac_veriexec_syscall,
1034 .mpo_system_check_sysctl = mac_veriexec_sysctl_check,
1035 .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec,
1036 .mpo_vnode_check_open = mac_veriexec_vnode_check_open,
1037 .mpo_vnode_check_unlink = mac_veriexec_vnode_check_unlink,
1038 .mpo_vnode_check_rename_to = mac_veriexec_vnode_check_rename_to,
1039 .mpo_vnode_check_rename_from = mac_veriexec_vnode_check_rename_from,
1040 .mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode,
1041 .mpo_vnode_copy_label = mac_veriexec_copy_label,
1042 .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,
1043 .mpo_vnode_init_label = mac_veriexec_vnode_init_label,
1046 MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
1047 MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
1048 MODULE_VERSION(mac_veriexec, MAC_VERIEXEC_VERSION);
1050 static struct vnode *
1051 mac_veriexec_bottom_vnode(struct vnode *vp)
1053 struct vnode *ldvp = NULL;
1056 * XXX This code is bogus. nullfs is not the only stacking
1057 * filesystem. Less bogus code would add a VOP to reach bottom
1058 * vnode and would not make assumptions how to get there.
1060 if (vp->v_mount != NULL &&
1061 strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0)
1062 ldvp = NULLVPTOLOWERVP(vp);
1067 * @brief Get the fingerprint status set on a vnode.
1069 * @param vp vnode to obtain fingerprint status from
1071 * @return Fingerprint status assigned to the vnode.
1073 fingerprint_status_t
1074 mac_veriexec_get_fingerprint_status(struct vnode *vp)
1076 fingerprint_status_t fps;
1079 fps = SLOT(vp->v_label);
1081 case FINGERPRINT_VALID:
1082 case FINGERPRINT_INDIRECT:
1083 case FINGERPRINT_FILE:
1086 /* we may need to recurse */
1087 ldvp = mac_veriexec_bottom_vnode(vp);
1089 return mac_veriexec_get_fingerprint_status(ldvp);
1096 * @brief Get the current verified execution subsystem state.
1098 * @return Current set of verified execution subsystem state flags.
1101 mac_veriexec_get_state(void)
1104 return (mac_veriexec_state);
1108 * @brief Determine if the verified execution subsystem state has specific
1111 * @param state mask of flags to check
1113 * @return State flags set within the masked bits
1116 mac_veriexec_in_state(int state)
1119 return (mac_veriexec_state & state);
1123 * @brief Set the fingerprint status for a vnode
1125 * Fingerprint status is stored in the MAC per-policy slot assigned to
1128 * @param vp vnode to store the fingerprint status on
1129 * @param fp_status fingerprint status to store
1132 mac_veriexec_set_fingerprint_status(struct vnode *vp,
1133 fingerprint_status_t fp_status)
1137 /* recurse until we find the real storage */
1138 ldvp = mac_veriexec_bottom_vnode(vp);
1140 mac_veriexec_set_fingerprint_status(ldvp, fp_status);
1143 SLOT_SET(vp->v_label, fp_status);
1147 * @brief Set verified execution subsystem state flags
1149 * @note Flags can only be added to the current state, not removed.
1151 * @param state state flags to add to the current state
1154 mac_veriexec_set_state(int state)
1157 mac_veriexec_state |= state;
1161 * @brief Determine if the process is trusted
1163 * @param cred credentials to use
1164 * @param p the process in question
1166 * @return 1 if the process is trusted, otherwise 0.
1169 mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
1171 int already_locked, error, flags;
1173 /* Make sure we lock the process if we do not already have the lock */
1174 already_locked = PROC_LOCKED(p);
1175 if (!already_locked)
1178 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
1180 /* Unlock the process if we locked it previously */
1181 if (!already_locked)
1184 /* Any errors, deny access */
1188 /* Check that the trusted flag is set */
1189 return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);