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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: e819aa5a667f4dba186b3cc497e7b8cc


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