The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_veriexec.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_veriexec.c,v 1.26 2020/06/11 02:30:21 thorpej Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
    5  * Copyright (c) 2005, 2006 Brett Lymn <blymn@NetBSD.org>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name of the authors may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __KERNEL_RCSID(0, "$NetBSD: kern_veriexec.c,v 1.26 2020/06/11 02:30:21 thorpej Exp $");
   33 
   34 #include "opt_veriexec.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/mount.h>
   38 #include <sys/kmem.h>
   39 #include <sys/vnode.h>
   40 #include <sys/namei.h>
   41 #include <sys/once.h>
   42 #include <sys/proc.h>
   43 #include <sys/rwlock.h>
   44 #include <sys/syslog.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/inttypes.h>
   47 #include <sys/verified_exec.h>
   48 #include <sys/sha1.h>
   49 #include <sys/sha2.h>
   50 #include <sys/rmd160.h>
   51 #include <sys/md5.h>
   52 #include <sys/fileassoc.h>
   53 #include <sys/kauth.h>
   54 #include <sys/conf.h>
   55 #include <miscfs/specfs/specdev.h>
   56 #include <prop/proplib.h>
   57 #include <sys/fcntl.h>
   58 
   59 /* Readable values for veriexec_file_report(). */
   60 #define REPORT_ALWAYS           0x01    /* Always print */
   61 #define REPORT_VERBOSE          0x02    /* Print when verbose >= 1 */
   62 #define REPORT_DEBUG            0x04    /* Print when verbose >= 2 (debug) */
   63 #define REPORT_PANIC            0x08    /* Call panic() */
   64 #define REPORT_ALARM            0x10    /* Alarm - also print pid/uid/.. */
   65 #define REPORT_LOGMASK          (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG)
   66 
   67 /* state of locking for veriexec_file_verify */
   68 #define VERIEXEC_UNLOCKED       0x00    /* Nothing locked, callee does it */
   69 #define VERIEXEC_LOCKED         0x01    /* Global op lock held */
   70 
   71 /* state of file locking for veriexec_file_verify */
   72 #define VERIEXEC_FILE_UNLOCKED  0x02    /* Nothing locked, callee does it */
   73 #define VERIEXEC_FILE_LOCKED    0x04    /* File locked */
   74 
   75 #define VERIEXEC_RW_UPGRADE(lock)       while((rw_tryupgrade(lock)) == 0){};
   76 
   77 struct veriexec_fpops {
   78         const char *type;
   79         size_t hash_len;
   80         size_t context_size;
   81         veriexec_fpop_init_t init;
   82         veriexec_fpop_update_t update;
   83         veriexec_fpop_final_t final;
   84         LIST_ENTRY(veriexec_fpops) entries;
   85 };
   86 
   87 /* Veriexec per-file entry data. */
   88 struct veriexec_file_entry {
   89         krwlock_t lock;                         /* r/w lock */
   90         u_char *filename;                       /* File name. */
   91         u_char type;                            /* Entry type. */
   92         u_char status;                          /* Evaluation status. */
   93         u_char *fp;                             /* Fingerprint. */
   94         struct veriexec_fpops *ops;             /* Fingerprint ops vector*/
   95         size_t filename_len;                    /* Length of filename. */
   96 };
   97 
   98 /* Veriexec per-table data. */
   99 struct veriexec_table_entry {
  100         uint64_t vte_count;                     /* Number of Veriexec entries. */
  101         const struct sysctlnode *vte_node;
  102 };
  103 
  104 static int veriexec_verbose;
  105 static int veriexec_strict;
  106 static int veriexec_bypass = 1;
  107 
  108 static char *veriexec_fp_names = NULL;
  109 static size_t veriexec_name_max = 0;
  110 
  111 static const struct sysctlnode *veriexec_count_node;
  112 
  113 static fileassoc_t veriexec_hook;
  114 static specificdata_key_t veriexec_mountspecific_key;
  115 
  116 static LIST_HEAD(, veriexec_fpops) veriexec_fpops_list =
  117         LIST_HEAD_INITIALIZER(veriexec_fpops_list);
  118 
  119 static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *,
  120     void *, void *, void *, void *);
  121 static struct veriexec_fpops *veriexec_fpops_lookup(const char *);
  122 static void veriexec_file_free(struct veriexec_file_entry *);
  123 
  124 static unsigned int veriexec_tablecount = 0;
  125 
  126 /*
  127  * Veriexec operations global lock - most ops hold this as a read
  128  * lock, it is upgraded to a write lock when destroying veriexec file
  129  * table entries.
  130  */
  131 static krwlock_t veriexec_op_lock;
  132 
  133 /*
  134  * Sysctl helper routine for Veriexec.
  135  */
  136 static int
  137 sysctl_kern_veriexec_algorithms(SYSCTLFN_ARGS)
  138 {
  139         size_t len;
  140         int error;
  141         const char *p;
  142 
  143         if (newp != NULL)
  144                 return EPERM;
  145 
  146         if (namelen != 0)
  147                 return EINVAL;
  148 
  149         p = veriexec_fp_names == NULL ? "" : veriexec_fp_names;
  150 
  151         len = strlen(p) + 1;
  152 
  153         if (*oldlenp < len && oldp)
  154                 return ENOMEM;
  155 
  156         if (oldp && (error = copyout(p, oldp, len)) != 0)
  157                 return error;
  158 
  159         *oldlenp = len;
  160         return 0;
  161 }
  162 
  163 static int
  164 sysctl_kern_veriexec_strict(SYSCTLFN_ARGS)
  165 {
  166         struct sysctlnode node;
  167         int error, newval;
  168 
  169         node = *rnode;
  170         node.sysctl_data = &newval;
  171 
  172         newval = veriexec_strict;
  173         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  174         if (error || newp == NULL)
  175                 return error;
  176 
  177         if (newval < veriexec_strict)
  178                 return EPERM;
  179 
  180         veriexec_strict = newval;
  181 
  182         return 0;
  183 }
  184 
  185 SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup")
  186 {
  187         const struct sysctlnode *rnode = NULL;
  188 
  189         sysctl_createv(clog, 0, NULL, &rnode,
  190                        CTLFLAG_PERMANENT,
  191                        CTLTYPE_NODE, "veriexec",
  192                        SYSCTL_DESCR("Veriexec"),
  193                        NULL, 0, NULL, 0,
  194                        CTL_KERN, CTL_CREATE, CTL_EOL);
  195 
  196         sysctl_createv(clog, 0, &rnode, NULL,
  197                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  198                        CTLTYPE_INT, "verbose",
  199                        SYSCTL_DESCR("Veriexec verbose level"),
  200                        NULL, 0, &veriexec_verbose, 0,
  201                        CTL_CREATE, CTL_EOL);
  202         sysctl_createv(clog, 0, &rnode, NULL,
  203                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  204                        CTLTYPE_INT, "strict",
  205                        SYSCTL_DESCR("Veriexec strict level"),
  206                        sysctl_kern_veriexec_strict, 0, NULL, 0,
  207                        CTL_CREATE, CTL_EOL);
  208         sysctl_createv(clog, 0, &rnode, NULL,
  209                        CTLFLAG_PERMANENT,
  210                        CTLTYPE_STRING, "algorithms",
  211                        SYSCTL_DESCR("Veriexec supported hashing "
  212                                     "algorithms"),
  213                        sysctl_kern_veriexec_algorithms, 0, NULL, 0,
  214                        CTL_CREATE, CTL_EOL);
  215         sysctl_createv(clog, 0, &rnode, &veriexec_count_node,
  216                        CTLFLAG_PERMANENT,
  217                        CTLTYPE_NODE, "count",
  218                        SYSCTL_DESCR("Number of fingerprints on mount(s)"),
  219                        NULL, 0, NULL, 0,
  220                        CTL_CREATE, CTL_EOL);
  221 }
  222 
  223 /*
  224  * Add ops to the fingerprint ops vector list.
  225  */
  226 int
  227 veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size,
  228     veriexec_fpop_init_t init, veriexec_fpop_update_t update,
  229     veriexec_fpop_final_t final)
  230 {
  231         struct veriexec_fpops *ops;
  232 
  233         KASSERT((init != NULL) && (update != NULL) && (final != NULL));
  234         KASSERT((hash_len != 0) && (ctx_size != 0));
  235         KASSERT(fp_type != NULL);
  236 
  237         if (veriexec_fpops_lookup(fp_type) != NULL)
  238                 return (EEXIST);
  239 
  240         ops = kmem_alloc(sizeof(*ops), KM_SLEEP);
  241         ops->type = fp_type;
  242         ops->hash_len = hash_len;
  243         ops->context_size = ctx_size;
  244         ops->init = init;
  245         ops->update = update;
  246         ops->final = final;
  247 
  248         LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries);
  249 
  250         /*
  251          * If we don't have space for any names, allocate enough for six
  252          * which should be sufficient. (it's also enough for all algorithms
  253          * we can support at the moment)
  254          */
  255         if (veriexec_fp_names == NULL) {
  256                 veriexec_name_max = 64;
  257                 veriexec_fp_names = kmem_zalloc(veriexec_name_max, KM_SLEEP);
  258         }
  259 
  260         /*
  261          * If we're running out of space for storing supported algorithms,
  262          * extend the buffer with space for four names.
  263          */
  264         while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) <
  265             strlen(fp_type)) {
  266                 char *newp;
  267                 unsigned int new_max;
  268 
  269                 /* Add space for four algorithm names. */
  270                 new_max = veriexec_name_max + 64;
  271                 newp = kmem_zalloc(new_max, KM_SLEEP);
  272                 strlcpy(newp, veriexec_fp_names, new_max);
  273                 kmem_free(veriexec_fp_names, veriexec_name_max);
  274                 veriexec_fp_names = newp;
  275                 veriexec_name_max = new_max;
  276         }
  277 
  278         if (*veriexec_fp_names != '\0')
  279                 strlcat(veriexec_fp_names, " ", veriexec_name_max);
  280 
  281         strlcat(veriexec_fp_names, fp_type, veriexec_name_max);
  282 
  283         return (0);
  284 }
  285 
  286 static void
  287 veriexec_mountspecific_dtor(void *v)
  288 {
  289         struct veriexec_table_entry *vte = v;
  290 
  291         if (vte == NULL) {
  292                 return;
  293         }
  294         sysctl_free(__UNCONST(vte->vte_node));
  295         veriexec_tablecount--;
  296         kmem_free(vte, sizeof(*vte));
  297 }
  298 
  299 static int
  300 veriexec_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
  301     void *arg0, void *arg1, void *arg2, void *arg3)
  302 {
  303         int result;
  304         enum kauth_system_req req;
  305 
  306         if (action != KAUTH_SYSTEM_VERIEXEC)
  307                 return KAUTH_RESULT_DEFER;
  308 
  309         result = KAUTH_RESULT_DEFER;
  310         req = (enum kauth_system_req)(uintptr_t)arg0;
  311 
  312         if (req == KAUTH_REQ_SYSTEM_VERIEXEC_MODIFY &&
  313             veriexec_strict > VERIEXEC_LEARNING) {
  314                 log(LOG_WARNING, "Veriexec: Strict mode, modifying "
  315                     "tables not permitted.\n");
  316 
  317                 result = KAUTH_RESULT_DENY;
  318         }
  319 
  320         return result;
  321 }
  322 
  323 /*
  324  * Initialise Veriexec.
  325  */
  326 void
  327 veriexec_init(void)
  328 {
  329         int error;
  330 
  331         /* Register a fileassoc for Veriexec. */
  332         error = fileassoc_register("veriexec",
  333             (fileassoc_cleanup_cb_t)veriexec_file_free, &veriexec_hook);
  334         if (error)
  335                 panic("Veriexec: Can't register fileassoc: error=%d", error);
  336 
  337         /* Register listener to handle raw disk access. */
  338         if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) ==
  339             NULL)
  340                 panic("Veriexec: Can't listen on device scope");
  341 
  342         error = mount_specific_key_create(&veriexec_mountspecific_key,
  343             veriexec_mountspecific_dtor);
  344         if (error)
  345                 panic("Veriexec: Can't create mountspecific key");
  346 
  347         if (kauth_listen_scope(KAUTH_SCOPE_SYSTEM, veriexec_listener_cb,
  348             NULL) == NULL)
  349                 panic("Veriexec: Can't listen on system scope");
  350 
  351         rw_init(&veriexec_op_lock);
  352 
  353 #define FPOPS_ADD(a, b, c, d, e, f)                     \
  354         veriexec_fpops_add(a, b, c,                     \
  355             __FPTRCAST(veriexec_fpop_init_t, d),        \
  356             __FPTRCAST(veriexec_fpop_update_t, e),      \
  357             __FPTRCAST(veriexec_fpop_final_t, f))
  358 
  359 #ifdef VERIFIED_EXEC_FP_SHA256
  360         FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX),
  361             SHA256_Init, SHA256_Update, SHA256_Final);
  362 #endif /* VERIFIED_EXEC_FP_SHA256 */
  363 
  364 #ifdef VERIFIED_EXEC_FP_SHA384
  365         FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX),
  366             SHA384_Init, SHA384_Update, SHA384_Final);
  367 #endif /* VERIFIED_EXEC_FP_SHA384 */
  368 
  369 #ifdef VERIFIED_EXEC_FP_SHA512
  370         FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX),
  371             SHA512_Init, SHA512_Update, SHA512_Final);
  372 #endif /* VERIFIED_EXEC_FP_SHA512 */
  373 
  374 #undef FPOPS_ADD
  375 }
  376 
  377 static struct veriexec_fpops *
  378 veriexec_fpops_lookup(const char *name)
  379 {
  380         struct veriexec_fpops *ops;
  381 
  382         if (name == NULL)
  383                 return (NULL);
  384 
  385         LIST_FOREACH(ops, &veriexec_fpops_list, entries) {
  386                 if (strcasecmp(name, ops->type) == 0)
  387                         return (ops);
  388         }
  389 
  390         return (NULL);
  391 }
  392 
  393 /*
  394  * Calculate fingerprint. Information on hash length and routines used is
  395  * extracted from veriexec_hash_list according to the hash type.
  396  *
  397  * NOTE: vfe is assumed to be locked for writing on entry.
  398  */
  399 static int
  400 veriexec_fp_calc(struct lwp *l, struct vnode *vp, int file_lock_state,
  401     struct veriexec_file_entry *vfe, u_char *fp)
  402 {
  403         struct vattr va;
  404         void *ctx;
  405         u_char *buf;
  406         off_t offset, len;
  407         size_t resid;
  408         int error;
  409 
  410         KASSERT(file_lock_state != VERIEXEC_LOCKED);
  411         KASSERT(file_lock_state != VERIEXEC_UNLOCKED);
  412 
  413         if (file_lock_state == VERIEXEC_FILE_UNLOCKED)
  414                 vn_lock(vp, LK_SHARED | LK_RETRY);
  415         error = VOP_GETATTR(vp, &va, l->l_cred);
  416         if (file_lock_state == VERIEXEC_FILE_UNLOCKED)
  417                 VOP_UNLOCK(vp);
  418         if (error)
  419                 return (error);
  420 
  421         ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP);
  422         buf = kmem_alloc(PAGE_SIZE, KM_SLEEP);
  423 
  424         (vfe->ops->init)(ctx);
  425 
  426         len = 0;
  427         error = 0;
  428         for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) {
  429                 len = ((va.va_size - offset) < PAGE_SIZE) ?
  430                     (va.va_size - offset) : PAGE_SIZE;
  431 
  432                 error = vn_rdwr(UIO_READ, vp, buf, len, offset,
  433                                 UIO_SYSSPACE,
  434                                 ((file_lock_state == VERIEXEC_FILE_LOCKED)?
  435                                  IO_NODELOCKED : 0),
  436                                 l->l_cred, &resid, NULL);
  437 
  438                 if (error) {
  439                         goto bad;
  440                 }
  441 
  442                 (vfe->ops->update)(ctx, buf, (unsigned int) len);
  443 
  444                 if (len != PAGE_SIZE)
  445                         break;
  446         }
  447 
  448         (vfe->ops->final)(fp, ctx);
  449 
  450 bad:
  451         kmem_free(ctx, vfe->ops->context_size);
  452         kmem_free(buf, PAGE_SIZE);
  453 
  454         return (error);
  455 }
  456 
  457 /* Compare two fingerprints of the same type. */
  458 static int
  459 veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2)
  460 {
  461         if (veriexec_verbose >= 2) {
  462                 int i;
  463 
  464                 printf("comparing hashes...\n");
  465                 printf("fp1: ");
  466                 for (i = 0; i < ops->hash_len; i++) {
  467                         printf("%02x", fp1[i]);
  468                 }
  469                 printf("\nfp2: ");
  470                 for (i = 0; i < ops->hash_len; i++) {
  471                         printf("%02x", fp2[i]);
  472                 }
  473                 printf("\n");
  474         }
  475 
  476         return (memcmp(fp1, fp2, ops->hash_len));
  477 }
  478 
  479 static int
  480 veriexec_fp_status(struct lwp *l, struct vnode *vp, int file_lock_state,
  481     struct veriexec_file_entry *vfe, u_char *status)
  482 {
  483         size_t hash_len = vfe->ops->hash_len;
  484         u_char *digest;
  485         int error;
  486 
  487         digest = kmem_zalloc(hash_len, KM_SLEEP);
  488 
  489         error = veriexec_fp_calc(l, vp, file_lock_state, vfe, digest);
  490         if (error)
  491                 goto out;
  492 
  493         /* Compare fingerprint with loaded data. */
  494         if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0)
  495                 *status = FINGERPRINT_VALID;
  496         else
  497                 *status = FINGERPRINT_NOMATCH;
  498 
  499 out:
  500         kmem_free(digest, hash_len);
  501         return error;
  502 }
  503 
  504 
  505 static struct veriexec_table_entry *
  506 veriexec_table_lookup(struct mount *mp)
  507 {
  508         /* XXX: From raidframe init */
  509         if (mp == NULL)
  510                 return NULL;
  511 
  512         return mount_getspecific(mp, veriexec_mountspecific_key);
  513 }
  514 
  515 static struct veriexec_file_entry *
  516 veriexec_get(struct vnode *vp)
  517 {
  518         return (fileassoc_lookup(vp, veriexec_hook));
  519 }
  520 
  521 bool
  522 veriexec_lookup(struct vnode *vp)
  523 {
  524         return (veriexec_get(vp) == NULL ? false : true);
  525 }
  526 
  527 /*
  528  * Routine for maintaining mostly consistent message formats in Veriexec.
  529  */
  530 static void
  531 veriexec_file_report(struct veriexec_file_entry *vfe, const u_char *msg,
  532     const u_char *filename, struct lwp *l, int f)
  533 {
  534         if (vfe != NULL && vfe->filename != NULL)
  535                 filename = vfe->filename;
  536         if (filename == NULL)
  537                 return;
  538 
  539         if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) {
  540                 if (!(f & REPORT_ALARM) || (l == NULL))
  541                         log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg,
  542                             filename);
  543                 else
  544                         log(LOG_ALERT, "Veriexec: %s [%s, prog=%s pid=%u, "
  545                             "uid=%u, gid=%u]\n", msg, filename,
  546                             l->l_proc->p_comm, l->l_proc->p_pid,
  547                             kauth_cred_getuid(l->l_cred),
  548                             kauth_cred_getgid(l->l_cred));
  549         }
  550 
  551         if (f & REPORT_PANIC)
  552                 panic("Veriexec: Unrecoverable error.");
  553 }
  554 
  555 /*
  556  * Verify the fingerprint of the given file. If we're called directly from
  557  * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from
  558  * exec_script(), 'flag' will be VERIEXEC_INDIRECT.  If we are called from
  559  * vn_open(), 'flag' will be VERIEXEC_FILE.
  560  *
  561  * 'veriexec_op_lock' must be locked (and remains locked).
  562  *
  563  * NOTE: The veriexec file entry pointer (vfep) will be returned LOCKED
  564  *       on no error.
  565  */
  566 static int
  567 veriexec_file_verify(struct lwp *l, struct vnode *vp, const u_char *name,
  568     int flag, int file_lock_state, struct veriexec_file_entry **vfep)
  569 {
  570         struct veriexec_file_entry *vfe;
  571         int error = 0;
  572 
  573         KASSERT(rw_lock_held(&veriexec_op_lock));
  574         KASSERT(file_lock_state != VERIEXEC_LOCKED);
  575         KASSERT(file_lock_state != VERIEXEC_UNLOCKED);
  576 
  577 #define VFE_NEEDS_EVAL(vfe) ((vfe->status == FINGERPRINT_NOTEVAL) || \
  578                              (vfe->type & VERIEXEC_UNTRUSTED))
  579 
  580         if (vfep != NULL)
  581                 *vfep = NULL;
  582 
  583         if (vp->v_type != VREG)
  584                 return (0);
  585 
  586         /* Lookup veriexec table entry, save pointer if requested. */
  587         vfe = veriexec_get(vp);
  588         if (vfep != NULL)
  589                 *vfep = vfe;
  590 
  591         /* No entry in the veriexec tables. */
  592         if (vfe == NULL) {
  593                 veriexec_file_report(NULL, "No entry.", name,
  594                     l, REPORT_VERBOSE);
  595 
  596                 /*
  597                  * Lockdown mode: Deny access to non-monitored files.
  598                  * IPS mode: Deny execution of non-monitored files.
  599                  */
  600                 if ((veriexec_strict >= VERIEXEC_LOCKDOWN) ||
  601                     ((veriexec_strict >= VERIEXEC_IPS) &&
  602                      (flag != VERIEXEC_FILE)))
  603                         return (EPERM);
  604 
  605                 return (0);
  606         }
  607 
  608         /*
  609          * Grab the lock for the entry, if we need to do an evaluation
  610          * then the lock is a write lock, after we have the write
  611          * lock, check if we really need it - some other thread may
  612          * have already done the work for us.
  613          */
  614         if (VFE_NEEDS_EVAL(vfe)) {
  615                 rw_enter(&vfe->lock, RW_WRITER);
  616                 if (!VFE_NEEDS_EVAL(vfe))
  617                         rw_downgrade(&vfe->lock);
  618         } else
  619                 rw_enter(&vfe->lock, RW_READER);
  620 
  621         /* Evaluate fingerprint if needed. */
  622         if (VFE_NEEDS_EVAL(vfe)) {
  623                 u_char status;
  624 
  625                 error = veriexec_fp_status(l, vp, file_lock_state, vfe, &status);
  626                 if (error) {
  627                         veriexec_file_report(vfe, "Fingerprint calculation error.",
  628                             name, NULL, REPORT_ALWAYS);
  629                         rw_exit(&vfe->lock);
  630                         return (error);
  631                 }
  632                 vfe->status = status;
  633                 rw_downgrade(&vfe->lock);
  634         }
  635 
  636         if (!(vfe->type & flag)) {
  637                 veriexec_file_report(vfe, "Incorrect access type.", name, l,
  638                     REPORT_ALWAYS|REPORT_ALARM);
  639 
  640                 /* IPS mode: Enforce access type. */
  641                 if (veriexec_strict >= VERIEXEC_IPS) {
  642                         rw_exit(&vfe->lock);
  643                         return (EPERM);
  644                 }
  645         }
  646 
  647         switch (vfe->status) {
  648         case FINGERPRINT_NOTEVAL:
  649                 /* Should not happen. */
  650                 rw_exit(&vfe->lock);
  651                 veriexec_file_report(vfe, "Not-evaluated status "
  652                     "post evaluation; inconsistency detected.", name,
  653                     NULL, REPORT_ALWAYS|REPORT_PANIC);
  654                 __builtin_unreachable();
  655                 /* NOTREACHED */
  656 
  657         case FINGERPRINT_VALID:
  658                 /* Valid fingerprint. */
  659                 veriexec_file_report(vfe, "Match.", name, NULL,
  660                     REPORT_VERBOSE);
  661 
  662                 break;
  663 
  664         case FINGERPRINT_NOMATCH:
  665                 /* Fingerprint mismatch. */
  666                 veriexec_file_report(vfe, "Mismatch.", name,
  667                     NULL, REPORT_ALWAYS|REPORT_ALARM);
  668 
  669                 /* IDS mode: Deny access on fingerprint mismatch. */
  670                 if (veriexec_strict >= VERIEXEC_IDS) {
  671                         rw_exit(&vfe->lock);
  672                         error = EPERM;
  673                 }
  674 
  675                 break;
  676 
  677         default:
  678                 /* Should never happen. */
  679                 rw_exit(&vfe->lock);
  680                 veriexec_file_report(vfe, "Invalid status "
  681                     "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC);
  682                 /* NOTREACHED */
  683         }
  684 
  685         return (error);
  686 }
  687 
  688 int
  689 veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
  690     bool *found)
  691 {
  692         struct veriexec_file_entry *vfe;
  693         int r;
  694 
  695         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
  696                 return 0;
  697 
  698         rw_enter(&veriexec_op_lock, RW_READER);
  699         r = veriexec_file_verify(l, vp, name, flag, VERIEXEC_FILE_UNLOCKED,
  700             &vfe);
  701         rw_exit(&veriexec_op_lock);
  702 
  703         if ((r  == 0) && (vfe != NULL))
  704                 rw_exit(&vfe->lock);
  705 
  706         if (found != NULL)
  707                 *found = (vfe != NULL) ? true : false;
  708 
  709         return (r);
  710 }
  711 
  712 /*
  713  * Veriexec remove policy code.
  714  */
  715 int
  716 veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf)
  717 {
  718         struct veriexec_file_entry *vfe;
  719         int error;
  720 
  721         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
  722                 return 0;
  723 
  724         rw_enter(&veriexec_op_lock, RW_READER);
  725         vfe = veriexec_get(vp);
  726         rw_exit(&veriexec_op_lock);
  727 
  728         if (vfe == NULL) {
  729                 /* Lockdown mode: Deny access to non-monitored files. */
  730                 if (veriexec_strict >= VERIEXEC_LOCKDOWN)
  731                         return (EPERM);
  732 
  733                 return (0);
  734         }
  735 
  736         veriexec_file_report(vfe, "Remove request.", pathbuf, l,
  737             REPORT_ALWAYS|REPORT_ALARM);
  738 
  739         /* IDS mode: Deny removal of monitored files. */
  740         if (veriexec_strict >= VERIEXEC_IDS)
  741                 error = EPERM;
  742         else
  743                 error = veriexec_file_delete(l, vp);
  744 
  745         return error;
  746 }
  747 
  748 /*
  749  * Veriexec rename policy.
  750  *
  751  * XXX: Once there's a way to hook after a successful rename, it would be
  752  * XXX: nice to update vfe->filename to the new name if it's not NULL and
  753  * XXX: the new name is absolute (ie., starts with a slash).
  754  */
  755 int
  756 veriexec_renamechk(struct lwp *l, struct vnode *fromvp, const char *fromname,
  757     struct vnode *tovp, const char *toname)
  758 {
  759         struct veriexec_file_entry *fvfe = NULL, *tvfe = NULL;
  760 
  761         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
  762                 return 0;
  763 
  764         rw_enter(&veriexec_op_lock, RW_READER);
  765 
  766         if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
  767                 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to "
  768                     "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname,
  769                     kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
  770                 rw_exit(&veriexec_op_lock);
  771                 return (EPERM);
  772         }
  773 
  774         fvfe = veriexec_get(fromvp);
  775         if (tovp != NULL)
  776                 tvfe = veriexec_get(tovp);
  777 
  778         if ((fvfe == NULL) && (tvfe == NULL)) {
  779                 /* None of them is monitored */
  780                 rw_exit(&veriexec_op_lock);
  781                 return 0;
  782         }
  783 
  784         if (veriexec_strict >= VERIEXEC_IPS) {
  785                 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' "
  786                     "to `%s', uid=%u, pid=%u: IPS mode, %s "
  787                     "monitored.\n", fromname, toname,
  788                     kauth_cred_geteuid(l->l_cred),
  789                     l->l_proc->p_pid, (fvfe != NULL && tvfe != NULL) ?
  790                     "files" : "file");
  791                 rw_exit(&veriexec_op_lock);
  792                 return (EPERM);
  793         }
  794 
  795         if (fvfe != NULL) {
  796                 /*
  797                  * Monitored file is renamed; filename no longer relevant.
  798                  */
  799 
  800                 /*
  801                  * XXX: We could keep the buffer, and when (and if) updating the
  802                  * XXX: filename post-rename, re-allocate it only if it's not
  803                  * XXX: big enough for the new filename.
  804                  */
  805 
  806                 /* XXX: Get write lock on fvfe here? */
  807 
  808                 VERIEXEC_RW_UPGRADE(&veriexec_op_lock);
  809                 /* once we have the op lock in write mode
  810                  * there should be no locks on any file
  811                  * entries so we can destroy the object.
  812                  */
  813 
  814                 if (fvfe->filename_len > 0)
  815                         kmem_free(fvfe->filename, fvfe->filename_len);
  816 
  817                 fvfe->filename = NULL;
  818                 fvfe->filename_len = 0;
  819 
  820                 rw_downgrade(&veriexec_op_lock);
  821         }
  822 
  823         log(LOG_NOTICE, "Veriexec: %s file `%s' renamed to "
  824             "%s file `%s', uid=%u, pid=%u.\n", (fvfe != NULL) ?
  825             "Monitored" : "Non-monitored", fromname, (tvfe != NULL) ?
  826             "monitored" : "non-monitored", toname,
  827             kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
  828 
  829         rw_exit(&veriexec_op_lock);
  830 
  831         if (tvfe != NULL) {
  832                 /*
  833                  * Monitored file is overwritten. Remove the entry.
  834                  */
  835                 (void)veriexec_file_delete(l, tovp);
  836         }
  837 
  838         return (0);
  839 }
  840 
  841 static void
  842 veriexec_file_free(struct veriexec_file_entry *vfe)
  843 {
  844         if (vfe != NULL) {
  845                 if (vfe->fp != NULL)
  846                         kmem_free(vfe->fp, vfe->ops->hash_len);
  847                 if (vfe->filename != NULL)
  848                         kmem_free(vfe->filename, vfe->filename_len);
  849                 rw_destroy(&vfe->lock);
  850                 kmem_free(vfe, sizeof(*vfe));
  851         }
  852 }
  853 
  854 static void
  855 veriexec_file_purge(struct veriexec_file_entry *vfe, int have_lock)
  856 {
  857         if (vfe == NULL)
  858                 return;
  859 
  860         if (have_lock == VERIEXEC_UNLOCKED)
  861                 rw_enter(&vfe->lock, RW_WRITER);
  862         else
  863                 VERIEXEC_RW_UPGRADE(&vfe->lock);
  864 
  865         vfe->status = FINGERPRINT_NOTEVAL;
  866         if (have_lock == VERIEXEC_UNLOCKED)
  867                 rw_exit(&vfe->lock);
  868         else
  869                 rw_downgrade(&vfe->lock);
  870 }
  871 
  872 static void
  873 veriexec_file_purge_cb(struct veriexec_file_entry *vfe, void *cookie)
  874 {
  875         veriexec_file_purge(vfe, VERIEXEC_UNLOCKED);
  876 }
  877 
  878 /*
  879  * Invalidate a Veriexec file entry.
  880  * XXX: This should be updated when per-page fingerprints are added.
  881  */
  882 void
  883 veriexec_purge(struct vnode *vp)
  884 {
  885         rw_enter(&veriexec_op_lock, RW_READER);
  886         veriexec_file_purge(veriexec_get(vp), VERIEXEC_UNLOCKED);
  887         rw_exit(&veriexec_op_lock);
  888 }
  889 
  890 /*
  891  * Enforce raw disk access policy.
  892  *
  893  * IDS mode: Invalidate fingerprints on a mount if it's opened for writing.
  894  * IPS mode: Don't allow raw writing to disks we monitor.
  895  * Lockdown mode: Don't allow raw writing to all disks.
  896  *
  897  * XXX: This is bogus. There's an obvious race condition between the time
  898  * XXX: the disk is open for writing, in which an attacker can access a
  899  * XXX: monitored file to get its signature cached again, and when the raw
  900  * XXX: file is overwritten on disk.
  901  * XXX:
  902  * XXX: To solve this, we need something like the following:
  903  * XXX:         open raw disk:
  904  * XXX:           - raise refcount,
  905  * XXX:           - invalidate fingerprints,
  906  * XXX:           - mark all entries for that disk with "no cache" flag
  907  * XXX:
  908  * XXX:         veriexec_verify:
  909  * XXX:           - if "no cache", don't cache evaluation result
  910  * XXX:
  911  * XXX:         close raw disk:
  912  * XXX:           - lower refcount,
  913  * XXX:           - if refcount == 0, remove "no cache" flag from all entries
  914  */
  915 static int
  916 veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
  917     void *arg0, void *arg1, void *arg2, void *arg3)
  918 {
  919         int result;
  920         enum kauth_device_req req;
  921         struct veriexec_table_entry *vte;
  922 
  923         result = KAUTH_RESULT_DENY;
  924         req = (enum kauth_device_req)(uintptr_t)arg0;
  925 
  926         switch (action) {
  927         case KAUTH_DEVICE_RAWIO_SPEC: {
  928                 struct vnode *vp, *bvp;
  929                 int error;
  930 
  931                 if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) {
  932                         result = KAUTH_RESULT_DEFER;
  933                         break;
  934                 }
  935 
  936                 vp = arg1;
  937                 KASSERT(vp != NULL);
  938 
  939                 /* Handle /dev/mem and /dev/kmem. */
  940                 if (iskmemvp(vp)) {
  941                         if (veriexec_strict < VERIEXEC_IPS)
  942                                 result = KAUTH_RESULT_DEFER;
  943 
  944                         break;
  945                 }
  946 
  947                 error = rawdev_mounted(vp, &bvp);
  948                 if (error == EINVAL) {
  949                         result = KAUTH_RESULT_DEFER;
  950                         break;
  951                 }
  952 
  953                 /*
  954                  * XXX: See vfs_mountedon() comment in rawdev_mounted().
  955                  */
  956                 vte = veriexec_table_lookup(bvp->v_mount);
  957                 if (vte == NULL) {
  958                         result = KAUTH_RESULT_DEFER;
  959                         break;
  960                 }
  961 
  962                 switch (veriexec_strict) {
  963                 case VERIEXEC_LEARNING:
  964                 case VERIEXEC_IDS:
  965                         result = KAUTH_RESULT_DEFER;
  966 
  967                         rw_enter(&veriexec_op_lock, RW_WRITER);
  968                         fileassoc_table_run(bvp->v_mount, veriexec_hook,
  969                             (fileassoc_cb_t)veriexec_file_purge_cb, NULL);
  970                         rw_exit(&veriexec_op_lock);
  971 
  972                         break;
  973                 case VERIEXEC_IPS:
  974                         result = KAUTH_RESULT_DENY;
  975                         break;
  976                 case VERIEXEC_LOCKDOWN:
  977                         result = KAUTH_RESULT_DENY;
  978                         break;
  979                 }
  980 
  981                 break;
  982                 }
  983 
  984         case KAUTH_DEVICE_RAWIO_PASSTHRU:
  985                 /* XXX What can we do here? */
  986                 if (veriexec_strict < VERIEXEC_IPS)
  987                         result = KAUTH_RESULT_DEFER;
  988 
  989                 break;
  990 
  991         default:
  992                 result = KAUTH_RESULT_DEFER;
  993                 break;
  994         }
  995 
  996         return (result);
  997 }
  998 
  999 /*
 1000  * Create a new Veriexec table.
 1001  */
 1002 static struct veriexec_table_entry *
 1003 veriexec_table_add(struct lwp *l, struct mount *mp)
 1004 {
 1005         struct veriexec_table_entry *vte;
 1006         u_char buf[16];
 1007 
 1008         vte = kmem_zalloc(sizeof(*vte), KM_SLEEP);
 1009         mount_setspecific(mp, veriexec_mountspecific_key, vte);
 1010 
 1011         snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++);
 1012         sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node,
 1013                        0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL,
 1014                        0, CTL_CREATE, CTL_EOL);
 1015 
 1016         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1017                        CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt",
 1018                        NULL, NULL, 0, mp->mnt_stat.f_mntonname,
 1019                        0, CTL_CREATE, CTL_EOL);
 1020         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1021                        CTLFLAG_READONLY, CTLTYPE_STRING, "fstype",
 1022                        NULL, NULL, 0, mp->mnt_stat.f_fstypename,
 1023                        0, CTL_CREATE, CTL_EOL);
 1024         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1025                        CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries",
 1026                        NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL);
 1027 
 1028         return (vte);
 1029 }
 1030 
 1031 /*
 1032  * Add a file to be monitored by Veriexec.
 1033  *
 1034  * Expected elements in dict:
 1035  *     file, fp, fp-type, entry-type, keep-filename, eval-on-load.
 1036  */
 1037 int
 1038 veriexec_file_add(struct lwp *l, prop_dictionary_t dict)
 1039 {
 1040         struct veriexec_table_entry *vte;
 1041         struct veriexec_file_entry *vfe = NULL;
 1042         struct veriexec_file_entry *ovfe;
 1043         struct vnode *vp;
 1044         const char *file, *fp_type;
 1045         int error;
 1046         bool ignore_dup = false;
 1047 
 1048         if (!prop_dictionary_get_string(dict, "file", &file))
 1049                 return (EINVAL);
 1050 
 1051         error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp);
 1052         if (error)
 1053                 return (error);
 1054 
 1055         /* Add only regular files. */
 1056         if (vp->v_type != VREG) {
 1057                 log(LOG_ERR, "Veriexec: Not adding `%s': Not a regular file.\n",
 1058                     file);
 1059                 error = EBADF;
 1060                 goto out;
 1061         }
 1062 
 1063         vfe = kmem_zalloc(sizeof(*vfe), KM_SLEEP);
 1064         rw_init(&vfe->lock);
 1065 
 1066         /* Lookup fingerprint hashing algorithm. */
 1067         fp_type = prop_string_value(prop_dictionary_get(dict, "fp-type"));
 1068         if ((vfe->ops = veriexec_fpops_lookup(fp_type)) == NULL) {
 1069                 log(LOG_ERR, "Veriexec: Invalid or unknown fingerprint type "
 1070                     "`%s' for file `%s'.\n", fp_type, file);
 1071                 error = EOPNOTSUPP;
 1072                 goto out;
 1073         }
 1074 
 1075         if (prop_data_size(prop_dictionary_get(dict, "fp")) !=
 1076             vfe->ops->hash_len) {
 1077                 log(LOG_ERR, "Veriexec: Bad fingerprint length for `%s'.\n",
 1078                     file);
 1079                 error = EINVAL;
 1080                 goto out;
 1081         }
 1082 
 1083         vfe->fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP);
 1084         memcpy(vfe->fp, prop_data_value(prop_dictionary_get(dict, "fp")),
 1085             vfe->ops->hash_len);
 1086 
 1087         rw_enter(&veriexec_op_lock, RW_WRITER);
 1088 
 1089         /* Continue entry initialization. */
 1090         if (prop_dictionary_get_uint8(dict, "entry-type", &vfe->type) == FALSE)
 1091                 vfe->type = 0;
 1092         else {
 1093                 uint8_t extra_flags;
 1094 
 1095                 extra_flags = vfe->type & ~(VERIEXEC_DIRECT |
 1096                     VERIEXEC_INDIRECT | VERIEXEC_FILE | VERIEXEC_UNTRUSTED);
 1097                 if (extra_flags) {
 1098                         log(LOG_NOTICE, "Veriexec: Contaminated flags `0x%x' "
 1099                             "for `%s', skipping.\n", extra_flags, file);
 1100                         error = EINVAL;
 1101                         goto unlock_out;
 1102                 }
 1103         }
 1104         if (!(vfe->type & (VERIEXEC_DIRECT | VERIEXEC_INDIRECT |
 1105             VERIEXEC_FILE)))
 1106                 vfe->type |= VERIEXEC_DIRECT;
 1107 
 1108         vfe->status = FINGERPRINT_NOTEVAL;
 1109         if (prop_bool_true(prop_dictionary_get(dict, "keep-filename"))) {
 1110                 vfe->filename = kmem_strdupsize(file, &vfe->filename_len,
 1111                     KM_SLEEP);
 1112         } else
 1113                 vfe->filename = NULL;
 1114 
 1115         if (prop_bool_true(prop_dictionary_get(dict, "eval-on-load")) ||
 1116             (vfe->type & VERIEXEC_UNTRUSTED)) {
 1117                 u_char status;
 1118 
 1119                 error = veriexec_fp_status(l, vp, VERIEXEC_FILE_UNLOCKED,
 1120                     vfe, &status);
 1121                 if (error)
 1122                         goto unlock_out;
 1123                 vfe->status = status;
 1124         }
 1125 
 1126         /*
 1127          * If we already have an entry for this file, and it matches
 1128          * the new entry exactly (except for the filename, which may
 1129          * hard-linked!), we just ignore the new entry.  If the new
 1130          * entry differs, report the error.
 1131          */
 1132         if ((ovfe = veriexec_get(vp)) != NULL) {
 1133                 error = EEXIST;
 1134                 if (vfe->type == ovfe->type &&
 1135                     vfe->status == ovfe->status &&
 1136                     vfe->ops == ovfe->ops &&
 1137                     memcmp(vfe->fp, ovfe->fp, vfe->ops->hash_len) == 0)
 1138                         ignore_dup = true;
 1139                 goto unlock_out;
 1140         }
 1141 
 1142         vte = veriexec_table_lookup(vp->v_mount);
 1143         if (vte == NULL)
 1144                 vte = veriexec_table_add(l, vp->v_mount);
 1145 
 1146         /* XXX if we bail below this, we might want to gc newly created vtes. */
 1147 
 1148         error = fileassoc_add(vp, veriexec_hook, vfe);
 1149         if (error)
 1150                 goto unlock_out;
 1151 
 1152         vte->vte_count++;
 1153 
 1154         veriexec_file_report(NULL, "New entry.", file, NULL, REPORT_DEBUG);
 1155         veriexec_bypass = 0;
 1156 
 1157   unlock_out:
 1158         rw_exit(&veriexec_op_lock);
 1159 
 1160   out:
 1161         vrele(vp);
 1162         if (error)
 1163                 veriexec_file_free(vfe);
 1164 
 1165         if (ignore_dup && error == EEXIST)
 1166                 error = 0;
 1167 
 1168         return (error);
 1169 }
 1170 
 1171 int
 1172 veriexec_table_delete(struct lwp *l, struct mount *mp)
 1173 {
 1174         struct veriexec_table_entry *vte;
 1175 
 1176         vte = veriexec_table_lookup(mp);
 1177         if (vte == NULL)
 1178                 return (ENOENT);
 1179 
 1180         veriexec_mountspecific_dtor(vte);
 1181         mount_setspecific(mp, veriexec_mountspecific_key, NULL);
 1182 
 1183         return (fileassoc_table_clear(mp, veriexec_hook));
 1184 }
 1185 
 1186 int
 1187 veriexec_file_delete(struct lwp *l, struct vnode *vp)
 1188 {
 1189         struct veriexec_table_entry *vte;
 1190         int error;
 1191 
 1192         vte = veriexec_table_lookup(vp->v_mount);
 1193         if (vte == NULL)
 1194                 return (ENOENT);
 1195 
 1196         rw_enter(&veriexec_op_lock, RW_WRITER);
 1197         error = fileassoc_clear(vp, veriexec_hook);
 1198         rw_exit(&veriexec_op_lock);
 1199         if (!error) {
 1200                 KASSERT(vte->vte_count > 0);
 1201                 vte->vte_count--;
 1202         }
 1203 
 1204         return (error);
 1205 }
 1206 
 1207 /*
 1208  * Convert Veriexec entry data to a dictionary readable by userland tools.
 1209  */
 1210 static void
 1211 veriexec_file_convert(struct veriexec_file_entry *vfe, prop_dictionary_t rdict)
 1212 {
 1213         if (vfe->filename)
 1214                 prop_dictionary_set(rdict, "file",
 1215                     prop_string_create_copy(vfe->filename));
 1216         prop_dictionary_set_uint8(rdict, "entry-type", vfe->type);
 1217         prop_dictionary_set_uint8(rdict, "status", vfe->status);
 1218         prop_dictionary_set(rdict, "fp-type",
 1219             prop_string_create_copy(vfe->ops->type));
 1220         prop_dictionary_set(rdict, "fp",
 1221             prop_data_create_copy(vfe->fp, vfe->ops->hash_len));
 1222 }
 1223 
 1224 int
 1225 veriexec_convert(struct vnode *vp, prop_dictionary_t rdict)
 1226 {
 1227         struct veriexec_file_entry *vfe;
 1228 
 1229         rw_enter(&veriexec_op_lock, RW_READER);
 1230 
 1231         vfe = veriexec_get(vp);
 1232         if (vfe == NULL) {
 1233                 rw_exit(&veriexec_op_lock);
 1234                 return (ENOENT);
 1235         }
 1236 
 1237         rw_enter(&vfe->lock, RW_READER);
 1238         veriexec_file_convert(vfe, rdict);
 1239         rw_exit(&vfe->lock);
 1240 
 1241         rw_exit(&veriexec_op_lock);
 1242         return (0);
 1243 }
 1244 
 1245 int
 1246 veriexec_unmountchk(struct mount *mp)
 1247 {
 1248         int error;
 1249 
 1250         if ((veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
 1251             || doing_shutdown)
 1252                 return (0);
 1253 
 1254         rw_enter(&veriexec_op_lock, RW_READER);
 1255 
 1256         switch (veriexec_strict) {
 1257         case VERIEXEC_LEARNING:
 1258                 error = 0;
 1259                 break;
 1260 
 1261         case VERIEXEC_IDS:
 1262                 if (veriexec_table_lookup(mp) != NULL) {
 1263                         log(LOG_INFO, "Veriexec: IDS mode, allowing unmount "
 1264                             "of \"%s\".\n", mp->mnt_stat.f_mntonname);
 1265                 }
 1266 
 1267                 error = 0;
 1268                 break;
 1269 
 1270         case VERIEXEC_IPS: {
 1271                 struct veriexec_table_entry *vte;
 1272 
 1273                 vte = veriexec_table_lookup(mp);
 1274                 if ((vte != NULL) && (vte->vte_count > 0)) {
 1275                         log(LOG_ALERT, "Veriexec: IPS mode, preventing"
 1276                             " unmount of \"%s\" with monitored files.\n",
 1277                             mp->mnt_stat.f_mntonname);
 1278 
 1279                         error = EPERM;
 1280                 } else
 1281                         error = 0;
 1282                 break;
 1283                 }
 1284 
 1285         case VERIEXEC_LOCKDOWN:
 1286         default:
 1287                 log(LOG_ALERT, "Veriexec: Lockdown mode, preventing unmount "
 1288                     "of \"%s\".\n", mp->mnt_stat.f_mntonname);
 1289                 error = EPERM;
 1290                 break;
 1291         }
 1292 
 1293         rw_exit(&veriexec_op_lock);
 1294         return (error);
 1295 }
 1296 
 1297 int
 1298 veriexec_openchk(struct lwp *l, struct vnode *vp, const char *path, int fmode)
 1299 {
 1300         struct veriexec_file_entry *vfe = NULL;
 1301         int error = 0;
 1302 
 1303         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
 1304                 return 0;
 1305 
 1306         if (vp == NULL) {
 1307                 /* If no creation requested, let this fail normally. */
 1308                 if (!(fmode & O_CREAT))
 1309                         goto out;
 1310 
 1311                 /* Lockdown mode: Prevent creation of new files. */
 1312                 if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
 1313                         log(LOG_ALERT, "Veriexec: Preventing new file "
 1314                             "creation in `%s'.\n", path);
 1315                         error = EPERM;
 1316                 }
 1317 
 1318                 goto out;
 1319         }
 1320 
 1321         rw_enter(&veriexec_op_lock, RW_READER);
 1322         error = veriexec_file_verify(l, vp, path, VERIEXEC_FILE,
 1323                                      VERIEXEC_FILE_LOCKED, &vfe);
 1324 
 1325         if (error) {
 1326                 rw_exit(&veriexec_op_lock);
 1327                 goto out;
 1328         }
 1329 
 1330         if ((vfe != NULL) && ((fmode & FWRITE) || (fmode & O_TRUNC))) {
 1331                 veriexec_file_report(vfe, "Write access request.", path, l,
 1332                     REPORT_ALWAYS | REPORT_ALARM);
 1333 
 1334                 /* IPS mode: Deny write access to monitored files. */
 1335                 if (veriexec_strict >= VERIEXEC_IPS)
 1336                         error = EPERM;
 1337                 else
 1338                         veriexec_file_purge(vfe, VERIEXEC_LOCKED);
 1339         }
 1340 
 1341         if (vfe != NULL)
 1342                 rw_exit(&vfe->lock);
 1343 
 1344         rw_exit(&veriexec_op_lock);
 1345  out:
 1346         return (error);
 1347 }
 1348 
 1349 static void
 1350 veriexec_file_dump(struct veriexec_file_entry *vfe, prop_array_t entries)
 1351 {
 1352         prop_dictionary_t entry;
 1353 
 1354         /* If we don't have a filename, this is meaningless. */
 1355         if (vfe->filename == NULL)
 1356                 return;
 1357 
 1358         entry = prop_dictionary_create();
 1359 
 1360         veriexec_file_convert(vfe, entry);
 1361 
 1362         prop_array_add(entries, entry);
 1363 }
 1364 
 1365 int
 1366 veriexec_dump(struct lwp *l, prop_array_t rarray)
 1367 {
 1368         mount_iterator_t *iter;
 1369         struct mount *mp;
 1370 
 1371         mountlist_iterator_init(&iter);
 1372         while ((mp = mountlist_iterator_next(iter)) != NULL) {
 1373                 fileassoc_table_run(mp, veriexec_hook,
 1374                     (fileassoc_cb_t)veriexec_file_dump, rarray);
 1375         }
 1376         mountlist_iterator_destroy(iter);
 1377 
 1378         return (0);
 1379 }
 1380 
 1381 int
 1382 veriexec_flush(struct lwp *l)
 1383 {
 1384         mount_iterator_t *iter;
 1385         struct mount *mp;
 1386         int error = 0;
 1387 
 1388         mountlist_iterator_init(&iter);
 1389         while ((mp = mountlist_iterator_next(iter)) != NULL) {
 1390                 int lerror;
 1391 
 1392                 lerror = veriexec_table_delete(l, mp);
 1393                 if (lerror && lerror != ENOENT)
 1394                         error = lerror;
 1395         }
 1396         mountlist_iterator_destroy(iter);
 1397 
 1398         return (error);
 1399 }

Cache object: 68b4cb3d1e96b3f1af16c1202557905e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.