4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019 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 #include <fs/nullfs/null.h>
54 #include <security/mac/mac_policy.h>
56 #include "mac_veriexec.h"
57 #include "mac_veriexec_internal.h"
60 mac_label_get((l), mac_veriexec_slot)
61 #define SLOT_SET(l, v) \
62 mac_label_set((l), mac_veriexec_slot, (v))
65 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) \
67 VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt \
68 "\n", ##__VA_ARGS__)); \
71 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...)
74 static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
75 static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
77 SYSCTL_DECL(_security_mac);
79 SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW, 0,
80 "MAC/veriexec policy controls");
82 int mac_veriexec_debug;
83 SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
84 &mac_veriexec_debug, 0, "Debug level");
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");
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");
95 static int mac_veriexec_slot;
97 MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
101 * @brief Handler for security.mac.veriexec.db sysctl
103 * Display a human-readable form of the current fingerprint database.
106 sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
111 error = sysctl_wire_old_buffer(req, 0);
115 sbuf_new_for_sysctl(&sb, NULL, 1024, req);
116 mac_veriexec_metadata_print_db(&sb);
117 error = sbuf_finish(&sb);
125 * @brief Generate human-readable output about the current verified execution
128 * @param sbp sbuf to write output to
131 mac_veriexec_print_state(struct sbuf *sbp)
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)
150 * @brief Handler for security.mac.veriexec.state sysctl
152 * Display a human-readable form of the current verified execution subsystem
156 sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
161 sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
162 mac_veriexec_print_state(&sb);
165 error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
172 * @brief Event handler called when a virtual file system is mounted.
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.
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
184 mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
185 struct vnode *fsrootvp, struct thread *td)
190 error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
194 SLOT_SET(mp->mnt_label, va.va_fsid);
196 MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p",
197 (uintmax_t)va.va_fsid, mp);
203 * @brief Event handler called when a virtual file system is unmounted.
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.
208 * @param arg unused argument
209 * @param mp mount point that is being unmounted
210 * @param td calling thread
213 mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
218 fsid = SLOT(mp->mnt_label);
220 MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount",
222 mac_veriexec_metadata_unmounted(fsid, td);
228 * @brief The mount point is being initialized, set the value in the MAC
229 * per-policy slot for veriexec to zero.
231 * @note A value of zero in this slot indicates no file system identifier
234 * @param label the label that is being initialized
237 mac_veriexec_mount_init_label(struct label *label)
245 * @brief The mount-point is being destroyed, reset the value in the MAC
246 * per-policy slot for veriexec back to zero.
248 * @note A value of zero in this slot indicates no file system identifier
251 * @param label the label that is being destroyed
254 mac_veriexec_mount_destroy_label(struct label *label)
262 * @brief The vnode label is being initialized, set the value in the MAC
263 * per-policy slot for veriexec to @c FINGERPRINT_INVALID
265 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
267 * @param label the label that is being initialized
270 mac_veriexec_vnode_init_label(struct label *label)
273 SLOT_SET(label, FINGERPRINT_INVALID);
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
281 * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
283 * @param label the label that is being destroyed
286 mac_veriexec_vnode_destroy_label(struct label *label)
289 SLOT_SET(label, FINGERPRINT_INVALID);
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
298 mac_veriexec_copy_label(struct label *src, struct label *dest)
301 SLOT_SET(dest, SLOT(src));
306 * @brief Check if the requested process can be debugged
308 * @param cred credentials to use
309 * @param p process to debug
311 * @return 0 if debugging is allowed, otherwise an error code.
314 mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
318 /* If we are not enforcing veriexec, nothing for us to check */
319 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
322 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
326 return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0);
331 * @brief A KLD load has been requested and needs to be validated.
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
337 * @return 0 if the KLD load is allowed, otherwise an error code.
340 mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
341 struct label *vlabel)
344 struct thread *td = curthread;
345 fingerprint_status_t status;
349 * If we are not actively enforcing, allow it
351 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
354 /* Get vnode attributes */
355 error = VOP_GETATTR(vp, &va, cred);
360 * Fetch the fingerprint status for the vnode
361 * (starting with files first)
363 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
364 VERIEXEC_FILES_FIRST);
365 if (error && error != EAUTH)
369 * By now we should have status...
371 status = mac_veriexec_get_fingerprint_status(vp);
373 case FINGERPRINT_FILE:
374 case FINGERPRINT_VALID:
375 case FINGERPRINT_INDIRECT:
381 * kldload should fail unless there is a valid fingerprint
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);
390 /* Everything is good, allow the KLD to be loaded */
396 * @brief Check privileges that veriexec needs to be concerned about.
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)
403 * @param cred credentials to use
404 * @param priv privilege to check
406 * @return 0 if the privilege is allowed, error code otherwise.
409 mac_veriexec_priv_check(struct ucred *cred, int priv)
412 /* If we are not enforcing veriexec, nothing for us to check */
413 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
417 case PRIV_KMEM_WRITE:
418 if (!mac_veriexec_proc_is_trusted(cred, curproc))
428 mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp,
429 void *arg1, int arg2, struct sysctl_req *req)
431 struct sysctl_oid *oid;
433 /* If we are not enforcing veriexec, nothing for us to check */
434 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
438 if (oid->oid_kind & CTLFLAG_SECURE) {
439 return (EPERM); /* XXX call mac_veriexec_priv_check? */
446 * @brief A program is being executed and needs to be validated.
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
454 * @return 0 if the program should be allowed to execute, otherwise an error
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)
462 struct thread *td = curthread;
465 error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
470 * @brief Check fingerprint for the specified vnode and validate it
472 * @param cred credentials to use
473 * @param vp vnode of the file
474 * @param accmode access mode to check (read, write, append, create,
477 * @return 0 if the file validated, otherwise an error code.
480 mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
483 struct thread *td = curthread;
484 fingerprint_status_t status;
487 /* Get vnode attributes */
488 error = VOP_GETATTR(vp, &va, cred);
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)
499 * By now we should have status...
501 status = mac_veriexec_get_fingerprint_status(vp);
502 if (accmode & VWRITE) {
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.
509 case FINGERPRINT_FILE:
510 case FINGERPRINT_VALID:
511 case FINGERPRINT_INDIRECT:
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);
521 if (accmode & VVERIFY) {
523 case FINGERPRINT_FILE:
524 case FINGERPRINT_VALID:
525 case FINGERPRINT_INDIRECT:
531 * Caller wants open to fail unless there is a valid
532 * fingerprint registered.
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);
545 * @brief Opening a file has been requested and may need to be validated.
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.)
553 * @return 0 if opening the file should be allowed, otherwise an error code.
556 mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
557 struct label *label __unused, accmode_t accmode)
562 * Look for the file on the fingerprint lists iff it has not been seen
565 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
568 error = mac_veriexec_check_vp(cred, vp, accmode);
573 * @brief Check mode changes on file to ensure they should be allowed.
575 * We cannot allow chmod of SUID or SGID on verified files.
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
582 * @return 0 if the mode change should be allowed, EAUTH otherwise.
585 mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
586 struct label *label __unused, mode_t mode)
590 if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
594 * Do not allow chmod (set-[gu]id) of verified file
596 error = mac_veriexec_check_vp(cred, vp, VVERIFY);
597 if (error == EAUTH) /* it isn't verified */
599 if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
606 * @brief Initialize the mac_veriexec MAC policy
608 * @param mpc MAC policy configuration
611 mac_veriexec_init(struct mac_policy_conf *mpc __unused)
613 /* Initialize state */
614 mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
616 /* Initialize meta-data storage */
617 mac_veriexec_metadata_init();
619 /* Initialize fingerprint ops */
620 mac_veriexec_fingerprint_init();
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);
631 * @brief MAC policy-specific syscall for mac_veriexec
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.
638 * @param td calling thread
639 * @param call system call number
640 * @param arg arugments to the syscall
642 * @return 0 on success, otherwise an error code.
645 mac_veriexec_syscall(struct thread *td, int call, void *arg)
647 struct image_params img;
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,
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)",
670 * setup the bits of image_params that are used by
671 * mac_veriexec_check_fingerprint().
673 bzero(&img, sizeof(img));
674 img.proc = td->td_proc;
675 img.vp = fp->f_vnode;
679 * Get vnode attributes
680 * (need to obtain a lock on the vnode first)
682 vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
683 error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred);
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);
693 /* Release the lock we obtained earlier */
694 VOP_UNLOCK(img.vp, 0);
698 case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
699 /* Look up the path to get the vnode */
701 FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1,
702 UIO_USERSPACE, arg, td);
706 NDFREE(&nd, NDF_ONLY_PNBUF);
708 /* Check the fingerprint status of the vnode */
709 error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
718 static struct mac_policy_ops mac_veriexec_ops =
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,
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);
741 * @brief Get the fingerprint status set on a vnode.
743 * @param vp vnode to obtain fingerprint status from
745 * @return Fingerprint status assigned to the vnode.
748 mac_veriexec_get_fingerprint_status(struct vnode *vp)
750 fingerprint_status_t fps;
752 fps = SLOT(vp->v_label);
754 case FINGERPRINT_VALID:
755 case FINGERPRINT_INDIRECT:
756 case FINGERPRINT_FILE:
759 /* we may need to recurse */
760 if (strcmp(vp->v_tag, "null") == 0) {
763 ldvp = NULLVPTOLOWERVP(vp);
764 return mac_veriexec_get_fingerprint_status(ldvp);
772 * @brief Get the current verified execution subsystem state.
774 * @return Current set of verified execution subsystem state flags.
777 mac_veriexec_get_state(void)
780 return (mac_veriexec_state);
784 * @brief Determine if the verified execution subsystem state has specific
787 * @param state mask of flags to check
789 * @return State flags set within the masked bits
792 mac_veriexec_in_state(int state)
795 return (mac_veriexec_state & state);
799 * @brief Set the fingerprint status for a vnode
801 * Fingerprint status is stored in the MAC per-policy slot assigned to
804 * @param vp vnode to store the fingerprint status on
805 * @param fp_status fingerprint status to store
808 mac_veriexec_set_fingerprint_status(struct vnode *vp,
809 fingerprint_status_t fp_status)
812 /* recurse until we find the real storage */
813 if (strcmp(vp->v_tag, "null") == 0) {
816 ldvp = NULLVPTOLOWERVP(vp);
817 mac_veriexec_set_fingerprint_status(ldvp, fp_status);
820 SLOT_SET(vp->v_label, fp_status);
824 * @brief Set verified execution subsystem state flags
826 * @note Flags can only be added to the current state, not removed.
828 * @param state state flags to add to the current state
831 mac_veriexec_set_state(int state)
834 mac_veriexec_state |= state;
838 * @brief Determine if the process is trusted
840 * @param cred credentials to use
841 * @param p the process in question
843 * @return 1 if the process is trusted, otherwise 0.
846 mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
848 int already_locked, error, flags;
850 /* Make sure we lock the process if we do not already have the lock */
851 already_locked = PROC_LOCKED(p);
855 error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
857 /* Unlock the process if we locked it previously */
861 /* Any errors, deny access */
865 /* Check that the trusted flag is set */
866 return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);