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_verifiedexec.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_verifiedexec.c,v 1.111.4.1 2008/12/18 00:56:27 snj 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_verifiedexec.c,v 1.111.4.1 2008/12/18 00:56:27 snj 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/exec.h>
   42 #include <sys/once.h>
   43 #include <sys/proc.h>
   44 #include <sys/rwlock.h>
   45 #include <sys/syslog.h>
   46 #include <sys/sysctl.h>
   47 #include <sys/inttypes.h>
   48 #include <sys/verified_exec.h>
   49 #if defined(__FreeBSD__)
   50 # include <sys/systm.h>
   51 # include <sys/imgact.h>
   52 # include <crypto/sha1.h>
   53 # include <crypto/sha2/sha2.h>
   54 # include <crypto/ripemd160/rmd160.h>
   55 #else
   56 # include <sys/sha1.h>
   57 # include <sys/sha2.h>
   58 # include <sys/rmd160.h>
   59 #endif
   60 #include <sys/md5.h>
   61 #include <uvm/uvm_extern.h>
   62 #include <sys/fileassoc.h>
   63 #include <sys/kauth.h>
   64 #include <sys/conf.h>
   65 #include <miscfs/specfs/specdev.h>
   66 #include <prop/proplib.h>
   67 #include <sys/fcntl.h>
   68 
   69 /* Readable values for veriexec_file_report(). */
   70 #define REPORT_ALWAYS           0x01    /* Always print */
   71 #define REPORT_VERBOSE          0x02    /* Print when verbose >= 1 */
   72 #define REPORT_DEBUG            0x04    /* Print when verbose >= 2 (debug) */
   73 #define REPORT_PANIC            0x08    /* Call panic() */
   74 #define REPORT_ALARM            0x10    /* Alarm - also print pid/uid/.. */
   75 #define REPORT_LOGMASK          (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG)
   76 
   77 /* state of locking for veriexec_file_verify */
   78 #define VERIEXEC_UNLOCKED       0x00    /* Nothing locked, callee does it */
   79 #define VERIEXEC_LOCKED         0x01    /* Global op lock held */
   80 
   81 
   82 #define VERIEXEC_RW_UPGRADE(lock)       while((rw_tryupgrade(lock)) == 0){};
   83 
   84 struct veriexec_fpops {
   85         const char *type;
   86         size_t hash_len;
   87         size_t context_size;
   88         veriexec_fpop_init_t init;
   89         veriexec_fpop_update_t update;
   90         veriexec_fpop_final_t final;
   91         LIST_ENTRY(veriexec_fpops) entries;
   92 };
   93 
   94 /* Veriexec per-file entry data. */
   95 struct veriexec_file_entry {
   96         krwlock_t lock;                         /* r/w lock */
   97         u_char *filename;                       /* File name. */
   98         u_char type;                            /* Entry type. */
   99         u_char status;                          /* Evaluation status. */
  100         u_char page_fp_status;                  /* Per-page FP status. */
  101         u_char *fp;                             /* Fingerprint. */
  102         void *page_fp;                          /* Per-page fingerprints */
  103         size_t npages;                          /* Number of pages. */
  104         size_t last_page_size;                  /* To support < PAGE_SIZE */
  105         struct veriexec_fpops *ops;             /* Fingerprint ops vector*/
  106         size_t filename_len;                    /* Length of filename. */
  107 };
  108 
  109 /* Veriexec per-table data. */
  110 struct veriexec_table_entry {
  111         uint64_t vte_count;                     /* Number of Veriexec entries. */
  112         const struct sysctlnode *vte_node;
  113 };
  114 
  115 static int veriexec_verbose;
  116 int veriexec_strict;
  117 static int veriexec_bypass = 1;
  118 
  119 static char *veriexec_fp_names = NULL;
  120 static size_t veriexec_name_max = 0;
  121 
  122 static const struct sysctlnode *veriexec_count_node;
  123 
  124 static fileassoc_t veriexec_hook;
  125 static specificdata_key_t veriexec_mountspecific_key;
  126 
  127 static LIST_HEAD(, veriexec_fpops) veriexec_fpops_list =
  128         LIST_HEAD_INITIALIZER(veriexec_fpops_list);
  129 
  130 static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *,
  131     void *, void *, void *, void *);
  132 static struct veriexec_fpops *veriexec_fpops_lookup(const char *);
  133 static void veriexec_file_free(struct veriexec_file_entry *);
  134 
  135 static unsigned int veriexec_tablecount = 0;
  136 
  137 /*
  138  * Veriexec operations global lock - most ops hold this as a read
  139  * lock, it is upgraded to a write lock when destroying veriexec file
  140  * table entries.
  141  */
  142 static krwlock_t veriexec_op_lock;
  143 
  144 /*
  145  * Sysctl helper routine for Veriexec.
  146  */
  147 static int
  148 sysctl_kern_veriexec(SYSCTLFN_ARGS)
  149 {
  150         int newval, error;
  151         int *var = NULL, raise_only = 0;
  152         struct sysctlnode node;
  153 
  154         node = *rnode;
  155 
  156         if (strcmp(rnode->sysctl_name, "strict") == 0) {
  157                 raise_only = 1;
  158                 var = &veriexec_strict;
  159         } else if (strcmp(rnode->sysctl_name, "algorithms") == 0) {
  160                 node.sysctl_data = veriexec_fp_names;
  161                 node.sysctl_size = strlen(veriexec_fp_names) + 1;
  162                 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  163         } else {
  164                 return (EINVAL);
  165         }
  166 
  167         newval = *var;
  168 
  169         node.sysctl_data = &newval;
  170         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  171         if (error || newp == NULL) {
  172                 return (error);
  173         }
  174 
  175         if (raise_only && (newval < *var))
  176                 return (EPERM);
  177 
  178         *var = newval;
  179 
  180         return (error);
  181 }
  182 
  183 SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup")
  184 {
  185         const struct sysctlnode *rnode = NULL;
  186 
  187         sysctl_createv(clog, 0, NULL, &rnode,
  188                        CTLFLAG_PERMANENT,
  189                        CTLTYPE_NODE, "kern", NULL,
  190                        NULL, 0, NULL, 0,
  191                        CTL_KERN, CTL_EOL);
  192 
  193         sysctl_createv(clog, 0, &rnode, &rnode,
  194                        CTLFLAG_PERMANENT,
  195                        CTLTYPE_NODE, "veriexec",
  196                        SYSCTL_DESCR("Veriexec"),
  197                        NULL, 0, NULL, 0,
  198                        CTL_CREATE, CTL_EOL);
  199 
  200         sysctl_createv(clog, 0, &rnode, NULL,
  201                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  202                        CTLTYPE_INT, "verbose",
  203                        SYSCTL_DESCR("Veriexec verbose level"),
  204                        NULL, 0, &veriexec_verbose, 0,
  205                        CTL_CREATE, CTL_EOL);
  206         sysctl_createv(clog, 0, &rnode, NULL,
  207                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  208                        CTLTYPE_INT, "strict",
  209                        SYSCTL_DESCR("Veriexec strict level"),
  210                        sysctl_kern_veriexec, 0, NULL, 0,
  211                        CTL_CREATE, CTL_EOL);
  212         sysctl_createv(clog, 0, &rnode, NULL,
  213                        CTLFLAG_PERMANENT,
  214                        CTLTYPE_STRING, "algorithms",
  215                        SYSCTL_DESCR("Veriexec supported hashing "
  216                                     "algorithms"),
  217                        sysctl_kern_veriexec, 0, NULL, 0,
  218                        CTL_CREATE, CTL_EOL);
  219         sysctl_createv(clog, 0, &rnode, &veriexec_count_node,
  220                        CTLFLAG_PERMANENT,
  221                        CTLTYPE_NODE, "count",
  222                        SYSCTL_DESCR("Number of fingerprints on mount(s)"),
  223                        NULL, 0, NULL, 0,
  224                        CTL_CREATE, CTL_EOL);
  225 }
  226 
  227 /*
  228  * Add ops to the fignerprint ops vector list.
  229  */
  230 int
  231 veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size,
  232     veriexec_fpop_init_t init, veriexec_fpop_update_t update,
  233     veriexec_fpop_final_t final)
  234 {
  235         struct veriexec_fpops *ops;
  236 
  237         /* Sanity check all parameters. */
  238         if ((fp_type == NULL) || (hash_len == 0) || (ctx_size == 0) ||
  239             (init == NULL) || (update == NULL) || (final == NULL))
  240                 return (EFAULT);
  241 
  242         if (veriexec_fpops_lookup(fp_type) != NULL)
  243                 return (EEXIST);
  244 
  245         ops = kmem_alloc(sizeof(*ops), KM_SLEEP);
  246 
  247         ops->type = fp_type;
  248         ops->hash_len = hash_len;
  249         ops->context_size = ctx_size;
  250         ops->init = init;
  251         ops->update = update;
  252         ops->final = final;
  253 
  254         LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries);
  255 
  256         /*
  257          * If we don't have space for any names, allocate enough for six
  258          * which should be sufficient. (it's also enough for all algorithms
  259          * we can support at the moment)
  260          */
  261         if (veriexec_fp_names == NULL) {
  262                 veriexec_name_max = 64;
  263                 veriexec_fp_names = kmem_zalloc(veriexec_name_max, KM_SLEEP);
  264         }
  265 
  266         /*
  267          * If we're running out of space for storing supported algorithms,
  268          * extend the buffer with space for four names.
  269          */
  270         while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) <
  271             strlen(fp_type)) {
  272                 char *newp;
  273                 unsigned int new_max;
  274 
  275                 /* Add space for four algorithm names. */
  276                 new_max = veriexec_name_max + 64;
  277                 newp = kmem_zalloc(new_max, KM_SLEEP);
  278                 strlcpy(newp, veriexec_fp_names, new_max);
  279                 kmem_free(veriexec_fp_names, veriexec_name_max);
  280                 veriexec_fp_names = newp;
  281                 veriexec_name_max = new_max;
  282         }
  283 
  284         if (*veriexec_fp_names != '\0')
  285                 strlcat(veriexec_fp_names, " ", veriexec_name_max);
  286 
  287         strlcat(veriexec_fp_names, fp_type, veriexec_name_max);
  288 
  289         return (0);
  290 }
  291 
  292 static void
  293 veriexec_mountspecific_dtor(void *v)
  294 {
  295         struct veriexec_table_entry *vte = v;
  296 
  297         if (vte == NULL) {
  298                 return;
  299         }
  300         sysctl_free(__UNCONST(vte->vte_node));
  301         veriexec_tablecount--;
  302         kmem_free(vte, sizeof(*vte));
  303 }
  304 
  305 /*
  306  * Initialise Veriexec.
  307  */
  308 void
  309 veriexec_init(void)
  310 {
  311         int error;
  312 
  313         /* Register a fileassoc for Veriexec. */
  314         error = fileassoc_register("veriexec",
  315             (fileassoc_cleanup_cb_t)veriexec_file_free, &veriexec_hook);
  316         if (error)
  317                 panic("Veriexec: Can't register fileassoc: error=%d", error);
  318 
  319         /* Register listener to handle raw disk access. */
  320         if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) ==
  321             NULL)
  322                 panic("Veriexec: Can't listen on device scope");
  323 
  324         error = mount_specific_key_create(&veriexec_mountspecific_key,
  325             veriexec_mountspecific_dtor);
  326         if (error)
  327                 panic("Veriexec: Can't create mountspecific key");
  328 
  329         rw_init(&veriexec_op_lock);
  330 
  331 #define FPOPS_ADD(a, b, c, d, e, f)     \
  332         veriexec_fpops_add(a, b, c, (veriexec_fpop_init_t)d, \
  333          (veriexec_fpop_update_t)e, (veriexec_fpop_final_t)f)
  334 
  335 #ifdef VERIFIED_EXEC_FP_RMD160
  336         FPOPS_ADD("RMD160", RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX),
  337             RMD160Init, RMD160Update, RMD160Final);
  338 #endif /* VERIFIED_EXEC_FP_RMD160 */
  339 
  340 #ifdef VERIFIED_EXEC_FP_SHA256
  341         FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX),
  342             SHA256_Init, SHA256_Update, SHA256_Final);
  343 #endif /* VERIFIED_EXEC_FP_SHA256 */
  344 
  345 #ifdef VERIFIED_EXEC_FP_SHA384
  346         FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX),
  347             SHA384_Init, SHA384_Update, SHA384_Final);
  348 #endif /* VERIFIED_EXEC_FP_SHA384 */
  349 
  350 #ifdef VERIFIED_EXEC_FP_SHA512
  351         FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX),
  352             SHA512_Init, SHA512_Update, SHA512_Final);
  353 #endif /* VERIFIED_EXEC_FP_SHA512 */
  354 
  355 #ifdef VERIFIED_EXEC_FP_SHA1
  356         FPOPS_ADD("SHA1", SHA1_DIGEST_LENGTH, sizeof(SHA1_CTX),
  357             SHA1Init, SHA1Update, SHA1Final);
  358 #endif /* VERIFIED_EXEC_FP_SHA1 */
  359 
  360 #ifdef VERIFIED_EXEC_FP_MD5
  361         FPOPS_ADD("MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX),
  362             MD5Init, MD5Update, MD5Final);
  363 #endif /* VERIFIED_EXEC_FP_MD5 */
  364 
  365 #undef FPOPS_ADD
  366 }
  367 
  368 static struct veriexec_fpops *
  369 veriexec_fpops_lookup(const char *name)
  370 {
  371         struct veriexec_fpops *ops;
  372 
  373         if (name == NULL)
  374                 return (NULL);
  375 
  376         LIST_FOREACH(ops, &veriexec_fpops_list, entries) {
  377                 if (strcasecmp(name, ops->type) == 0)
  378                         return (ops);
  379         }
  380 
  381         return (NULL);
  382 }
  383 
  384 /*
  385  * Calculate fingerprint. Information on hash length and routines used is
  386  * extracted from veriexec_hash_list according to the hash type.
  387  *
  388  * NOTE: vfe is assumed to be locked for writing on entry.
  389  */
  390 static int
  391 veriexec_fp_calc(struct lwp *l, struct vnode *vp, int lock_state,
  392     struct veriexec_file_entry *vfe, u_char *fp)
  393 {
  394         struct vattr va;
  395         void *ctx, *page_ctx;
  396         u_char *buf, *page_fp;
  397         off_t offset, len;
  398         size_t resid, npages;
  399         int error, do_perpage, pagen;
  400 
  401         error = VOP_GETATTR(vp, &va, l->l_cred);
  402         if (error)
  403                 return (error);
  404 
  405 #ifdef notyet /* XXX - for now */
  406         if ((vfe->type & VERIEXEC_UNTRUSTED) &&
  407             (vfe->page_fp_status == PAGE_FP_NONE))
  408                 do_perpage = 1;
  409         else
  410 #endif  /* notyet */
  411                 do_perpage = 0;
  412 
  413         ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP);
  414         buf = kmem_alloc(PAGE_SIZE, KM_SLEEP);
  415 
  416         page_ctx = NULL;
  417         page_fp = NULL;
  418         npages = 0;
  419         if (do_perpage) {
  420                 npages = (va.va_size >> PAGE_SHIFT) + 1;
  421                 page_fp = kmem_alloc(vfe->ops->hash_len * npages, KM_SLEEP);
  422                 vfe->page_fp = page_fp;
  423                 page_ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP);
  424         }
  425 
  426         (vfe->ops->init)(ctx);
  427 
  428         len = 0;
  429         error = 0;
  430         pagen = 0;
  431         for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) {
  432                 len = ((va.va_size - offset) < PAGE_SIZE) ?
  433                     (va.va_size - offset) : PAGE_SIZE;
  434 
  435                 error = vn_rdwr(UIO_READ, vp, buf, len, offset,
  436                                 UIO_SYSSPACE,
  437                                 ((lock_state == VERIEXEC_LOCKED)?
  438                                  IO_NODELOCKED : 0),
  439                                 l->l_cred, &resid, NULL);
  440 
  441                 if (error) {
  442                         if (do_perpage) {
  443                                 kmem_free(vfe->page_fp,
  444                                     vfe->ops->hash_len * npages);
  445                                 vfe->page_fp = NULL;
  446                         }
  447 
  448                         goto bad;
  449                 }
  450 
  451                 (vfe->ops->update)(ctx, buf, (unsigned int) len);
  452 
  453                 if (do_perpage) {
  454                         (vfe->ops->init)(page_ctx);
  455                         (vfe->ops->update)(page_ctx, buf, (unsigned int)len);
  456                         (vfe->ops->final)(page_fp, page_ctx);
  457 
  458                         if (veriexec_verbose >= 2) {
  459                                 int i;
  460 
  461                                 printf("hash for page %d: ", pagen);
  462                                 for (i = 0; i < vfe->ops->hash_len; i++)
  463                                         printf("%02x", page_fp[i]);
  464                                 printf("\n");
  465                         }
  466 
  467                         page_fp += vfe->ops->hash_len;
  468                         pagen++;
  469                 }
  470 
  471                 if (len != PAGE_SIZE)
  472                         break;
  473         }
  474 
  475         (vfe->ops->final)(fp, ctx);
  476 
  477         if (do_perpage) {
  478                 vfe->last_page_size = len;
  479                 vfe->page_fp_status = PAGE_FP_READY;
  480                 vfe->npages = npages;
  481         }
  482 
  483 bad:
  484         if (do_perpage)
  485                 kmem_free(page_ctx, vfe->ops->context_size);
  486 
  487         kmem_free(ctx, vfe->ops->context_size);
  488         kmem_free(buf, PAGE_SIZE);
  489 
  490         return (error);
  491 }
  492 
  493 /* Compare two fingerprints of the same type. */
  494 static int
  495 veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2)
  496 {
  497         if (veriexec_verbose >= 2) {
  498                 int i;
  499 
  500                 printf("comparing hashes...\n");
  501                 printf("fp1: ");
  502                 for (i = 0; i < ops->hash_len; i++) {
  503                         printf("%02x", fp1[i]);
  504                 }
  505                 printf("\nfp2: ");
  506                 for (i = 0; i < ops->hash_len; i++) {
  507                         printf("%02x", fp2[i]);
  508                 }
  509                 printf("\n");
  510         }
  511 
  512         return (memcmp(fp1, fp2, ops->hash_len));
  513 }
  514 
  515 static struct veriexec_table_entry *
  516 veriexec_table_lookup(struct mount *mp)
  517 {
  518         /* XXX: From raidframe init */
  519         if (mp == NULL)
  520                 return NULL;
  521 
  522         return mount_getspecific(mp, veriexec_mountspecific_key);
  523 }
  524 
  525 static struct veriexec_file_entry *
  526 veriexec_get(struct vnode *vp)
  527 {
  528         return (fileassoc_lookup(vp, veriexec_hook));
  529 }
  530 
  531 bool
  532 veriexec_lookup(struct vnode *vp)
  533 {
  534         return (veriexec_get(vp) == NULL ? false : true);
  535 }
  536 
  537 /*
  538  * Routine for maintaining mostly consistent message formats in Veriexec.
  539  */
  540 static void
  541 veriexec_file_report(struct veriexec_file_entry *vfe, const u_char *msg,
  542     const u_char *filename, struct lwp *l, int f)
  543 {
  544         if (msg == NULL)
  545                 return;
  546 
  547         if (vfe != NULL && vfe->filename != NULL)
  548                 filename = vfe->filename;
  549 
  550         if (filename == NULL)
  551                 return;
  552 
  553         if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) {
  554                 if (!(f & REPORT_ALARM) || (l == NULL))
  555                         log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg,
  556                             filename);
  557                 else
  558                         log(LOG_ALERT, "Veriexec: %s [%s, prog=%s pid=%u, "
  559                             "uid=%u, gid=%u]\n", msg, filename,
  560                             l->l_proc->p_comm, l->l_proc->p_pid,
  561                             kauth_cred_getuid(l->l_cred),
  562                             kauth_cred_getgid(l->l_cred));
  563         }
  564 
  565         if (f & REPORT_PANIC)
  566                 panic("Veriexec: Unrecoverable error.");
  567 }
  568 
  569 /*
  570  * Verify the fingerprint of the given file. If we're called directly from
  571  * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from
  572  * exec_script(), 'flag' will be VERIEXEC_INDIRECT.  If we are called from
  573  * vn_open(), 'flag' will be VERIEXEC_FILE.
  574  *
  575  * NOTE: The veriexec file entry pointer (vfep) will be returned LOCKED
  576  *       on no error.
  577  */
  578 static int
  579 veriexec_file_verify(struct lwp *l, struct vnode *vp, const u_char *name,
  580     int flag, int lockstate, struct veriexec_file_entry **vfep)
  581 {
  582         struct veriexec_file_entry *vfe;
  583         int error;
  584 
  585 #define VFE_NEEDS_EVAL(vfe) ((vfe->status == FINGERPRINT_NOTEVAL) || \
  586                              (vfe->type & VERIEXEC_UNTRUSTED))
  587 
  588         if (vfep != NULL)
  589                 *vfep = NULL;
  590 
  591         if (vp->v_type != VREG)
  592                 return (0);
  593 
  594         if (lockstate == VERIEXEC_UNLOCKED)
  595                 rw_enter(&veriexec_op_lock, RW_READER);
  596 
  597         /* Lookup veriexec table entry, save pointer if requested. */
  598         vfe = veriexec_get(vp);
  599         if (vfep != NULL)
  600                 *vfep = vfe;
  601         if (vfe == NULL)
  602                 goto out;
  603 
  604         error = 0;
  605 
  606         /*
  607          * Grab the lock for the entry, if we need to do an evaluation
  608          * then the lock is a write lock, after we have the write
  609          * lock, check if we really need it - some other thread may
  610          * have already done the work for us.
  611          */
  612         if (VFE_NEEDS_EVAL(vfe)) {
  613                 rw_enter(&vfe->lock, RW_WRITER);
  614                 if (!VFE_NEEDS_EVAL(vfe))
  615                         rw_downgrade(&vfe->lock);
  616         } else
  617                 rw_enter(&vfe->lock, RW_READER);
  618 
  619         /* Evaluate fingerprint if needed. */
  620         if (VFE_NEEDS_EVAL(vfe)) {
  621                 u_char *digest;
  622 
  623                 /* Calculate fingerprint for on-disk file. */
  624                 digest = kmem_zalloc(vfe->ops->hash_len, KM_SLEEP);
  625 
  626                 error = veriexec_fp_calc(l, vp, lockstate, vfe, digest);
  627                 if (error) {
  628                         veriexec_file_report(vfe, "Fingerprint calculation error.",
  629                             name, NULL, REPORT_ALWAYS);
  630                         kmem_free(digest, vfe->ops->hash_len);
  631                         rw_exit(&vfe->lock);
  632                         rw_exit(&veriexec_op_lock);
  633                         return (error);
  634                 }
  635 
  636                 /* Compare fingerprint with loaded data. */
  637                 if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0)
  638                         vfe->status = FINGERPRINT_VALID;
  639                 else
  640                         vfe->status = FINGERPRINT_NOMATCH;
  641 
  642                 kmem_free(digest, vfe->ops->hash_len);
  643                 rw_downgrade(&vfe->lock);
  644         }
  645 
  646         if (!(vfe->type & flag)) {
  647                 veriexec_file_report(vfe, "Incorrect access type.", name, l,
  648                     REPORT_ALWAYS|REPORT_ALARM);
  649 
  650                 /* IPS mode: Enforce access type. */
  651                 if (veriexec_strict >= VERIEXEC_IPS) {
  652                         rw_exit(&vfe->lock);
  653                         rw_exit(&veriexec_op_lock);
  654                         return (EPERM);
  655                 }
  656         }
  657 
  658  out:
  659         /* No entry in the veriexec tables. */
  660         if (vfe == NULL) {
  661                 veriexec_file_report(NULL, "No entry.", name,
  662                     l, REPORT_VERBOSE);
  663 
  664                 if (lockstate == VERIEXEC_UNLOCKED)
  665                         rw_exit(&veriexec_op_lock);
  666                 /*
  667                  * Lockdown mode: Deny access to non-monitored files.
  668                  * IPS mode: Deny execution of non-monitored files.
  669                  */
  670                 if ((veriexec_strict >= VERIEXEC_LOCKDOWN) ||
  671                     ((veriexec_strict >= VERIEXEC_IPS) &&
  672                      (flag != VERIEXEC_FILE)))
  673                         return (EPERM);
  674 
  675                 return (0);
  676         }
  677 
  678         switch (vfe->status) {
  679         case FINGERPRINT_NOTEVAL:
  680                 /* Should not happen. */
  681                 rw_exit(&vfe->lock);
  682                 rw_exit(&veriexec_op_lock);
  683                 veriexec_file_report(vfe, "Not-evaluated status "
  684                     "post evaluation; inconsistency detected.", name,
  685                     NULL, REPORT_ALWAYS|REPORT_PANIC);
  686 
  687                 /*NOTREACHED*/
  688 
  689         case FINGERPRINT_VALID:
  690                 /* Valid fingerprint. */
  691                 veriexec_file_report(vfe, "Match.", name, NULL,
  692                     REPORT_VERBOSE);
  693 
  694                 break;
  695 
  696         case FINGERPRINT_NOMATCH:
  697                 /* Fingerprint mismatch. */
  698                 veriexec_file_report(vfe, "Mismatch.", name,
  699                     NULL, REPORT_ALWAYS|REPORT_ALARM);
  700 
  701                 /* IDS mode: Deny access on fingerprint mismatch. */
  702                 if (veriexec_strict >= VERIEXEC_IDS) {
  703                         rw_exit(&vfe->lock);
  704                         error = EPERM;
  705                 }
  706 
  707                 break;
  708 
  709         default:
  710                 /* Should never happen. */
  711                 rw_exit(&vfe->lock);
  712                 rw_exit(&veriexec_op_lock);
  713                 veriexec_file_report(vfe, "Invalid status "
  714                     "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC);
  715         }
  716 
  717         if (lockstate == VERIEXEC_UNLOCKED)
  718                 rw_exit(&veriexec_op_lock);
  719         return (error);
  720 }
  721 
  722 int
  723 veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
  724     bool *found)
  725 {
  726         struct veriexec_file_entry *vfe;
  727         int r;
  728 
  729         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
  730                 return 0;
  731 
  732         r = veriexec_file_verify(l, vp, name, flag, VERIEXEC_UNLOCKED, &vfe);
  733 
  734         if ((r  == 0) && (vfe != NULL))
  735                 rw_exit(&vfe->lock);
  736 
  737         if (found != NULL)
  738                 *found = (vfe != NULL) ? true : false;
  739 
  740         return (r);
  741 }
  742 
  743 #ifdef notyet
  744 /*
  745  * Evaluate per-page fingerprints.
  746  */
  747 int
  748 veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg,
  749     size_t idx, struct lwp *l)
  750 {
  751         void *ctx;
  752         u_char *fp;
  753         u_char *page_fp;
  754         int error;
  755         vaddr_t kva;
  756 
  757         if (vfe->page_fp_status == PAGE_FP_NONE)
  758                 return (0);
  759 
  760         if (vfe->page_fp_status == PAGE_FP_FAIL)
  761                 return (EPERM);
  762 
  763         if (idx >= vfe->npages)
  764                 return (0);
  765 
  766         ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP);
  767         fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP);
  768         kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
  769         pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ);
  770         pmap_update(pmap_kernel());
  771 
  772         page_fp = (u_char *) vfe->page_fp + (vfe->ops->hash_len * idx);
  773         (vfe->ops->init)(ctx);
  774         (vfe->ops->update)(ctx, (void *) kva,
  775                            ((vfe->npages - 1) == idx) ? vfe->last_page_size
  776                                                       : PAGE_SIZE);
  777         (vfe->ops->final)(fp, ctx);
  778 
  779         pmap_kremove(kva, PAGE_SIZE);
  780         pmap_update(pmap_kernel());
  781         uvm_km_free(kernel_map, kva, PAGE_SIZE, UVM_KMF_VAONLY);
  782 
  783         error = veriexec_fp_cmp(vfe->ops, page_fp, fp);
  784         if (error) {
  785                 const char *msg;
  786 
  787                 if (veriexec_strict > VERIEXEC_LEARNING) {
  788                         msg = "Pages modified: Killing process.";
  789                 } else {
  790                         msg = "Pages modified.";
  791                         error = 0;
  792                 }
  793 
  794                 veriexec_file_report(msg, "[page_in]", l,
  795                     REPORT_ALWAYS|REPORT_ALARM);
  796 
  797                 if (error) {
  798                         ksiginfo_t ksi;
  799 
  800                         KSI_INIT(&ksi);
  801                         ksi.ksi_signo = SIGKILL;
  802                         ksi.ksi_code = SI_NOINFO;
  803                         ksi.ksi_pid = l->l_proc->p_pid;
  804                         ksi.ksi_uid = 0;
  805 
  806                         kpsignal(l->l_proc, &ksi, NULL);
  807                 }
  808         }
  809 
  810         kmem_free(ctx, vfe->ops->context_size);
  811         kmem_free(fp, vfe->ops->hash_len);
  812 
  813         return (error);
  814 }
  815 #endif /* notyet */
  816 
  817 /*
  818  * Veriexec remove policy code.
  819  */
  820 int
  821 veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf)
  822 {
  823         struct veriexec_file_entry *vfe;
  824         int error;
  825 
  826         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
  827                 return 0;
  828 
  829         rw_enter(&veriexec_op_lock, RW_READER);
  830 
  831         vfe = veriexec_get(vp);
  832         rw_exit(&veriexec_op_lock);
  833 
  834         if (vfe == NULL) {
  835                 /* Lockdown mode: Deny access to non-monitored files. */
  836                 if (veriexec_strict >= VERIEXEC_LOCKDOWN)
  837                         return (EPERM);
  838 
  839                 return (0);
  840         }
  841 
  842         veriexec_file_report(vfe, "Remove request.", pathbuf, l,
  843             REPORT_ALWAYS|REPORT_ALARM);
  844 
  845         /* IDS mode: Deny removal of monitored files. */
  846         if (veriexec_strict >= VERIEXEC_IDS)
  847                 error = EPERM;
  848         else
  849                 error = veriexec_file_delete(l, vp);
  850 
  851 
  852         return error;
  853 }
  854 
  855 /*
  856  * Veriexe rename policy.
  857  *
  858  * XXX: Once there's a way to hook after a successful rename, it would be
  859  * XXX: nice to update vfe->filename to the new name if it's not NULL and
  860  * XXX: the new name is absolute (ie., starts with a slash).
  861  */
  862 int
  863 veriexec_renamechk(struct lwp *l, struct vnode *fromvp, const char *fromname,
  864     struct vnode *tovp, const char *toname)
  865 {
  866         struct veriexec_file_entry *vfe, *tvfe;
  867 
  868         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
  869                 return 0;
  870 
  871         rw_enter(&veriexec_op_lock, RW_READER);
  872 
  873         if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
  874                 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to "
  875                     "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname,
  876                     kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
  877 
  878                 rw_exit(&veriexec_op_lock);
  879                 return (EPERM);
  880         }
  881 
  882         vfe = veriexec_get(fromvp);
  883         tvfe = NULL;
  884         if (tovp != NULL)
  885                 tvfe = veriexec_get(tovp);
  886 
  887         if ((vfe != NULL) || (tvfe != NULL)) {
  888                 if (veriexec_strict >= VERIEXEC_IPS) {
  889                         log(LOG_ALERT, "Veriexec: Preventing rename of `%s' "
  890                             "to `%s', uid=%u, pid=%u: IPS mode, %s "
  891                             "monitored.\n", fromname, toname,
  892                             kauth_cred_geteuid(l->l_cred),
  893                             l->l_proc->p_pid, (vfe != NULL && tvfe != NULL) ?
  894                             "files" : "file");
  895 
  896                         rw_exit(&veriexec_op_lock);
  897                         return (EPERM);
  898                 }
  899 
  900                 /*
  901                  * Monitored file is renamed; filename no longer relevant.
  902                  *
  903                  * XXX: We could keep the buffer, and when (and if) updating the
  904                  * XXX: filename post-rename, re-allocate it only if it's not
  905                  * XXX: big enough for the new filename.
  906                  */
  907                 if (vfe != NULL) {
  908                         /* XXXX get write lock on vfe here? */
  909 
  910                         VERIEXEC_RW_UPGRADE(&veriexec_op_lock);
  911                         /* once we have the op lock in write mode
  912                          * there should be no locks on any file
  913                          * entries so we can destroy the object.
  914                          */
  915 
  916                         kmem_free(vfe->filename, vfe->filename_len);
  917                         vfe->filename = NULL;
  918                         vfe->filename_len = 0;
  919                         rw_downgrade(&veriexec_op_lock);
  920                 }
  921 
  922                 log(LOG_NOTICE, "Veriexec: %s file `%s' renamed to "
  923                     "%s file `%s', uid=%u, pid=%u.\n", (vfe != NULL) ?
  924                     "Monitored" : "Non-monitored", fromname, (tvfe != NULL) ?
  925                     "monitored" : "non-monitored", toname,
  926                     kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
  927 
  928                 rw_exit(&veriexec_op_lock);
  929 
  930                 /*
  931                  * Monitored file is overwritten. Remove the entry.
  932                  */
  933                 if (tvfe != NULL)
  934                         (void)veriexec_file_delete(l, tovp);
  935 
  936         } else
  937                 rw_exit(&veriexec_op_lock);
  938 
  939         return (0);
  940 }
  941 
  942 static void
  943 veriexec_file_free(struct veriexec_file_entry *vfe)
  944 {
  945         if (vfe != NULL) {
  946                 if (vfe->fp != NULL)
  947                         kmem_free(vfe->fp, vfe->ops->hash_len);
  948                 if (vfe->page_fp != NULL)
  949                         kmem_free(vfe->page_fp, vfe->ops->hash_len);
  950                 if (vfe->filename != NULL)
  951                         kmem_free(vfe->filename, vfe->filename_len);
  952                 rw_destroy(&vfe->lock);
  953                 kmem_free(vfe, sizeof(*vfe));
  954         }
  955 }
  956 
  957 static void
  958 veriexec_file_purge(struct veriexec_file_entry *vfe, int have_lock)
  959 {
  960         if (vfe == NULL)
  961                 return;
  962 
  963         if (have_lock == VERIEXEC_UNLOCKED)
  964                 rw_enter(&vfe->lock, RW_WRITER);
  965         else
  966                 VERIEXEC_RW_UPGRADE(&vfe->lock);
  967 
  968         vfe->status = FINGERPRINT_NOTEVAL;
  969         if (have_lock == VERIEXEC_UNLOCKED)
  970                 rw_exit(&vfe->lock);
  971         else
  972                 rw_downgrade(&vfe->lock);
  973 }
  974 
  975 static void
  976 veriexec_file_purge_cb(struct veriexec_file_entry *vfe, void *cookie)
  977 {
  978         veriexec_file_purge(vfe, VERIEXEC_UNLOCKED);
  979 }
  980 
  981 /*
  982  * Invalidate a Veriexec file entry.
  983  * XXX: This should be updated when per-page fingerprints are added.
  984  */
  985 void
  986 veriexec_purge(struct vnode *vp)
  987 {
  988 
  989         rw_enter(&veriexec_op_lock, RW_READER);
  990         veriexec_file_purge(veriexec_get(vp), VERIEXEC_UNLOCKED);
  991         rw_exit(&veriexec_op_lock);
  992 }
  993 
  994 /*
  995  * Enforce raw disk access policy.
  996  *
  997  * IDS mode: Invalidate fingerprints on a mount if it's opened for writing.
  998  * IPS mode: Don't allow raw writing to disks we monitor.
  999  * Lockdown mode: Don't allow raw writing to all disks.
 1000  *
 1001  * XXX: This is bogus. There's an obvious race condition between the time
 1002  * XXX: the disk is open for writing, in which an attacker can access a
 1003  * XXX: monitored file to get its signature cached again, and when the raw
 1004  * XXX: file is overwritten on disk.
 1005  * XXX:
 1006  * XXX: To solve this, we need something like the following:
 1007  * XXX:         open raw disk:
 1008  * XXX:           - raise refcount,
 1009  * XXX:           - invalidate fingerprints,
 1010  * XXX:           - mark all entries for that disk with "no cache" flag
 1011  * XXX:
 1012  * XXX:         veriexec_verify:
 1013  * XXX:           - if "no cache", don't cache evaluation result
 1014  * XXX:
 1015  * XXX:         close raw disk:
 1016  * XXX:           - lower refcount,
 1017  * XXX:           - if refcount == 0, remove "no cache" flag from all entries
 1018  */
 1019 static int
 1020 veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
 1021     void *arg0, void *arg1, void *arg2, void *arg3)
 1022 {
 1023         int result;
 1024         enum kauth_device_req req;
 1025         struct veriexec_table_entry *vte;
 1026 
 1027         result = KAUTH_RESULT_DENY;
 1028         req = (enum kauth_device_req)arg0;
 1029 
 1030         switch (action) {
 1031         case KAUTH_DEVICE_RAWIO_SPEC: {
 1032                 struct vnode *vp, *bvp;
 1033                 dev_t dev;
 1034                 int d_type;
 1035 
 1036                 if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) {
 1037                         result = KAUTH_RESULT_DEFER;
 1038                         break;
 1039                 }
 1040 
 1041                 vp = arg1;
 1042                 KASSERT(vp != NULL);
 1043 
 1044                 dev = vp->v_rdev;
 1045                 d_type = D_OTHER;
 1046                 bvp = NULL;
 1047 
 1048                 /* Handle /dev/mem and /dev/kmem. */
 1049                 if ((vp->v_type == VCHR) && iskmemdev(dev)) {
 1050                         if (veriexec_strict < VERIEXEC_IPS)
 1051                                 result = KAUTH_RESULT_DEFER;
 1052 
 1053                         break;
 1054                 }
 1055 
 1056                 switch (vp->v_type) {
 1057                 case VCHR: {
 1058                         const struct cdevsw *cdev;
 1059 
 1060                         cdev = cdevsw_lookup(dev);
 1061                         if (cdev != NULL) {
 1062                                 dev_t blkdev;
 1063 
 1064                                 blkdev = devsw_chr2blk(dev);
 1065                                 if (blkdev != NODEV) {
 1066                                         vfinddev(blkdev, VBLK, &bvp);
 1067                                         if (bvp != NULL)
 1068                                                 d_type = cdev->d_flag &
 1069                                                     D_TYPEMASK;
 1070                                 }
 1071                         }
 1072 
 1073                         break;
 1074                         }
 1075                 case VBLK: {
 1076                         const struct bdevsw *bdev;
 1077 
 1078                         bdev = bdevsw_lookup(dev);
 1079                         if (bdev != NULL)
 1080                                 d_type = bdev->d_flag & D_TYPEMASK;
 1081 
 1082                         bvp = vp;
 1083 
 1084                         break;
 1085                         }
 1086                 default:
 1087                         result = KAUTH_RESULT_DEFER;
 1088                         break;
 1089                 }
 1090 
 1091                 if (d_type != D_DISK) {
 1092                         result = KAUTH_RESULT_DEFER;
 1093                         break;
 1094                 }
 1095 
 1096                 /*
 1097                  * XXX: See vfs_mountedon() comment in secmodel/bsd44.
 1098                  */
 1099                 vte = veriexec_table_lookup(bvp->v_mount);
 1100                 if (vte == NULL) {
 1101                         result = KAUTH_RESULT_DEFER;
 1102                         break;
 1103                 }
 1104 
 1105                 switch (veriexec_strict) {
 1106                 case VERIEXEC_LEARNING:
 1107                 case VERIEXEC_IDS:
 1108                         result = KAUTH_RESULT_DEFER;
 1109 
 1110                         rw_enter(&veriexec_op_lock, RW_WRITER);
 1111                         fileassoc_table_run(bvp->v_mount, veriexec_hook,
 1112                             (fileassoc_cb_t)veriexec_file_purge_cb, NULL);
 1113                         rw_exit(&veriexec_op_lock);
 1114 
 1115                         break;
 1116                 case VERIEXEC_IPS:
 1117                         result = KAUTH_RESULT_DENY;
 1118                         break;
 1119                 case VERIEXEC_LOCKDOWN:
 1120                         result = KAUTH_RESULT_DENY;
 1121                         break;
 1122                 }
 1123 
 1124                 break;
 1125                 }
 1126 
 1127         case KAUTH_DEVICE_RAWIO_PASSTHRU:
 1128                 /* XXX What can we do here? */
 1129                 if (veriexec_strict < VERIEXEC_IPS)
 1130                         result = KAUTH_RESULT_DEFER;
 1131 
 1132                 break;
 1133 
 1134         default:
 1135                 result = KAUTH_RESULT_DEFER;
 1136                 break;
 1137         }
 1138 
 1139         return (result);
 1140 }
 1141 
 1142 /*
 1143  * Create a new Veriexec table.
 1144  */
 1145 static struct veriexec_table_entry *
 1146 veriexec_table_add(struct lwp *l, struct mount *mp)
 1147 {
 1148         struct veriexec_table_entry *vte;
 1149         u_char buf[16];
 1150 
 1151         vte = kmem_zalloc(sizeof(*vte), KM_SLEEP);
 1152         mount_setspecific(mp, veriexec_mountspecific_key, vte);
 1153 
 1154         snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++);
 1155         sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node,
 1156                        0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL,
 1157                        0, CTL_CREATE, CTL_EOL);
 1158 
 1159         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1160                        CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt",
 1161                        NULL, NULL, 0, mp->mnt_stat.f_mntonname,
 1162                        0, CTL_CREATE, CTL_EOL);
 1163         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1164                        CTLFLAG_READONLY, CTLTYPE_STRING, "fstype",
 1165                        NULL, NULL, 0, mp->mnt_stat.f_fstypename,
 1166                        0, CTL_CREATE, CTL_EOL);
 1167         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1168                        CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries",
 1169                        NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL);
 1170 
 1171         return (vte);
 1172 }
 1173 
 1174 /*
 1175  * Add a file to be monitored by Veriexec.
 1176  *
 1177  * Expected elements in dict: file, fp, fp-type, entry-type.
 1178  */
 1179 int
 1180 veriexec_file_add(struct lwp *l, prop_dictionary_t dict)
 1181 {
 1182         struct veriexec_table_entry *vte;
 1183         struct veriexec_file_entry *vfe = NULL, *hh;
 1184         struct nameidata nid;
 1185         const char *file, *fp_type;
 1186         int error;
 1187 
 1188         if (!prop_dictionary_get_cstring_nocopy(dict, "file", &file))
 1189                 return (EINVAL);
 1190 
 1191         NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, file);
 1192         error = namei(&nid);
 1193         if (error)
 1194                 return (error);
 1195 
 1196         /* Add only regular files. */
 1197         if (nid.ni_vp->v_type != VREG) {
 1198                 log(LOG_ERR, "Veriexec: Not adding `%s': Not a regular file.\n",
 1199                     file);
 1200 
 1201                 error = EBADF;
 1202 
 1203                 goto out;
 1204         }
 1205 
 1206         vfe = kmem_zalloc(sizeof(*vfe), KM_SLEEP);
 1207 
 1208         /* Lookup fingerprint hashing algorithm. */
 1209         fp_type = prop_string_cstring_nocopy(prop_dictionary_get(dict,
 1210             "fp-type"));
 1211         if ((vfe->ops = veriexec_fpops_lookup(fp_type)) == NULL) {
 1212                 log(LOG_ERR, "Veriexec: Invalid or unknown fingerprint type "
 1213                     "`%s' for file `%s'.\n", fp_type, file);
 1214 
 1215                 error = EOPNOTSUPP;
 1216 
 1217                 goto out;
 1218         }
 1219 
 1220         if (prop_data_size(prop_dictionary_get(dict, "fp")) !=
 1221             vfe->ops->hash_len) {
 1222                 log(LOG_ERR, "Veriexec: Bad fingerprint length for `%s'.\n",
 1223                     file);
 1224 
 1225                 error = EINVAL;
 1226 
 1227                 goto out;
 1228         }
 1229 
 1230         vfe->fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP);
 1231         memcpy(vfe->fp, prop_data_data_nocopy(prop_dictionary_get(dict, "fp")),
 1232             vfe->ops->hash_len);
 1233 
 1234         rw_enter(&veriexec_op_lock, RW_WRITER);
 1235 
 1236         /*
 1237          * See if we already have an entry for this file. If we do, then
 1238          * let the user know and silently pretend to succeed.
 1239          */
 1240         hh = veriexec_get(nid.ni_vp);
 1241         if (hh != NULL) {
 1242                 bool fp_mismatch;
 1243 
 1244                 if (strcmp(vfe->ops->type, fp_type) ||
 1245                     memcmp(hh->fp, vfe->fp, hh->ops->hash_len))
 1246                         fp_mismatch = true;
 1247                 else
 1248                         fp_mismatch = false;
 1249 
 1250                 if ((veriexec_verbose >= 1) || fp_mismatch)
 1251                         log(LOG_NOTICE, "Veriexec: Duplicate entry for `%s' "
 1252                             "ignored. (%s fingerprint)\n", file,
 1253                             fp_mismatch ? "different" : "same");
 1254 
 1255                 veriexec_file_free(vfe);
 1256 
 1257                 /* XXX Should this be EEXIST if fp_mismatch is true? */
 1258                 error = 0;
 1259 
 1260                 goto unlock_out;
 1261         }
 1262 
 1263         /* Continue entry initialization. */
 1264         if (prop_dictionary_get_uint8(dict, "entry-type", &vfe->type) == FALSE)
 1265                 vfe->type = 0;
 1266         else {
 1267                 uint8_t extra_flags;
 1268 
 1269                 extra_flags = vfe->type & ~(VERIEXEC_DIRECT |
 1270                     VERIEXEC_INDIRECT | VERIEXEC_FILE | VERIEXEC_UNTRUSTED);
 1271                 if (extra_flags) {
 1272                         log(LOG_NOTICE, "Veriexec: Contaminated flags `0x%x' "
 1273                             "for `%s', skipping.\n", extra_flags, file);
 1274 
 1275                         error = EINVAL;
 1276 
 1277                         goto unlock_out;
 1278                 }
 1279         }
 1280         if (!(vfe->type & (VERIEXEC_DIRECT | VERIEXEC_INDIRECT |
 1281             VERIEXEC_FILE)))
 1282                 vfe->type |= VERIEXEC_DIRECT;
 1283 
 1284         vfe->status = FINGERPRINT_NOTEVAL;
 1285         if (prop_bool_true(prop_dictionary_get(dict, "keep-filename"))) {
 1286                 vfe->filename_len = strlen(file) + 1;
 1287                 vfe->filename = kmem_alloc(vfe->filename_len, KM_SLEEP);
 1288                 strlcpy(vfe->filename, file, vfe->filename_len);
 1289         } else
 1290                 vfe->filename = NULL;
 1291 
 1292         vfe->page_fp = NULL;
 1293         vfe->page_fp_status = PAGE_FP_NONE;
 1294         vfe->npages = 0;
 1295         vfe->last_page_size = 0;
 1296         rw_init(&vfe->lock);
 1297 
 1298         vte = veriexec_table_lookup(nid.ni_vp->v_mount);
 1299         if (vte == NULL)
 1300                 vte = veriexec_table_add(l, nid.ni_vp->v_mount);
 1301 
 1302         /* XXX if we bail below this, we might want to gc newly created vtes. */
 1303 
 1304         error = fileassoc_add(nid.ni_vp, veriexec_hook, vfe);
 1305         if (error)
 1306                 goto unlock_out;
 1307 
 1308         vte->vte_count++;
 1309 
 1310         if (prop_bool_true(prop_dictionary_get(dict, "eval-on-load")) ||
 1311             (vfe->type & VERIEXEC_UNTRUSTED)) {
 1312                 u_char *digest;
 1313 
 1314                 digest = kmem_zalloc(vfe->ops->hash_len, KM_SLEEP);
 1315 
 1316                 error = veriexec_fp_calc(l, nid.ni_vp, VERIEXEC_UNLOCKED,
 1317                                          vfe, digest);
 1318                 if (error) {
 1319                         kmem_free(digest, vfe->ops->hash_len);
 1320                         goto unlock_out;
 1321                 }
 1322 
 1323                 if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0)
 1324                         vfe->status = FINGERPRINT_VALID;
 1325                 else
 1326                         vfe->status = FINGERPRINT_NOMATCH;
 1327 
 1328                 kmem_free(digest, vfe->ops->hash_len);
 1329         }
 1330 
 1331         veriexec_file_report(NULL, "New entry.", file, NULL, REPORT_DEBUG);
 1332         veriexec_bypass = 0;
 1333 
 1334   unlock_out:
 1335         rw_exit(&veriexec_op_lock);
 1336 
 1337   out:
 1338         vrele(nid.ni_vp);
 1339         if (error)
 1340                 veriexec_file_free(vfe);
 1341 
 1342         return (error);
 1343 }
 1344 
 1345 int
 1346 veriexec_table_delete(struct lwp *l, struct mount *mp) {
 1347         struct veriexec_table_entry *vte;
 1348 
 1349         vte = veriexec_table_lookup(mp);
 1350         if (vte == NULL)
 1351                 return (ENOENT);
 1352 
 1353         veriexec_mountspecific_dtor(vte);
 1354         mount_setspecific(mp, veriexec_mountspecific_key, NULL);
 1355 
 1356         return (fileassoc_table_clear(mp, veriexec_hook));
 1357 }
 1358 
 1359 int
 1360 veriexec_file_delete(struct lwp *l, struct vnode *vp) {
 1361         struct veriexec_table_entry *vte;
 1362         int error;
 1363 
 1364         vte = veriexec_table_lookup(vp->v_mount);
 1365         if (vte == NULL)
 1366                 return (ENOENT);
 1367 
 1368         rw_enter(&veriexec_op_lock, RW_WRITER);
 1369         error = fileassoc_clear(vp, veriexec_hook);
 1370         rw_exit(&veriexec_op_lock);
 1371         if (!error)
 1372                 vte->vte_count--;
 1373 
 1374         return (error);
 1375 }
 1376 
 1377 /*
 1378  * Convert Veriexec entry data to a dictionary readable by userland tools.
 1379  */
 1380 static void
 1381 veriexec_file_convert(struct veriexec_file_entry *vfe, prop_dictionary_t rdict)
 1382 {
 1383         if (vfe->filename)
 1384                 prop_dictionary_set(rdict, "file",
 1385                     prop_string_create_cstring(vfe->filename));
 1386         prop_dictionary_set_uint8(rdict, "entry-type", vfe->type);
 1387         prop_dictionary_set_uint8(rdict, "status", vfe->status);
 1388         prop_dictionary_set(rdict, "fp-type",
 1389             prop_string_create_cstring(vfe->ops->type));
 1390         prop_dictionary_set(rdict, "fp",
 1391             prop_data_create_data(vfe->fp, vfe->ops->hash_len));
 1392 }
 1393 
 1394 int
 1395 veriexec_convert(struct vnode *vp, prop_dictionary_t rdict)
 1396 {
 1397         struct veriexec_file_entry *vfe;
 1398 
 1399         rw_enter(&veriexec_op_lock, RW_READER);
 1400 
 1401         vfe = veriexec_get(vp);
 1402         if (vfe == NULL) {
 1403                 rw_exit(&veriexec_op_lock);
 1404                 return (ENOENT);
 1405         }
 1406 
 1407         rw_enter(&vfe->lock, RW_READER);
 1408         veriexec_file_convert(vfe, rdict);
 1409 
 1410         rw_exit(&vfe->lock);
 1411         rw_exit(&veriexec_op_lock);
 1412         return (0);
 1413 }
 1414 
 1415 int
 1416 veriexec_unmountchk(struct mount *mp)
 1417 {
 1418         int error;
 1419 
 1420         if ((veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
 1421             || doing_shutdown)
 1422                 return (0);
 1423 
 1424         rw_enter(&veriexec_op_lock, RW_READER);
 1425 
 1426         switch (veriexec_strict) {
 1427         case VERIEXEC_LEARNING:
 1428                 error = 0;
 1429                 break;
 1430 
 1431         case VERIEXEC_IDS:
 1432                 if (veriexec_table_lookup(mp) != NULL) {
 1433                         log(LOG_INFO, "Veriexec: IDS mode, allowing unmount "
 1434                             "of \"%s\".\n", mp->mnt_stat.f_mntonname);
 1435                 }
 1436 
 1437                 error = 0;
 1438                 break;
 1439 
 1440         case VERIEXEC_IPS: {
 1441                 struct veriexec_table_entry *vte;
 1442 
 1443                 vte = veriexec_table_lookup(mp);
 1444                 if ((vte != NULL) && (vte->vte_count > 0)) {
 1445                         log(LOG_ALERT, "Veriexec: IPS mode, preventing"
 1446                             " unmount of \"%s\" with monitored files.\n",
 1447                             mp->mnt_stat.f_mntonname);
 1448 
 1449                         error = EPERM;
 1450                 } else
 1451                         error = 0;
 1452                 break;
 1453                 }
 1454 
 1455         case VERIEXEC_LOCKDOWN:
 1456         default:
 1457                 log(LOG_ALERT, "Veriexec: Lockdown mode, preventing unmount "
 1458                     "of \"%s\".\n", mp->mnt_stat.f_mntonname);
 1459                 error = EPERM;
 1460                 break;
 1461         }
 1462 
 1463         rw_exit(&veriexec_op_lock);
 1464         return (error);
 1465 }
 1466 
 1467 int
 1468 veriexec_openchk(struct lwp *l, struct vnode *vp, const char *path, int fmode)
 1469 {
 1470         struct veriexec_file_entry *vfe = NULL;
 1471         int error = 0;
 1472 
 1473         if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING))
 1474                 return 0;
 1475 
 1476         if (vp == NULL) {
 1477                 /* If no creation requested, let this fail normally. */
 1478                 if (!(fmode & O_CREAT))
 1479                         goto out;
 1480 
 1481                 /* Lockdown mode: Prevent creation of new files. */
 1482                 if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
 1483                         log(LOG_ALERT, "Veriexec: Preventing new file "
 1484                             "creation in `%s'.\n", path);
 1485                         error = EPERM;
 1486                 }
 1487 
 1488                 goto out;
 1489         }
 1490 
 1491         rw_enter(&veriexec_op_lock, RW_READER);
 1492         error = veriexec_file_verify(l, vp, path, VERIEXEC_FILE,
 1493                                      VERIEXEC_LOCKED, &vfe);
 1494 
 1495         if (error) {
 1496                 rw_exit(&veriexec_op_lock);
 1497                 goto out;
 1498         }
 1499 
 1500         if ((vfe != NULL) && ((fmode & FWRITE) || (fmode & O_TRUNC))) {
 1501                 veriexec_file_report(vfe, "Write access request.", path, l,
 1502                     REPORT_ALWAYS | REPORT_ALARM);
 1503 
 1504                 /* IPS mode: Deny write access to monitored files. */
 1505                 if (veriexec_strict >= VERIEXEC_IPS)
 1506                         error = EPERM;
 1507                 else
 1508                         veriexec_file_purge(vfe, VERIEXEC_LOCKED);
 1509         }
 1510 
 1511         if (vfe != NULL)
 1512                 rw_exit(&vfe->lock);
 1513 
 1514         rw_exit(&veriexec_op_lock);
 1515  out:
 1516         return (error);
 1517 }
 1518 
 1519 static void
 1520 veriexec_file_dump(struct veriexec_file_entry *vfe, prop_array_t entries)
 1521 {
 1522         prop_dictionary_t entry;
 1523 
 1524         /* If we don't have a filename, this is meaningless. */
 1525         if (vfe->filename == NULL)
 1526                 return;
 1527 
 1528         entry = prop_dictionary_create();
 1529 
 1530         veriexec_file_convert(vfe, entry);
 1531 
 1532         prop_array_add(entries, entry);
 1533 }
 1534 
 1535 int
 1536 veriexec_dump(struct lwp *l, prop_array_t rarray)
 1537 {
 1538         struct mount *mp;
 1539 
 1540         CIRCLEQ_FOREACH(mp, &mountlist, mnt_list) {
 1541                 fileassoc_table_run(mp, veriexec_hook,
 1542                     (fileassoc_cb_t)veriexec_file_dump, rarray);
 1543         }
 1544 
 1545         return (0);
 1546 }
 1547 
 1548 int
 1549 veriexec_flush(struct lwp *l)
 1550 {
 1551         struct mount *mp;
 1552         int error = 0;
 1553 
 1554         CIRCLEQ_FOREACH(mp, &mountlist, mnt_list) {
 1555                 int lerror;
 1556 
 1557                 lerror = veriexec_table_delete(l, mp);
 1558                 if (lerror && lerror != ENOENT)
 1559                         error = lerror;
 1560         }
 1561 
 1562         return (error);
 1563 }

Cache object: f80f0e81aedcfc50ab87c812549aac55


[ 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.