1fb47a376SStephen J. Kiernan /* 2fb47a376SStephen J. Kiernan * $FreeBSD$ 3fb47a376SStephen J. Kiernan * 4ed377cf4SStephen J. Kiernan * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019 Juniper Networks, Inc. 5fb47a376SStephen J. Kiernan * All rights reserved. 6fb47a376SStephen J. Kiernan * 7fb47a376SStephen J. Kiernan * Redistribution and use in source and binary forms, with or without 8fb47a376SStephen J. Kiernan * modification, are permitted provided that the following conditions 9fb47a376SStephen J. Kiernan * are met: 10fb47a376SStephen J. Kiernan * 1. Redistributions of source code must retain the above copyright 11fb47a376SStephen J. Kiernan * notice, this list of conditions and the following disclaimer. 12fb47a376SStephen J. Kiernan * 2. Redistributions in binary form must reproduce the above copyright 13fb47a376SStephen J. Kiernan * notice, this list of conditions and the following disclaimer in the 14fb47a376SStephen J. Kiernan * documentation and/or other materials provided with the distribution. 15fb47a376SStephen J. Kiernan * 16fb47a376SStephen J. Kiernan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17fb47a376SStephen J. Kiernan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18fb47a376SStephen J. Kiernan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19fb47a376SStephen J. Kiernan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20fb47a376SStephen J. Kiernan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21fb47a376SStephen J. Kiernan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22fb47a376SStephen J. Kiernan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23fb47a376SStephen J. Kiernan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24fb47a376SStephen J. Kiernan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25fb47a376SStephen J. Kiernan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26fb47a376SStephen J. Kiernan * SUCH DAMAGE. 27fb47a376SStephen J. Kiernan */ 28fb47a376SStephen J. Kiernan 29fb47a376SStephen J. Kiernan #include <sys/cdefs.h> 30fb47a376SStephen J. Kiernan 31fb47a376SStephen J. Kiernan #include "opt_capsicum.h" 32fb47a376SStephen J. Kiernan #include "opt_mac.h" 33fb47a376SStephen J. Kiernan 34fb47a376SStephen J. Kiernan #include <sys/param.h> 35fb47a376SStephen J. Kiernan #include <sys/systm.h> 36fb47a376SStephen J. Kiernan #include <sys/capsicum.h> 37fb47a376SStephen J. Kiernan #include <sys/eventhandler.h> 38fb47a376SStephen J. Kiernan #include <sys/fcntl.h> 39fb47a376SStephen J. Kiernan #include <sys/file.h> 40fb47a376SStephen J. Kiernan #include <sys/filedesc.h> 41fb47a376SStephen J. Kiernan #include <sys/imgact.h> 42fb47a376SStephen J. Kiernan #include <sys/jail.h> 43fb47a376SStephen J. Kiernan #include <sys/kernel.h> 44fb47a376SStephen J. Kiernan #include <sys/mac.h> 45fb47a376SStephen J. Kiernan #include <sys/mount.h> 46fb47a376SStephen J. Kiernan #include <sys/namei.h> 47fb47a376SStephen J. Kiernan #include <sys/priv.h> 48fb47a376SStephen J. Kiernan #include <sys/proc.h> 49fb47a376SStephen J. Kiernan #include <sys/sbuf.h> 50fb47a376SStephen J. Kiernan #include <sys/stat.h> 51fb47a376SStephen J. Kiernan #include <sys/sysctl.h> 52fb47a376SStephen J. Kiernan #include <sys/vnode.h> 53fb47a376SStephen J. Kiernan #include <fs/nullfs/null.h> 54fb47a376SStephen J. Kiernan #include <security/mac/mac_policy.h> 55fb47a376SStephen J. Kiernan 56fb47a376SStephen J. Kiernan #include "mac_veriexec.h" 57fb47a376SStephen J. Kiernan #include "mac_veriexec_internal.h" 58fb47a376SStephen J. Kiernan 59fb47a376SStephen J. Kiernan #define SLOT(l) \ 60fb47a376SStephen J. Kiernan mac_label_get((l), mac_veriexec_slot) 61fb47a376SStephen J. Kiernan #define SLOT_SET(l, v) \ 62fb47a376SStephen J. Kiernan mac_label_set((l), mac_veriexec_slot, (v)) 63fb47a376SStephen J. Kiernan 64fb47a376SStephen J. Kiernan #ifdef MAC_DEBUG 65fb47a376SStephen J. Kiernan #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) \ 66fb47a376SStephen J. Kiernan do { \ 67fb47a376SStephen J. Kiernan VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt \ 68fb47a376SStephen J. Kiernan "\n", ##__VA_ARGS__)); \ 69fb47a376SStephen J. Kiernan } while(0) 70fb47a376SStephen J. Kiernan #else 71fb47a376SStephen J. Kiernan #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...) 72fb47a376SStephen J. Kiernan #endif 73fb47a376SStephen J. Kiernan 74fb47a376SStephen J. Kiernan static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS); 75fb47a376SStephen J. Kiernan static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS); 76fb47a376SStephen J. Kiernan 77fb47a376SStephen J. Kiernan SYSCTL_DECL(_security_mac); 78fb47a376SStephen J. Kiernan 79*7029da5cSPawel Biernacki SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 80fb47a376SStephen J. Kiernan "MAC/veriexec policy controls"); 81fb47a376SStephen J. Kiernan 82fb47a376SStephen J. Kiernan int mac_veriexec_debug; 83fb47a376SStephen J. Kiernan SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW, 84fb47a376SStephen J. Kiernan &mac_veriexec_debug, 0, "Debug level"); 85fb47a376SStephen J. Kiernan 86fb47a376SStephen J. Kiernan static int mac_veriexec_state; 87fb47a376SStephen J. Kiernan SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state, 88*7029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 89*7029da5cSPawel Biernacki 0, 0, sysctl_mac_veriexec_state, "A", 90fb47a376SStephen J. Kiernan "Verified execution subsystem state"); 91fb47a376SStephen J. Kiernan 92fb47a376SStephen J. Kiernan SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db, 93*7029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT, 94*7029da5cSPawel Biernacki 0, 0, sysctl_mac_veriexec_db, 95fb47a376SStephen J. Kiernan "A", "Verified execution fingerprint database"); 96fb47a376SStephen J. Kiernan 97fb47a376SStephen J. Kiernan static int mac_veriexec_slot; 98fb47a376SStephen J. Kiernan 99fb47a376SStephen J. Kiernan MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data"); 100fb47a376SStephen J. Kiernan 101fb47a376SStephen J. Kiernan /** 102fb47a376SStephen J. Kiernan * @internal 103fb47a376SStephen J. Kiernan * @brief Handler for security.mac.veriexec.db sysctl 104fb47a376SStephen J. Kiernan * 105fb47a376SStephen J. Kiernan * Display a human-readable form of the current fingerprint database. 106fb47a376SStephen J. Kiernan */ 107fb47a376SStephen J. Kiernan static int 108fb47a376SStephen J. Kiernan sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS) 109fb47a376SStephen J. Kiernan { 110fb47a376SStephen J. Kiernan struct sbuf sb; 111fb47a376SStephen J. Kiernan int error; 112fb47a376SStephen J. Kiernan 113fb47a376SStephen J. Kiernan error = sysctl_wire_old_buffer(req, 0); 114fb47a376SStephen J. Kiernan if (error != 0) 115fb47a376SStephen J. Kiernan return (error); 116fb47a376SStephen J. Kiernan 117fb47a376SStephen J. Kiernan sbuf_new_for_sysctl(&sb, NULL, 1024, req); 1181db017d0SStephen J. Kiernan mac_veriexec_metadata_print_db(&sb); 119fb47a376SStephen J. Kiernan error = sbuf_finish(&sb); 120fb47a376SStephen J. Kiernan sbuf_delete(&sb); 121fb47a376SStephen J. Kiernan 122fb47a376SStephen J. Kiernan return (error); 123fb47a376SStephen J. Kiernan } 124fb47a376SStephen J. Kiernan 125fb47a376SStephen J. Kiernan /** 126fb47a376SStephen J. Kiernan * @internal 127fb47a376SStephen J. Kiernan * @brief Generate human-readable output about the current verified execution 128fb47a376SStephen J. Kiernan * state. 129fb47a376SStephen J. Kiernan * 130fb47a376SStephen J. Kiernan * @param sbp sbuf to write output to 131fb47a376SStephen J. Kiernan */ 132fb47a376SStephen J. Kiernan static void 133fb47a376SStephen J. Kiernan mac_veriexec_print_state(struct sbuf *sbp) 134fb47a376SStephen J. Kiernan { 135fb47a376SStephen J. Kiernan 136fb47a376SStephen J. Kiernan if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE) 137fb47a376SStephen J. Kiernan sbuf_printf(sbp, "inactive "); 138fb47a376SStephen J. Kiernan if (mac_veriexec_state & VERIEXEC_STATE_LOADED) 139fb47a376SStephen J. Kiernan sbuf_printf(sbp, "loaded "); 140fb47a376SStephen J. Kiernan if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE) 141fb47a376SStephen J. Kiernan sbuf_printf(sbp, "active "); 142fb47a376SStephen J. Kiernan if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE) 143fb47a376SStephen J. Kiernan sbuf_printf(sbp, "enforce "); 144fb47a376SStephen J. Kiernan if (mac_veriexec_state & VERIEXEC_STATE_LOCKED) 145fb47a376SStephen J. Kiernan sbuf_printf(sbp, "locked "); 146fb47a376SStephen J. Kiernan if (mac_veriexec_state != 0) 147fb47a376SStephen J. Kiernan sbuf_trim(sbp); 148fb47a376SStephen J. Kiernan } 149fb47a376SStephen J. Kiernan 150fb47a376SStephen J. Kiernan /** 151fb47a376SStephen J. Kiernan * @internal 152fb47a376SStephen J. Kiernan * @brief Handler for security.mac.veriexec.state sysctl 153fb47a376SStephen J. Kiernan * 154fb47a376SStephen J. Kiernan * Display a human-readable form of the current verified execution subsystem 155fb47a376SStephen J. Kiernan * state. 156fb47a376SStephen J. Kiernan */ 157fb47a376SStephen J. Kiernan static int 158fb47a376SStephen J. Kiernan sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS) 159fb47a376SStephen J. Kiernan { 160fb47a376SStephen J. Kiernan struct sbuf sb; 161fb47a376SStephen J. Kiernan int error; 162fb47a376SStephen J. Kiernan 163fb47a376SStephen J. Kiernan sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND); 164fb47a376SStephen J. Kiernan mac_veriexec_print_state(&sb); 165fb47a376SStephen J. Kiernan sbuf_finish(&sb); 166fb47a376SStephen J. Kiernan 167fb47a376SStephen J. Kiernan error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb)); 168fb47a376SStephen J. Kiernan sbuf_delete(&sb); 169fb47a376SStephen J. Kiernan return (error); 170fb47a376SStephen J. Kiernan } 171fb47a376SStephen J. Kiernan 172fb47a376SStephen J. Kiernan /** 173fb47a376SStephen J. Kiernan * @internal 174fb47a376SStephen J. Kiernan * @brief Event handler called when a virtual file system is mounted. 175fb47a376SStephen J. Kiernan * 176fb47a376SStephen J. Kiernan * We need to record the file system identifier in the MAC per-policy slot 177fb47a376SStephen J. Kiernan * assigned to veriexec, so we have a key to use in order to reference the 178fb47a376SStephen J. Kiernan * mount point in the meta-data store. 179fb47a376SStephen J. Kiernan * 180fb47a376SStephen J. Kiernan * @param arg unused argument 181fb47a376SStephen J. Kiernan * @param mp mount point that is being mounted 182fb47a376SStephen J. Kiernan * @param fsrootvp vnode of the file system root 183fb47a376SStephen J. Kiernan * @param td calling thread 184fb47a376SStephen J. Kiernan */ 185fb47a376SStephen J. Kiernan static void 186fb47a376SStephen J. Kiernan mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp, 187fb47a376SStephen J. Kiernan struct vnode *fsrootvp, struct thread *td) 188fb47a376SStephen J. Kiernan { 189fb47a376SStephen J. Kiernan struct vattr va; 190fb47a376SStephen J. Kiernan int error; 191fb47a376SStephen J. Kiernan 192fb47a376SStephen J. Kiernan error = VOP_GETATTR(fsrootvp, &va, td->td_ucred); 193fb47a376SStephen J. Kiernan if (error) 194fb47a376SStephen J. Kiernan return; 195fb47a376SStephen J. Kiernan 196fb47a376SStephen J. Kiernan SLOT_SET(mp->mnt_label, va.va_fsid); 197fb47a376SStephen J. Kiernan #ifdef MAC_DEBUG 1983d53cd0fSStephen J. Kiernan MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p", 1993d53cd0fSStephen J. Kiernan (uintmax_t)va.va_fsid, mp); 200fb47a376SStephen J. Kiernan #endif 201fb47a376SStephen J. Kiernan } 202fb47a376SStephen J. Kiernan 203fb47a376SStephen J. Kiernan /** 204fb47a376SStephen J. Kiernan * @internal 205fb47a376SStephen J. Kiernan * @brief Event handler called when a virtual file system is unmounted. 206fb47a376SStephen J. Kiernan * 207fb47a376SStephen J. Kiernan * If we recorded a file system identifier in the MAC per-policy slot assigned 208fb47a376SStephen J. Kiernan * to veriexec, then we need to tell the meta-data store to clean up. 209fb47a376SStephen J. Kiernan * 210fb47a376SStephen J. Kiernan * @param arg unused argument 211fb47a376SStephen J. Kiernan * @param mp mount point that is being unmounted 212fb47a376SStephen J. Kiernan * @param td calling thread 213fb47a376SStephen J. Kiernan */ 214fb47a376SStephen J. Kiernan static void 215fb47a376SStephen J. Kiernan mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp, 216fb47a376SStephen J. Kiernan struct thread *td) 217fb47a376SStephen J. Kiernan { 218fb47a376SStephen J. Kiernan dev_t fsid; 219fb47a376SStephen J. Kiernan 220fb47a376SStephen J. Kiernan fsid = SLOT(mp->mnt_label); 221fb47a376SStephen J. Kiernan if (fsid) { 2223d53cd0fSStephen J. Kiernan MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount", 2233d53cd0fSStephen J. Kiernan (uintmax_t)fsid); 224fb47a376SStephen J. Kiernan mac_veriexec_metadata_unmounted(fsid, td); 225fb47a376SStephen J. Kiernan } 226fb47a376SStephen J. Kiernan } 227fb47a376SStephen J. Kiernan 228fb47a376SStephen J. Kiernan /** 229fb47a376SStephen J. Kiernan * @internal 230fb47a376SStephen J. Kiernan * @brief The mount point is being initialized, set the value in the MAC 231fb47a376SStephen J. Kiernan * per-policy slot for veriexec to zero. 232fb47a376SStephen J. Kiernan * 233fb47a376SStephen J. Kiernan * @note A value of zero in this slot indicates no file system identifier 234fb47a376SStephen J. Kiernan * is assigned. 235fb47a376SStephen J. Kiernan * 236fb47a376SStephen J. Kiernan * @param label the label that is being initialized 237fb47a376SStephen J. Kiernan */ 238fb47a376SStephen J. Kiernan static void 239fb47a376SStephen J. Kiernan mac_veriexec_mount_init_label(struct label *label) 240fb47a376SStephen J. Kiernan { 241fb47a376SStephen J. Kiernan 242fb47a376SStephen J. Kiernan SLOT_SET(label, 0); 243fb47a376SStephen J. Kiernan } 244fb47a376SStephen J. Kiernan 245fb47a376SStephen J. Kiernan /** 246fb47a376SStephen J. Kiernan * @internal 247fb47a376SStephen J. Kiernan * @brief The mount-point is being destroyed, reset the value in the MAC 248fb47a376SStephen J. Kiernan * per-policy slot for veriexec back to zero. 249fb47a376SStephen J. Kiernan * 250fb47a376SStephen J. Kiernan * @note A value of zero in this slot indicates no file system identifier 251fb47a376SStephen J. Kiernan * is assigned. 252fb47a376SStephen J. Kiernan * 253fb47a376SStephen J. Kiernan * @param label the label that is being destroyed 254fb47a376SStephen J. Kiernan */ 255fb47a376SStephen J. Kiernan static void 256fb47a376SStephen J. Kiernan mac_veriexec_mount_destroy_label(struct label *label) 257fb47a376SStephen J. Kiernan { 258fb47a376SStephen J. Kiernan 259fb47a376SStephen J. Kiernan SLOT_SET(label, 0); 260fb47a376SStephen J. Kiernan } 261fb47a376SStephen J. Kiernan 262fb47a376SStephen J. Kiernan /** 263fb47a376SStephen J. Kiernan * @internal 264fb47a376SStephen J. Kiernan * @brief The vnode label is being initialized, set the value in the MAC 265fb47a376SStephen J. Kiernan * per-policy slot for veriexec to @c FINGERPRINT_INVALID 266fb47a376SStephen J. Kiernan * 267fb47a376SStephen J. Kiernan * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. 268fb47a376SStephen J. Kiernan * 269fb47a376SStephen J. Kiernan * @param label the label that is being initialized 270fb47a376SStephen J. Kiernan */ 271fb47a376SStephen J. Kiernan static void 272fb47a376SStephen J. Kiernan mac_veriexec_vnode_init_label(struct label *label) 273fb47a376SStephen J. Kiernan { 274fb47a376SStephen J. Kiernan 275fb47a376SStephen J. Kiernan SLOT_SET(label, FINGERPRINT_INVALID); 276fb47a376SStephen J. Kiernan } 277fb47a376SStephen J. Kiernan 278fb47a376SStephen J. Kiernan /** 279fb47a376SStephen J. Kiernan * @internal 280fb47a376SStephen J. Kiernan * @brief The vnode label is being destroyed, reset the value in the MAC 281fb47a376SStephen J. Kiernan * per-policy slot for veriexec back to @c FINGERPRINT_INVALID 282fb47a376SStephen J. Kiernan * 283fb47a376SStephen J. Kiernan * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid. 284fb47a376SStephen J. Kiernan * 285fb47a376SStephen J. Kiernan * @param label the label that is being destroyed 286fb47a376SStephen J. Kiernan */ 287fb47a376SStephen J. Kiernan static void 288fb47a376SStephen J. Kiernan mac_veriexec_vnode_destroy_label(struct label *label) 289fb47a376SStephen J. Kiernan { 290fb47a376SStephen J. Kiernan 291fb47a376SStephen J. Kiernan SLOT_SET(label, FINGERPRINT_INVALID); 292fb47a376SStephen J. Kiernan } 293fb47a376SStephen J. Kiernan 294fb47a376SStephen J. Kiernan /** 295fb47a376SStephen J. Kiernan * @internal 296fb47a376SStephen J. Kiernan * @brief Copy the value in the MAC per-policy slot assigned to veriexec from 297fb47a376SStephen J. Kiernan * the @p src label to the @p dest label 298fb47a376SStephen J. Kiernan */ 299fb47a376SStephen J. Kiernan static void 300fb47a376SStephen J. Kiernan mac_veriexec_copy_label(struct label *src, struct label *dest) 301fb47a376SStephen J. Kiernan { 302fb47a376SStephen J. Kiernan 303fb47a376SStephen J. Kiernan SLOT_SET(dest, SLOT(src)); 304fb47a376SStephen J. Kiernan } 305fb47a376SStephen J. Kiernan 306fb47a376SStephen J. Kiernan /** 307fb47a376SStephen J. Kiernan * @internal 308fb47a376SStephen J. Kiernan * @brief Check if the requested process can be debugged 309fb47a376SStephen J. Kiernan * 310fb47a376SStephen J. Kiernan * @param cred credentials to use 311fb47a376SStephen J. Kiernan * @param p process to debug 312fb47a376SStephen J. Kiernan * 313fb47a376SStephen J. Kiernan * @return 0 if debugging is allowed, otherwise an error code. 314fb47a376SStephen J. Kiernan */ 315fb47a376SStephen J. Kiernan static int 316fb47a376SStephen J. Kiernan mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p) 317fb47a376SStephen J. Kiernan { 318fb47a376SStephen J. Kiernan int error, flags; 319fb47a376SStephen J. Kiernan 320fb47a376SStephen J. Kiernan /* If we are not enforcing veriexec, nothing for us to check */ 321fb47a376SStephen J. Kiernan if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 322fb47a376SStephen J. Kiernan return (0); 323fb47a376SStephen J. Kiernan 324fb47a376SStephen J. Kiernan error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); 325fb47a376SStephen J. Kiernan if (error != 0) 326fb47a376SStephen J. Kiernan return (0); 327fb47a376SStephen J. Kiernan 328fb47a376SStephen J. Kiernan return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0); 329fb47a376SStephen J. Kiernan } 330fb47a376SStephen J. Kiernan 331fb47a376SStephen J. Kiernan /** 332fb47a376SStephen J. Kiernan * @internal 333fb47a376SStephen J. Kiernan * @brief A KLD load has been requested and needs to be validated. 334fb47a376SStephen J. Kiernan * 335fb47a376SStephen J. Kiernan * @param cred credentials to use 336fb47a376SStephen J. Kiernan * @param vp vnode of the KLD that has been requested 337fb47a376SStephen J. Kiernan * @param vlabel vnode label assigned to the vnode 338fb47a376SStephen J. Kiernan * 339fb47a376SStephen J. Kiernan * @return 0 if the KLD load is allowed, otherwise an error code. 340fb47a376SStephen J. Kiernan */ 341fb47a376SStephen J. Kiernan static int 342fb47a376SStephen J. Kiernan mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp, 343fb47a376SStephen J. Kiernan struct label *vlabel) 344fb47a376SStephen J. Kiernan { 345fb47a376SStephen J. Kiernan struct vattr va; 346fb47a376SStephen J. Kiernan struct thread *td = curthread; 347fb47a376SStephen J. Kiernan fingerprint_status_t status; 348fb47a376SStephen J. Kiernan int error; 349fb47a376SStephen J. Kiernan 350fb47a376SStephen J. Kiernan /* 351fb47a376SStephen J. Kiernan * If we are not actively enforcing, allow it 352fb47a376SStephen J. Kiernan */ 353fb47a376SStephen J. Kiernan if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 354fb47a376SStephen J. Kiernan return (0); 355fb47a376SStephen J. Kiernan 356fb47a376SStephen J. Kiernan /* Get vnode attributes */ 357fb47a376SStephen J. Kiernan error = VOP_GETATTR(vp, &va, cred); 358fb47a376SStephen J. Kiernan if (error) 359fb47a376SStephen J. Kiernan return (error); 360fb47a376SStephen J. Kiernan 361fb47a376SStephen J. Kiernan /* 362fb47a376SStephen J. Kiernan * Fetch the fingerprint status for the vnode 363fb47a376SStephen J. Kiernan * (starting with files first) 364fb47a376SStephen J. Kiernan */ 365fb47a376SStephen J. Kiernan error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, 366fb47a376SStephen J. Kiernan VERIEXEC_FILES_FIRST); 367fb47a376SStephen J. Kiernan if (error && error != EAUTH) 368fb47a376SStephen J. Kiernan return (error); 369fb47a376SStephen J. Kiernan 370fb47a376SStephen J. Kiernan /* 371fb47a376SStephen J. Kiernan * By now we should have status... 372fb47a376SStephen J. Kiernan */ 373fb47a376SStephen J. Kiernan status = mac_veriexec_get_fingerprint_status(vp); 374fb47a376SStephen J. Kiernan switch (status) { 375fb47a376SStephen J. Kiernan case FINGERPRINT_FILE: 376fb47a376SStephen J. Kiernan case FINGERPRINT_VALID: 377fb47a376SStephen J. Kiernan case FINGERPRINT_INDIRECT: 378fb47a376SStephen J. Kiernan if (error) 379fb47a376SStephen J. Kiernan return (error); 380fb47a376SStephen J. Kiernan break; 381fb47a376SStephen J. Kiernan default: 382fb47a376SStephen J. Kiernan /* 383fb47a376SStephen J. Kiernan * kldload should fail unless there is a valid fingerprint 384fb47a376SStephen J. Kiernan * registered. 385fb47a376SStephen J. Kiernan */ 3863d53cd0fSStephen J. Kiernan MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, " 3873d53cd0fSStephen J. Kiernan "file %ju.%ju\n", status, (uintmax_t)va.va_fsid, 3883d53cd0fSStephen J. Kiernan (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen); 389fb47a376SStephen J. Kiernan return (EAUTH); 390fb47a376SStephen J. Kiernan } 391fb47a376SStephen J. Kiernan 392fb47a376SStephen J. Kiernan /* Everything is good, allow the KLD to be loaded */ 393fb47a376SStephen J. Kiernan return (0); 394fb47a376SStephen J. Kiernan } 395fb47a376SStephen J. Kiernan 396fb47a376SStephen J. Kiernan /** 397fb47a376SStephen J. Kiernan * @internal 398fb47a376SStephen J. Kiernan * @brief Check privileges that veriexec needs to be concerned about. 399fb47a376SStephen J. Kiernan * 400fb47a376SStephen J. Kiernan * The following privileges are checked by this function: 401fb47a376SStephen J. Kiernan * - PRIV_KMEM_WRITE\n 402fb47a376SStephen J. Kiernan * Check if writes to /dev/mem and /dev/kmem are allowed\n 403fb47a376SStephen J. Kiernan * (Only trusted processes are allowed) 404fb47a376SStephen J. Kiernan * 405fb47a376SStephen J. Kiernan * @param cred credentials to use 406fb47a376SStephen J. Kiernan * @param priv privilege to check 407fb47a376SStephen J. Kiernan * 408fb47a376SStephen J. Kiernan * @return 0 if the privilege is allowed, error code otherwise. 409fb47a376SStephen J. Kiernan */ 410fb47a376SStephen J. Kiernan static int 411fb47a376SStephen J. Kiernan mac_veriexec_priv_check(struct ucred *cred, int priv) 412fb47a376SStephen J. Kiernan { 413fb47a376SStephen J. Kiernan 414fb47a376SStephen J. Kiernan /* If we are not enforcing veriexec, nothing for us to check */ 415fb47a376SStephen J. Kiernan if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 416fb47a376SStephen J. Kiernan return (0); 417fb47a376SStephen J. Kiernan 418fb47a376SStephen J. Kiernan switch (priv) { 419fb47a376SStephen J. Kiernan case PRIV_KMEM_WRITE: 420fb47a376SStephen J. Kiernan if (!mac_veriexec_proc_is_trusted(cred, curproc)) 421fb47a376SStephen J. Kiernan return (EPERM); 422fb47a376SStephen J. Kiernan break; 423fb47a376SStephen J. Kiernan default: 424fb47a376SStephen J. Kiernan break; 425fb47a376SStephen J. Kiernan } 426fb47a376SStephen J. Kiernan return (0); 427fb47a376SStephen J. Kiernan } 428fb47a376SStephen J. Kiernan 429ed377cf4SStephen J. Kiernan static int 430ed377cf4SStephen J. Kiernan mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp, 431ed377cf4SStephen J. Kiernan void *arg1, int arg2, struct sysctl_req *req) 432ed377cf4SStephen J. Kiernan { 433ed377cf4SStephen J. Kiernan struct sysctl_oid *oid; 434ed377cf4SStephen J. Kiernan 435ed377cf4SStephen J. Kiernan /* If we are not enforcing veriexec, nothing for us to check */ 436ed377cf4SStephen J. Kiernan if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 437ed377cf4SStephen J. Kiernan return (0); 438ed377cf4SStephen J. Kiernan 439ed377cf4SStephen J. Kiernan oid = oidp; 440ed377cf4SStephen J. Kiernan if (oid->oid_kind & CTLFLAG_SECURE) { 441ed377cf4SStephen J. Kiernan return (EPERM); /* XXX call mac_veriexec_priv_check? */ 442ed377cf4SStephen J. Kiernan } 443ed377cf4SStephen J. Kiernan return 0; 444ed377cf4SStephen J. Kiernan } 445ed377cf4SStephen J. Kiernan 446fb47a376SStephen J. Kiernan /** 447fb47a376SStephen J. Kiernan * @internal 448fb47a376SStephen J. Kiernan * @brief A program is being executed and needs to be validated. 449fb47a376SStephen J. Kiernan * 450fb47a376SStephen J. Kiernan * @param cred credentials to use 451fb47a376SStephen J. Kiernan * @param vp vnode of the program that is being executed 452fb47a376SStephen J. Kiernan * @param label vnode label assigned to the vnode 453fb47a376SStephen J. Kiernan * @param imgp parameters for the image to be executed 454fb47a376SStephen J. Kiernan * @param execlabel optional exec label 455fb47a376SStephen J. Kiernan * 456fb47a376SStephen J. Kiernan * @return 0 if the program should be allowed to execute, otherwise an error 457fb47a376SStephen J. Kiernan * code. 458fb47a376SStephen J. Kiernan */ 459fb47a376SStephen J. Kiernan static int 460fb47a376SStephen J. Kiernan mac_veriexec_vnode_check_exec(struct ucred *cred __unused, 461fb47a376SStephen J. Kiernan struct vnode *vp __unused, struct label *label __unused, 462fb47a376SStephen J. Kiernan struct image_params *imgp, struct label *execlabel __unused) 463fb47a376SStephen J. Kiernan { 464fb47a376SStephen J. Kiernan struct thread *td = curthread; 465fb47a376SStephen J. Kiernan int error; 466fb47a376SStephen J. Kiernan 467fb47a376SStephen J. Kiernan error = mac_veriexec_fingerprint_check_image(imgp, 0, td); 468fb47a376SStephen J. Kiernan return (error); 469fb47a376SStephen J. Kiernan } 470fb47a376SStephen J. Kiernan 471fb47a376SStephen J. Kiernan /** 472fb47a376SStephen J. Kiernan * @brief Check fingerprint for the specified vnode and validate it 473fb47a376SStephen J. Kiernan * 474fb47a376SStephen J. Kiernan * @param cred credentials to use 475fb47a376SStephen J. Kiernan * @param vp vnode of the file 476fb47a376SStephen J. Kiernan * @param accmode access mode to check (read, write, append, create, 477fb47a376SStephen J. Kiernan * verify, etc.) 478fb47a376SStephen J. Kiernan * 479fb47a376SStephen J. Kiernan * @return 0 if the file validated, otherwise an error code. 480fb47a376SStephen J. Kiernan */ 481fb47a376SStephen J. Kiernan static int 482fb47a376SStephen J. Kiernan mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode) 483fb47a376SStephen J. Kiernan { 484fb47a376SStephen J. Kiernan struct vattr va; 485fb47a376SStephen J. Kiernan struct thread *td = curthread; 486fb47a376SStephen J. Kiernan fingerprint_status_t status; 487fb47a376SStephen J. Kiernan int error; 488fb47a376SStephen J. Kiernan 489fb47a376SStephen J. Kiernan /* Get vnode attributes */ 490fb47a376SStephen J. Kiernan error = VOP_GETATTR(vp, &va, cred); 491fb47a376SStephen J. Kiernan if (error) 492fb47a376SStephen J. Kiernan return (error); 493fb47a376SStephen J. Kiernan 494fb47a376SStephen J. Kiernan /* Get the fingerprint status for the file */ 495fb47a376SStephen J. Kiernan error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td, 496fb47a376SStephen J. Kiernan VERIEXEC_FILES_FIRST); 497fb47a376SStephen J. Kiernan if (error && error != EAUTH) 498fb47a376SStephen J. Kiernan return (error); 499fb47a376SStephen J. Kiernan 500fb47a376SStephen J. Kiernan /* 501fb47a376SStephen J. Kiernan * By now we should have status... 502fb47a376SStephen J. Kiernan */ 503fb47a376SStephen J. Kiernan status = mac_veriexec_get_fingerprint_status(vp); 504fb47a376SStephen J. Kiernan if (accmode & VWRITE) { 505fb47a376SStephen J. Kiernan /* 506fb47a376SStephen J. Kiernan * If file has a fingerprint then deny the write request, 507fb47a376SStephen J. Kiernan * otherwise invalidate the status so we don't keep checking 508fb47a376SStephen J. Kiernan * for the file having a fingerprint. 509fb47a376SStephen J. Kiernan */ 510fb47a376SStephen J. Kiernan switch (status) { 511fb47a376SStephen J. Kiernan case FINGERPRINT_FILE: 512fb47a376SStephen J. Kiernan case FINGERPRINT_VALID: 513fb47a376SStephen J. Kiernan case FINGERPRINT_INDIRECT: 514fb47a376SStephen J. Kiernan MAC_VERIEXEC_DBG(2, 515fb47a376SStephen J. Kiernan "attempted write to fingerprinted file for dev " 5163d53cd0fSStephen J. Kiernan "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid, 5173d53cd0fSStephen J. Kiernan (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen); 518fb47a376SStephen J. Kiernan return (EPERM); 519fb47a376SStephen J. Kiernan default: 520fb47a376SStephen J. Kiernan break; 521fb47a376SStephen J. Kiernan } 522fb47a376SStephen J. Kiernan } 523fb47a376SStephen J. Kiernan if (accmode & VVERIFY) { 524fb47a376SStephen J. Kiernan switch (status) { 525fb47a376SStephen J. Kiernan case FINGERPRINT_FILE: 526fb47a376SStephen J. Kiernan case FINGERPRINT_VALID: 527fb47a376SStephen J. Kiernan case FINGERPRINT_INDIRECT: 528fb47a376SStephen J. Kiernan if (error) 529fb47a376SStephen J. Kiernan return (error); 530fb47a376SStephen J. Kiernan break; 531fb47a376SStephen J. Kiernan default: 532fb47a376SStephen J. Kiernan /* 533fb47a376SStephen J. Kiernan * Caller wants open to fail unless there is a valid 534fb47a376SStephen J. Kiernan * fingerprint registered. 535fb47a376SStephen J. Kiernan */ 536fb47a376SStephen J. Kiernan MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev " 5373d53cd0fSStephen J. Kiernan "%ju, file %ju.%ju\n", status, 5383d53cd0fSStephen J. Kiernan (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid, 5393d53cd0fSStephen J. Kiernan (uintmax_t)va.va_gen); 540fb47a376SStephen J. Kiernan return (EAUTH); 541fb47a376SStephen J. Kiernan } 542fb47a376SStephen J. Kiernan } 543fb47a376SStephen J. Kiernan return (0); 544fb47a376SStephen J. Kiernan } 545fb47a376SStephen J. Kiernan 546fb47a376SStephen J. Kiernan /** 547fb47a376SStephen J. Kiernan * @brief Opening a file has been requested and may need to be validated. 548fb47a376SStephen J. Kiernan * 549fb47a376SStephen J. Kiernan * @param cred credentials to use 550fb47a376SStephen J. Kiernan * @param vp vnode of the file to open 551fb47a376SStephen J. Kiernan * @param label vnode label assigned to the vnode 552fb47a376SStephen J. Kiernan * @param accmode access mode to use for opening the file (read, write, 553fb47a376SStephen J. Kiernan * append, create, verify, etc.) 554fb47a376SStephen J. Kiernan * 555fb47a376SStephen J. Kiernan * @return 0 if opening the file should be allowed, otherwise an error code. 556fb47a376SStephen J. Kiernan */ 557fb47a376SStephen J. Kiernan static int 558fb47a376SStephen J. Kiernan mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp, 559fb47a376SStephen J. Kiernan struct label *label __unused, accmode_t accmode) 560fb47a376SStephen J. Kiernan { 561fb47a376SStephen J. Kiernan int error; 562fb47a376SStephen J. Kiernan 563fb47a376SStephen J. Kiernan /* 564fb47a376SStephen J. Kiernan * Look for the file on the fingerprint lists iff it has not been seen 565fb47a376SStephen J. Kiernan * before. 566fb47a376SStephen J. Kiernan */ 567fb47a376SStephen J. Kiernan if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 568fb47a376SStephen J. Kiernan return (0); 569fb47a376SStephen J. Kiernan 570fb47a376SStephen J. Kiernan error = mac_veriexec_check_vp(cred, vp, accmode); 571fb47a376SStephen J. Kiernan return (error); 572fb47a376SStephen J. Kiernan } 573fb47a376SStephen J. Kiernan 574fb47a376SStephen J. Kiernan /** 575ade97886SStephen J. Kiernan * @brief Check mode changes on file to ensure they should be allowed. 576ade97886SStephen J. Kiernan * 577ade97886SStephen J. Kiernan * We cannot allow chmod of SUID or SGID on verified files. 578ade97886SStephen J. Kiernan * 579ade97886SStephen J. Kiernan * @param cred credentials to use 580ade97886SStephen J. Kiernan * @param vp vnode of the file to open 581ade97886SStephen J. Kiernan * @param label vnode label assigned to the vnode 582ade97886SStephen J. Kiernan * @param mode mode flags to set 583ade97886SStephen J. Kiernan * 584ade97886SStephen J. Kiernan * @return 0 if the mode change should be allowed, EAUTH otherwise. 585ade97886SStephen J. Kiernan */ 586ade97886SStephen J. Kiernan static int 587ade97886SStephen J. Kiernan mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp, 588ade97886SStephen J. Kiernan struct label *label __unused, mode_t mode) 589ade97886SStephen J. Kiernan { 590ade97886SStephen J. Kiernan int error; 591ade97886SStephen J. Kiernan 592ade97886SStephen J. Kiernan if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0) 593ade97886SStephen J. Kiernan return (0); 594ade97886SStephen J. Kiernan 595ade97886SStephen J. Kiernan /* 596ade97886SStephen J. Kiernan * Do not allow chmod (set-[gu]id) of verified file 597ade97886SStephen J. Kiernan */ 598ade97886SStephen J. Kiernan error = mac_veriexec_check_vp(cred, vp, VVERIFY); 599ade97886SStephen J. Kiernan if (error == EAUTH) /* it isn't verified */ 600ade97886SStephen J. Kiernan return (0); 601ade97886SStephen J. Kiernan if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0) 602ade97886SStephen J. Kiernan return (EAUTH); 603ade97886SStephen J. Kiernan return (0); 604ade97886SStephen J. Kiernan } 605ade97886SStephen J. Kiernan 606ade97886SStephen J. Kiernan /** 607fb47a376SStephen J. Kiernan * @internal 608fb47a376SStephen J. Kiernan * @brief Initialize the mac_veriexec MAC policy 609fb47a376SStephen J. Kiernan * 610fb47a376SStephen J. Kiernan * @param mpc MAC policy configuration 611fb47a376SStephen J. Kiernan */ 612fb47a376SStephen J. Kiernan static void 613fb47a376SStephen J. Kiernan mac_veriexec_init(struct mac_policy_conf *mpc __unused) 614fb47a376SStephen J. Kiernan { 615fb47a376SStephen J. Kiernan /* Initialize state */ 616fb47a376SStephen J. Kiernan mac_veriexec_state = VERIEXEC_STATE_INACTIVE; 617fb47a376SStephen J. Kiernan 618fb47a376SStephen J. Kiernan /* Initialize meta-data storage */ 619fb47a376SStephen J. Kiernan mac_veriexec_metadata_init(); 620fb47a376SStephen J. Kiernan 621fb47a376SStephen J. Kiernan /* Initialize fingerprint ops */ 622fb47a376SStephen J. Kiernan mac_veriexec_fingerprint_init(); 623fb47a376SStephen J. Kiernan 624fb47a376SStephen J. Kiernan /* Register event handlers */ 625fb47a376SStephen J. Kiernan EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL, 626fb47a376SStephen J. Kiernan EVENTHANDLER_PRI_FIRST); 627fb47a376SStephen J. Kiernan EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL, 628fb47a376SStephen J. Kiernan EVENTHANDLER_PRI_LAST); 629fb47a376SStephen J. Kiernan } 630fb47a376SStephen J. Kiernan 631fb47a376SStephen J. Kiernan /** 632fb47a376SStephen J. Kiernan * @internal 633fb47a376SStephen J. Kiernan * @brief MAC policy-specific syscall for mac_veriexec 634fb47a376SStephen J. Kiernan * 635fb47a376SStephen J. Kiernan * The following syscalls are implemented: 636fb47a376SStephen J. Kiernan * - @c MAC_VERIEXEC_CHECK_SYSCALL 637fb47a376SStephen J. Kiernan * Check if the file referenced by a file descriptor has a fingerprint 638fb47a376SStephen J. Kiernan * registered in the meta-data store. 639fb47a376SStephen J. Kiernan * 640fb47a376SStephen J. Kiernan * @param td calling thread 641fb47a376SStephen J. Kiernan * @param call system call number 642fb47a376SStephen J. Kiernan * @param arg arugments to the syscall 643fb47a376SStephen J. Kiernan * 644fb47a376SStephen J. Kiernan * @return 0 on success, otherwise an error code. 645fb47a376SStephen J. Kiernan */ 646fb47a376SStephen J. Kiernan static int 647fb47a376SStephen J. Kiernan mac_veriexec_syscall(struct thread *td, int call, void *arg) 648fb47a376SStephen J. Kiernan { 649fb47a376SStephen J. Kiernan struct image_params img; 650fb47a376SStephen J. Kiernan struct nameidata nd; 651fb47a376SStephen J. Kiernan cap_rights_t rights; 652fb47a376SStephen J. Kiernan struct vattr va; 653fb47a376SStephen J. Kiernan struct file *fp; 654fb47a376SStephen J. Kiernan int error; 655fb47a376SStephen J. Kiernan 656fb47a376SStephen J. Kiernan switch (call) { 657fb47a376SStephen J. Kiernan case MAC_VERIEXEC_CHECK_FD_SYSCALL: 658fb47a376SStephen J. Kiernan /* Get the vnode associated with the file descriptor passed */ 659fb47a376SStephen J. Kiernan error = getvnode(td, (uintptr_t) arg, cap_rights_init(&rights, 660fb47a376SStephen J. Kiernan CAP_READ), &fp); 661fb47a376SStephen J. Kiernan if (error) 662fb47a376SStephen J. Kiernan return (error); 663fb47a376SStephen J. Kiernan if (fp->f_type != DTYPE_VNODE) { 664fb47a376SStephen J. Kiernan MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: " 665fb47a376SStephen J. Kiernan "file is not vnode type (type=0x%x)", 666fb47a376SStephen J. Kiernan fp->f_type); 667fb47a376SStephen J. Kiernan error = EINVAL; 668fb47a376SStephen J. Kiernan goto cleanup_file; 669fb47a376SStephen J. Kiernan } 670fb47a376SStephen J. Kiernan 671fb47a376SStephen J. Kiernan /* 672fb47a376SStephen J. Kiernan * setup the bits of image_params that are used by 673fb47a376SStephen J. Kiernan * mac_veriexec_check_fingerprint(). 674fb47a376SStephen J. Kiernan */ 675fb47a376SStephen J. Kiernan bzero(&img, sizeof(img)); 676fb47a376SStephen J. Kiernan img.proc = td->td_proc; 677fb47a376SStephen J. Kiernan img.vp = fp->f_vnode; 678fb47a376SStephen J. Kiernan img.attr = &va; 679fb47a376SStephen J. Kiernan 680fb47a376SStephen J. Kiernan /* 681fb47a376SStephen J. Kiernan * Get vnode attributes 682fb47a376SStephen J. Kiernan * (need to obtain a lock on the vnode first) 683fb47a376SStephen J. Kiernan */ 684fb47a376SStephen J. Kiernan vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY); 685fb47a376SStephen J. Kiernan error = VOP_GETATTR(fp->f_vnode, &va, td->td_ucred); 686fb47a376SStephen J. Kiernan if (error) 687fb47a376SStephen J. Kiernan goto check_done; 688fb47a376SStephen J. Kiernan 689fb47a376SStephen J. Kiernan MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: " 690fb47a376SStephen J. Kiernan "va_mode=%o, check_files=%d\n", va.va_mode, 691fb47a376SStephen J. Kiernan ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)); 692fb47a376SStephen J. Kiernan error = mac_veriexec_fingerprint_check_image(&img, 693fb47a376SStephen J. Kiernan ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td); 694fb47a376SStephen J. Kiernan check_done: 695fb47a376SStephen J. Kiernan /* Release the lock we obtained earlier */ 696b249ce48SMateusz Guzik VOP_UNLOCK(img.vp); 697fb47a376SStephen J. Kiernan cleanup_file: 698fb47a376SStephen J. Kiernan fdrop(fp, td); 699fb47a376SStephen J. Kiernan break; 700fb47a376SStephen J. Kiernan case MAC_VERIEXEC_CHECK_PATH_SYSCALL: 701fb47a376SStephen J. Kiernan /* Look up the path to get the vnode */ 7026cbc9703SStephen J. Kiernan NDINIT(&nd, LOOKUP, 7036cbc9703SStephen J. Kiernan FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1, 704fb47a376SStephen J. Kiernan UIO_USERSPACE, arg, td); 705fb47a376SStephen J. Kiernan error = namei(&nd); 706fb47a376SStephen J. Kiernan if (error != 0) 707fb47a376SStephen J. Kiernan break; 708fb47a376SStephen J. Kiernan NDFREE(&nd, NDF_ONLY_PNBUF); 709fb47a376SStephen J. Kiernan 710fb47a376SStephen J. Kiernan /* Check the fingerprint status of the vnode */ 711fb47a376SStephen J. Kiernan error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY); 712fb47a376SStephen J. Kiernan vput(nd.ni_vp); 713fb47a376SStephen J. Kiernan break; 714fb47a376SStephen J. Kiernan default: 715fb47a376SStephen J. Kiernan error = EOPNOTSUPP; 716fb47a376SStephen J. Kiernan } 717fb47a376SStephen J. Kiernan return (error); 718fb47a376SStephen J. Kiernan } 719fb47a376SStephen J. Kiernan 720fb47a376SStephen J. Kiernan static struct mac_policy_ops mac_veriexec_ops = 721fb47a376SStephen J. Kiernan { 722fb47a376SStephen J. Kiernan .mpo_init = mac_veriexec_init, 723fb47a376SStephen J. Kiernan .mpo_kld_check_load = mac_veriexec_kld_check_load, 724fb47a376SStephen J. Kiernan .mpo_mount_destroy_label = mac_veriexec_mount_destroy_label, 725fb47a376SStephen J. Kiernan .mpo_mount_init_label = mac_veriexec_mount_init_label, 726fb47a376SStephen J. Kiernan .mpo_priv_check = mac_veriexec_priv_check, 727fb47a376SStephen J. Kiernan .mpo_proc_check_debug = mac_veriexec_proc_check_debug, 728ed377cf4SStephen J. Kiernan .mpo_syscall = mac_veriexec_syscall, 729ed377cf4SStephen J. Kiernan .mpo_system_check_sysctl = mac_veriexec_sysctl_check, 730fb47a376SStephen J. Kiernan .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec, 731fb47a376SStephen J. Kiernan .mpo_vnode_check_open = mac_veriexec_vnode_check_open, 732ade97886SStephen J. Kiernan .mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode, 733fb47a376SStephen J. Kiernan .mpo_vnode_copy_label = mac_veriexec_copy_label, 734fb47a376SStephen J. Kiernan .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label, 735fb47a376SStephen J. Kiernan .mpo_vnode_init_label = mac_veriexec_vnode_init_label, 736fb47a376SStephen J. Kiernan }; 737fb47a376SStephen J. Kiernan 738fb47a376SStephen J. Kiernan MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME, 739fb47a376SStephen J. Kiernan MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot); 740fb47a376SStephen J. Kiernan MODULE_VERSION(mac_veriexec, 1); 741fb47a376SStephen J. Kiernan 742478368caSMateusz Guzik static struct vnode * 743478368caSMateusz Guzik mac_veriexec_bottom_vnode(struct vnode *vp) 744478368caSMateusz Guzik { 745478368caSMateusz Guzik struct vnode *ldvp = NULL; 746478368caSMateusz Guzik 747478368caSMateusz Guzik /* 748478368caSMateusz Guzik * XXX This code is bogus. nullfs is not the only stacking 749478368caSMateusz Guzik * filesystem. Less bogus code would add a VOP to reach bottom 750478368caSMateusz Guzik * vnode and would not make assumptions how to get there. 751478368caSMateusz Guzik */ 752478368caSMateusz Guzik if (vp->v_mount != NULL && 753478368caSMateusz Guzik strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0) 754478368caSMateusz Guzik ldvp = NULLVPTOLOWERVP(vp); 755478368caSMateusz Guzik return (ldvp); 756478368caSMateusz Guzik } 757478368caSMateusz Guzik 758fb47a376SStephen J. Kiernan /** 759fb47a376SStephen J. Kiernan * @brief Get the fingerprint status set on a vnode. 760fb47a376SStephen J. Kiernan * 761fb47a376SStephen J. Kiernan * @param vp vnode to obtain fingerprint status from 762fb47a376SStephen J. Kiernan * 763fb47a376SStephen J. Kiernan * @return Fingerprint status assigned to the vnode. 764fb47a376SStephen J. Kiernan */ 765fb47a376SStephen J. Kiernan fingerprint_status_t 766fb47a376SStephen J. Kiernan mac_veriexec_get_fingerprint_status(struct vnode *vp) 767fb47a376SStephen J. Kiernan { 768fb47a376SStephen J. Kiernan fingerprint_status_t fps; 769478368caSMateusz Guzik struct vnode *ldvp; 770fb47a376SStephen J. Kiernan 771fb47a376SStephen J. Kiernan fps = SLOT(vp->v_label); 772fb47a376SStephen J. Kiernan switch (fps) { 773fb47a376SStephen J. Kiernan case FINGERPRINT_VALID: 774fb47a376SStephen J. Kiernan case FINGERPRINT_INDIRECT: 775fb47a376SStephen J. Kiernan case FINGERPRINT_FILE: 776fb47a376SStephen J. Kiernan break; 777fb47a376SStephen J. Kiernan default: 778fb47a376SStephen J. Kiernan /* we may need to recurse */ 779478368caSMateusz Guzik ldvp = mac_veriexec_bottom_vnode(vp); 780478368caSMateusz Guzik if (ldvp != NULL) 781fb47a376SStephen J. Kiernan return mac_veriexec_get_fingerprint_status(ldvp); 782fb47a376SStephen J. Kiernan break; 783fb47a376SStephen J. Kiernan } 784fb47a376SStephen J. Kiernan return fps; 785fb47a376SStephen J. Kiernan } 786fb47a376SStephen J. Kiernan 787fb47a376SStephen J. Kiernan /** 788fb47a376SStephen J. Kiernan * @brief Get the current verified execution subsystem state. 789fb47a376SStephen J. Kiernan * 790fb47a376SStephen J. Kiernan * @return Current set of verified execution subsystem state flags. 791fb47a376SStephen J. Kiernan */ 792fb47a376SStephen J. Kiernan int 793fb47a376SStephen J. Kiernan mac_veriexec_get_state(void) 794fb47a376SStephen J. Kiernan { 795fb47a376SStephen J. Kiernan 796fb47a376SStephen J. Kiernan return (mac_veriexec_state); 797fb47a376SStephen J. Kiernan } 798fb47a376SStephen J. Kiernan 799fb47a376SStephen J. Kiernan /** 800fb47a376SStephen J. Kiernan * @brief Determine if the verified execution subsystem state has specific 801fb47a376SStephen J. Kiernan * flags set. 802fb47a376SStephen J. Kiernan * 803fb47a376SStephen J. Kiernan * @param state mask of flags to check 804fb47a376SStephen J. Kiernan * 805fb47a376SStephen J. Kiernan * @return State flags set within the masked bits 806fb47a376SStephen J. Kiernan */ 807fb47a376SStephen J. Kiernan int 808fb47a376SStephen J. Kiernan mac_veriexec_in_state(int state) 809fb47a376SStephen J. Kiernan { 810fb47a376SStephen J. Kiernan 811fb47a376SStephen J. Kiernan return (mac_veriexec_state & state); 812fb47a376SStephen J. Kiernan } 813fb47a376SStephen J. Kiernan 814fb47a376SStephen J. Kiernan /** 815fb47a376SStephen J. Kiernan * @brief Set the fingerprint status for a vnode 816fb47a376SStephen J. Kiernan * 817fb47a376SStephen J. Kiernan * Fingerprint status is stored in the MAC per-policy slot assigned to 818fb47a376SStephen J. Kiernan * mac_veriexec. 819fb47a376SStephen J. Kiernan * 820fb47a376SStephen J. Kiernan * @param vp vnode to store the fingerprint status on 821fb47a376SStephen J. Kiernan * @param fp_status fingerprint status to store 822fb47a376SStephen J. Kiernan */ 823fb47a376SStephen J. Kiernan void 824fb47a376SStephen J. Kiernan mac_veriexec_set_fingerprint_status(struct vnode *vp, 825fb47a376SStephen J. Kiernan fingerprint_status_t fp_status) 826fb47a376SStephen J. Kiernan { 827fb47a376SStephen J. Kiernan struct vnode *ldvp; 828fb47a376SStephen J. Kiernan 829478368caSMateusz Guzik /* recurse until we find the real storage */ 830478368caSMateusz Guzik ldvp = mac_veriexec_bottom_vnode(vp); 831478368caSMateusz Guzik if (ldvp != NULL) { 832fb47a376SStephen J. Kiernan mac_veriexec_set_fingerprint_status(ldvp, fp_status); 833fb47a376SStephen J. Kiernan return; 834fb47a376SStephen J. Kiernan } 835fb47a376SStephen J. Kiernan SLOT_SET(vp->v_label, fp_status); 836fb47a376SStephen J. Kiernan } 837fb47a376SStephen J. Kiernan 838fb47a376SStephen J. Kiernan /** 839fb47a376SStephen J. Kiernan * @brief Set verified execution subsystem state flags 840fb47a376SStephen J. Kiernan * 841fb47a376SStephen J. Kiernan * @note Flags can only be added to the current state, not removed. 842fb47a376SStephen J. Kiernan * 843fb47a376SStephen J. Kiernan * @param state state flags to add to the current state 844fb47a376SStephen J. Kiernan */ 845fb47a376SStephen J. Kiernan void 846fb47a376SStephen J. Kiernan mac_veriexec_set_state(int state) 847fb47a376SStephen J. Kiernan { 848fb47a376SStephen J. Kiernan 849fb47a376SStephen J. Kiernan mac_veriexec_state |= state; 850fb47a376SStephen J. Kiernan } 851fb47a376SStephen J. Kiernan 852fb47a376SStephen J. Kiernan /** 853fb47a376SStephen J. Kiernan * @brief Determine if the process is trusted 854fb47a376SStephen J. Kiernan * 855fb47a376SStephen J. Kiernan * @param cred credentials to use 856fb47a376SStephen J. Kiernan * @param p the process in question 857fb47a376SStephen J. Kiernan * 858fb47a376SStephen J. Kiernan * @return 1 if the process is trusted, otherwise 0. 859fb47a376SStephen J. Kiernan */ 860fb47a376SStephen J. Kiernan int 861fb47a376SStephen J. Kiernan mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p) 862fb47a376SStephen J. Kiernan { 8633da3012aSStephen J. Kiernan int already_locked, error, flags; 8643da3012aSStephen J. Kiernan 8653da3012aSStephen J. Kiernan /* Make sure we lock the process if we do not already have the lock */ 8663da3012aSStephen J. Kiernan already_locked = PROC_LOCKED(p); 8673da3012aSStephen J. Kiernan if (!already_locked) 8683da3012aSStephen J. Kiernan PROC_LOCK(p); 869fb47a376SStephen J. Kiernan 870fb47a376SStephen J. Kiernan error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0); 871fb47a376SStephen J. Kiernan 8723da3012aSStephen J. Kiernan /* Unlock the process if we locked it previously */ 8733da3012aSStephen J. Kiernan if (!already_locked) 8743da3012aSStephen J. Kiernan PROC_UNLOCK(p); 8753da3012aSStephen J. Kiernan 876fb47a376SStephen J. Kiernan /* Any errors, deny access */ 877fb47a376SStephen J. Kiernan if (error != 0) 878fb47a376SStephen J. Kiernan return (0); 879fb47a376SStephen J. Kiernan 880fb47a376SStephen J. Kiernan /* Check that the trusted flag is set */ 881fb47a376SStephen J. Kiernan return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED); 882fb47a376SStephen J. Kiernan } 883