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.78.2.9 2007/03/10 12:18:34 bouyer Exp $        */
    2 
    3 /*-
    4  * Copyright 2005 Elad Efrat <elad@NetBSD.org>
    5  * Copyright 2005 Brett Lymn <blymn@netbsd.org>
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Brett Lymn and Elad Efrat
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Neither the name of The NetBSD Foundation nor the names of its
   16  *    contributors may be used to endorse or promote products derived
   17  *    from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.78.2.9 2007/03/10 12:18:34 bouyer Exp $");
   34 
   35 #include "opt_veriexec.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/mount.h>
   39 #include <sys/malloc.h>
   40 #include <sys/vnode.h>
   41 #include <sys/namei.h>
   42 #include <sys/exec.h>
   43 #include <sys/proc.h>
   44 #include <sys/syslog.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/inttypes.h>
   47 #include <sys/verified_exec.h>
   48 #if defined(__FreeBSD__)
   49 # include <sys/systm.h>
   50 # include <sys/imgact.h>
   51 # include <crypto/sha1.h>
   52 # include <crypto/sha2/sha2.h>
   53 # include <crypto/ripemd160/rmd160.h>
   54 #else
   55 # include <sys/sha1.h>
   56 # include <sys/sha2.h>
   57 # include <sys/rmd160.h>
   58 #endif
   59 #include <sys/md5.h>
   60 #include <uvm/uvm_extern.h>
   61 #include <sys/fileassoc.h>
   62 #include <sys/kauth.h>
   63 #include <sys/conf.h>
   64 #include <miscfs/specfs/specdev.h>
   65 #include <prop/proplib.h>
   66 #include <sys/fcntl.h>
   67 
   68 MALLOC_DEFINE(M_VERIEXEC, "Veriexec", "Veriexec data-structures");
   69 
   70 struct veriexec_fpops {
   71         const char *type;
   72         size_t hash_len;
   73         size_t context_size;
   74         veriexec_fpop_init_t init;
   75         veriexec_fpop_update_t update;
   76         veriexec_fpop_final_t final;
   77         LIST_ENTRY(veriexec_fpops) entries;
   78 };
   79 
   80 /* Veriexec per-file entry data. */
   81 struct veriexec_file_entry {
   82         u_char type;                            /* Entry type. */
   83         u_char status;                          /* Evaluation status. */
   84         u_char page_fp_status;                  /* Per-page FP status. */
   85         u_char *fp;                             /* Fingerprint. */
   86         void *page_fp;                          /* Per-page fingerprints */
   87         size_t npages;                          /* Number of pages. */
   88         size_t last_page_size;                  /* To support < PAGE_SIZE */
   89         struct veriexec_fpops *ops;             /* Fingerprint ops vector*/
   90 };
   91 
   92 /* Veriexec per-table data. */
   93 struct veriexec_table_entry {
   94         uint64_t vte_count;                     /* Number of Veriexec entries. */
   95         const struct sysctlnode *vte_node;
   96 };
   97 
   98 int veriexec_verbose;
   99 int veriexec_strict;
  100 
  101 char *veriexec_fp_names;
  102 size_t veriexec_name_max;
  103 
  104 const struct sysctlnode *veriexec_count_node;
  105 
  106 int veriexec_hook;
  107 
  108 LIST_HEAD(, veriexec_fpops) veriexec_fpops_list;
  109 
  110 static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *,
  111     void *, void *, void *, void *);
  112 static int sysctl_kern_veriexec(SYSCTLFN_PROTO);
  113 static struct veriexec_fpops *veriexec_fpops_lookup(const char *);
  114 static void veriexec_clear(void *, int);
  115 
  116 static unsigned int veriexec_tablecount = 0;
  117 
  118 /*
  119  * Sysctl helper routine for Veriexec.
  120  */
  121 static int
  122 sysctl_kern_veriexec(SYSCTLFN_ARGS)
  123 {
  124         int newval, error;
  125         int *var = NULL, raise_only = 0;
  126         struct sysctlnode node;
  127 
  128         node = *rnode;
  129 
  130         if (strcmp(rnode->sysctl_name, "strict") == 0) {
  131                 raise_only = 1;
  132                 var = &veriexec_strict;
  133         } else if (strcmp(rnode->sysctl_name, "algorithms") == 0) {
  134                 node.sysctl_data = veriexec_fp_names;
  135                 node.sysctl_size = strlen(veriexec_fp_names) + 1;
  136                 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  137         } else {
  138                 return (EINVAL);
  139         }
  140 
  141         newval = *var;
  142 
  143         node.sysctl_data = &newval;
  144         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  145         if (error || newp == NULL) {
  146                 return (error);
  147         }
  148 
  149         if (raise_only && (newval < *var))
  150                 return (EPERM);
  151 
  152         *var = newval;
  153 
  154         return (error);
  155 }
  156 
  157 SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup")
  158 {
  159         const struct sysctlnode *rnode = NULL;
  160 
  161         sysctl_createv(clog, 0, NULL, &rnode,
  162                        CTLFLAG_PERMANENT,
  163                        CTLTYPE_NODE, "kern", NULL,
  164                        NULL, 0, NULL, 0,
  165                        CTL_KERN, CTL_EOL);
  166 
  167         sysctl_createv(clog, 0, &rnode, &rnode,
  168                        CTLFLAG_PERMANENT,
  169                        CTLTYPE_NODE, "veriexec",
  170                        SYSCTL_DESCR("Veriexec"),
  171                        NULL, 0, NULL, 0,
  172                        CTL_CREATE, CTL_EOL);
  173 
  174         sysctl_createv(clog, 0, &rnode, NULL,
  175                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  176                        CTLTYPE_INT, "verbose",
  177                        SYSCTL_DESCR("Veriexec verbose level"),
  178                        NULL, 0, &veriexec_verbose, 0,
  179                        CTL_CREATE, CTL_EOL);
  180         sysctl_createv(clog, 0, &rnode, NULL,
  181                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  182                        CTLTYPE_INT, "strict",
  183                        SYSCTL_DESCR("Veriexec strict level"),
  184                        sysctl_kern_veriexec, 0, NULL, 0,
  185                        CTL_CREATE, CTL_EOL);
  186         sysctl_createv(clog, 0, &rnode, NULL,
  187                        CTLFLAG_PERMANENT,
  188                        CTLTYPE_STRING, "algorithms",
  189                        SYSCTL_DESCR("Veriexec supported hashing "
  190                                     "algorithms"),
  191                        sysctl_kern_veriexec, 0, NULL, 0,
  192                        CTL_CREATE, CTL_EOL);
  193         sysctl_createv(clog, 0, &rnode, &veriexec_count_node,
  194                        CTLFLAG_PERMANENT,
  195                        CTLTYPE_NODE, "count",
  196                        SYSCTL_DESCR("Number of fingerprints on mount(s)"),
  197                        NULL, 0, NULL, 0,
  198                        CTL_CREATE, CTL_EOL);
  199 }
  200 
  201 /*
  202  * Add ops to the fignerprint ops vector list.
  203  */
  204 int
  205 veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size,
  206     veriexec_fpop_init_t init, veriexec_fpop_update_t update,
  207     veriexec_fpop_final_t final)
  208 {
  209         struct veriexec_fpops *ops;
  210         char *newp;
  211         unsigned int new_max;
  212 
  213         /* Sanity check all parameters. */
  214         if ((fp_type == NULL) || (hash_len == 0) || (ctx_size == 0) ||
  215             (init == NULL) || (update == NULL) || (final == NULL))
  216                 return (EFAULT);
  217 
  218         if (veriexec_fpops_lookup(fp_type) != NULL)
  219                 return (EEXIST);
  220 
  221         ops = malloc(sizeof(*ops), M_VERIEXEC, M_WAITOK);
  222 
  223         ops->type = fp_type;
  224         ops->hash_len = hash_len;
  225         ops->context_size = ctx_size;
  226         ops->init = init;
  227         ops->update = update;
  228         ops->final = final;
  229 
  230         LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries);
  231 
  232         /*
  233          * If we don't have space for any names, allocate enough for six
  234          * which should be sufficient. (it's also enough for all algorithms
  235          * we can support at the moment)
  236          */
  237         if (veriexec_fp_names == NULL) {
  238                 veriexec_name_max = 64;
  239                 veriexec_fp_names = malloc(veriexec_name_max, M_VERIEXEC,
  240                     M_WAITOK|M_ZERO);
  241         }
  242 
  243         /*
  244          * If we're running out of space for storing supported algorithms,
  245          * extend the buffer with space for four names.
  246          */
  247         while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) <
  248             strlen(fp_type)) {
  249                 /* Add space for four algorithm names. */
  250                 new_max = veriexec_name_max + 64;
  251                 newp = realloc(veriexec_fp_names, new_max, M_VERIEXEC,
  252                     M_WAITOK|M_ZERO);
  253                 veriexec_fp_names = newp;
  254                 veriexec_name_max = new_max;
  255         }
  256 
  257         if (*veriexec_fp_names != '\0')
  258                 strlcat(veriexec_fp_names, " ", veriexec_name_max);
  259 
  260         strlcat(veriexec_fp_names, fp_type, veriexec_name_max);
  261 
  262         return (0);
  263 }
  264 
  265 /*
  266  * Initialise Veriexec.
  267  */
  268 void
  269 veriexec_init(void)
  270 {
  271         /* Register a fileassoc for Veriexec. */
  272         veriexec_hook = fileassoc_register("veriexec", veriexec_clear);
  273         if (veriexec_hook == FILEASSOC_INVAL)
  274                 panic("Veriexec: Can't register fileassoc");
  275 
  276         /* Register listener to handle raw disk access. */
  277         if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) ==
  278             NULL)
  279                 panic("Veriexec: Can't listen on device scope");
  280 
  281         LIST_INIT(&veriexec_fpops_list);
  282         veriexec_fp_names = NULL;
  283         veriexec_name_max = 0;
  284 
  285 #define FPOPS_ADD(a, b, c, d, e, f)     \
  286         veriexec_fpops_add(a, b, c, (veriexec_fpop_init_t)d, \
  287          (veriexec_fpop_update_t)e, (veriexec_fpop_final_t)f)
  288 
  289 #ifdef VERIFIED_EXEC_FP_RMD160
  290         FPOPS_ADD("RMD160", RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX),
  291             RMD160Init, RMD160Update, RMD160Final);
  292 #endif /* VERIFIED_EXEC_FP_RMD160 */
  293 
  294 #ifdef VERIFIED_EXEC_FP_SHA256
  295         FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX),
  296             SHA256_Init, SHA256_Update, SHA256_Final);
  297 #endif /* VERIFIED_EXEC_FP_SHA256 */
  298 
  299 #ifdef VERIFIED_EXEC_FP_SHA384
  300         FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX),
  301             SHA384_Init, SHA384_Update, SHA384_Final);
  302 #endif /* VERIFIED_EXEC_FP_SHA384 */
  303 
  304 #ifdef VERIFIED_EXEC_FP_SHA512
  305         FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX),
  306             SHA512_Init, SHA512_Update, SHA512_Final);
  307 #endif /* VERIFIED_EXEC_FP_SHA512 */
  308 
  309 #ifdef VERIFIED_EXEC_FP_SHA1
  310         FPOPS_ADD("SHA1", SHA1_DIGEST_LENGTH, sizeof(SHA1_CTX),
  311             SHA1Init, SHA1Update, SHA1Final);
  312 #endif /* VERIFIED_EXEC_FP_SHA1 */
  313 
  314 #ifdef VERIFIED_EXEC_FP_MD5
  315         FPOPS_ADD("MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX),
  316             MD5Init, MD5Update, MD5Final);
  317 #endif /* VERIFIED_EXEC_FP_MD5 */
  318 
  319 #undef FPOPS_ADD
  320 }
  321 
  322 static struct veriexec_fpops *
  323 veriexec_fpops_lookup(const char *name)
  324 {
  325         struct veriexec_fpops *ops;
  326 
  327         if (name == NULL)
  328                 return (NULL);
  329 
  330         LIST_FOREACH(ops, &veriexec_fpops_list, entries) {
  331                 if (strcasecmp(name, ops->type) == 0)
  332                         return (ops);
  333         }
  334 
  335         return (NULL);
  336 }
  337 
  338 /*
  339  * Calculate fingerprint. Information on hash length and routines used is
  340  * extracted from veriexec_hash_list according to the hash type.
  341  */
  342 static int
  343 veriexec_fp_calc(struct lwp *l, struct vnode *vp,
  344     struct veriexec_file_entry *vfe, u_char *fp)
  345 {
  346         struct vattr va;
  347         void *ctx, *page_ctx;
  348         u_char *buf, *page_fp;
  349         off_t offset, len;
  350         size_t resid, npages;
  351         int error, do_perpage, pagen;
  352 
  353         error = VOP_GETATTR(vp, &va, l->l_cred, l);
  354         if (error)
  355                 return (error);
  356 
  357 #if 0 /* XXX - for now */
  358         if ((vfe->type & VERIEXEC_UNTRUSTED) &&
  359             (vfe->page_fp_status == PAGE_FP_NONE))
  360                 do_perpage = 1;
  361         else
  362 #endif
  363                 do_perpage = 0;
  364 
  365         ctx = (void *) malloc(vfe->ops->context_size, M_VERIEXEC, M_WAITOK);
  366         buf = (u_char *) malloc(PAGE_SIZE, M_VERIEXEC, M_WAITOK);
  367 
  368         page_ctx = NULL;
  369         page_fp = NULL;
  370         npages = 0;
  371         if (do_perpage) {
  372                 npages = (va.va_size >> PAGE_SHIFT) + 1;
  373                 page_fp = (u_char *) malloc(vfe->ops->hash_len * npages,
  374                     M_VERIEXEC, M_WAITOK|M_ZERO);
  375                 vfe->page_fp = page_fp;
  376                 page_ctx = (void *) malloc(vfe->ops->context_size, M_VERIEXEC,
  377                     M_WAITOK);
  378         }
  379 
  380         (vfe->ops->init)(ctx);
  381 
  382         len = 0;
  383         error = 0;
  384         pagen = 0;
  385         for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) {
  386                 len = ((va.va_size - offset) < PAGE_SIZE) ?
  387                     (va.va_size - offset) : PAGE_SIZE;
  388 
  389                 error = vn_rdwr(UIO_READ, vp, buf, len, offset,
  390                                 UIO_SYSSPACE,
  391 #ifdef __FreeBSD__
  392                                 IO_NODELOCKED,
  393 #else
  394                                 0,
  395 #endif
  396                                 l->l_cred, &resid, NULL);
  397 
  398                 if (error) {
  399                         if (do_perpage) {
  400                                 free(vfe->page_fp, M_VERIEXEC);
  401                                 vfe->page_fp = NULL;
  402                         }
  403 
  404                         goto bad;
  405                 }
  406 
  407                 (vfe->ops->update)(ctx, buf, (unsigned int) len);
  408 
  409                 if (do_perpage) {
  410                         (vfe->ops->init)(page_ctx);
  411                         (vfe->ops->update)(page_ctx, buf, (unsigned int)len);
  412                         (vfe->ops->final)(page_fp, page_ctx);
  413 
  414                         if (veriexec_verbose >= 2) {
  415                                 int i;
  416 
  417                                 printf("hash for page %d: ", pagen);
  418                                 for (i = 0; i < vfe->ops->hash_len; i++)
  419                                         printf("%02x", page_fp[i]);
  420                                 printf("\n");
  421                         }
  422 
  423                         page_fp += vfe->ops->hash_len;
  424                         pagen++;
  425                 }
  426 
  427                 if (len != PAGE_SIZE)
  428                         break;
  429         }
  430 
  431         (vfe->ops->final)(fp, ctx);
  432 
  433         if (do_perpage) {
  434                 vfe->last_page_size = len;
  435                 vfe->page_fp_status = PAGE_FP_READY;
  436                 vfe->npages = npages;
  437         }
  438 
  439 bad:
  440         if (do_perpage)
  441                 free(page_ctx, M_VERIEXEC);
  442         free(ctx, M_VERIEXEC);
  443         free(buf, M_VERIEXEC);
  444 
  445         return (error);
  446 }
  447 
  448 /* Compare two fingerprints of the same type. */
  449 static int
  450 veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2)
  451 {
  452         if (veriexec_verbose >= 2) {
  453                 int i;
  454 
  455                 printf("comparing hashes...\n");
  456                 printf("fp1: ");
  457                 for (i = 0; i < ops->hash_len; i++) {
  458                         printf("%02x", fp1[i]);
  459                 }
  460                 printf("\nfp2: ");
  461                 for (i = 0; i < ops->hash_len; i++) {
  462                         printf("%02x", fp2[i]);
  463                 }
  464                 printf("\n");
  465         }
  466 
  467         return (memcmp(fp1, fp2, ops->hash_len));
  468 }
  469 
  470 static struct veriexec_table_entry *
  471 veriexec_table_lookup(struct mount *mp)
  472 {
  473         return (fileassoc_tabledata_lookup(mp, veriexec_hook));
  474 }
  475 
  476 static struct veriexec_file_entry *
  477 veriexec_get(struct vnode *vp)
  478 {
  479         return (fileassoc_lookup(vp, veriexec_hook));
  480 }
  481 
  482 boolean_t
  483 veriexec_lookup(struct vnode *vp)
  484 {
  485         return (veriexec_get(vp) == NULL ? FALSE : TRUE);
  486 }
  487 
  488 /*
  489  * Verify the fingerprint of the given file. If we're called directly from
  490  * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from
  491  * exec_script(), 'flag' will be VERIEXEC_INDIRECT.  If we are called from
  492  * vn_open(), 'flag' will be VERIEXEC_FILE.
  493  */
  494 int
  495 veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag,
  496     boolean_t *found)
  497 {
  498         struct veriexec_file_entry *vfe;
  499         u_char *digest;
  500         int error;
  501 
  502         if (vp->v_type != VREG)
  503                 return (0);
  504 
  505         /* Lookup veriexec table entry, save pointer if requested. */
  506         vfe = veriexec_get(vp);
  507         if (found != NULL) {
  508                 if (vfe != NULL)
  509                         *found = TRUE;
  510                 else
  511                         *found = FALSE;
  512         }
  513         if (vfe == NULL)
  514                 goto out;
  515 
  516         /* Evaluate fingerprint if needed. */
  517         error = 0;
  518         digest = NULL;
  519         if ((vfe->status == FINGERPRINT_NOTEVAL) ||
  520             (vfe->type & VERIEXEC_UNTRUSTED)) {
  521                 /* Calculate fingerprint for on-disk file. */
  522                 digest = (u_char *) malloc(vfe->ops->hash_len, M_VERIEXEC,
  523                     M_WAITOK);
  524                 error = veriexec_fp_calc(l, vp, vfe, digest);
  525                 if (error) {
  526                         veriexec_report("Fingerprint calculation error.",
  527                             name, NULL, REPORT_ALWAYS);
  528                         free(digest, M_VERIEXEC);
  529                         return (error);
  530                 }
  531 
  532                 /* Compare fingerprint with loaded data. */
  533                 if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0) {
  534                         vfe->status = FINGERPRINT_VALID;
  535                 } else {
  536                         vfe->status = FINGERPRINT_NOMATCH;
  537                 }
  538 
  539                 free(digest, M_VERIEXEC);
  540         }
  541 
  542         if (!(vfe->type & flag)) {
  543                 veriexec_report("Incorrect access type.", name, l,
  544                     REPORT_ALWAYS|REPORT_ALARM);
  545 
  546                 /* IPS mode: Enforce access type. */
  547                 if (veriexec_strict >= VERIEXEC_IPS)
  548                         return (EPERM);
  549         }
  550 
  551  out:
  552         /* No entry in the veriexec tables. */
  553         if (vfe == NULL) {
  554                 veriexec_report("No entry.", name,
  555                     l, REPORT_VERBOSE);
  556 
  557                 /*
  558                  * Lockdown mode: Deny access to non-monitored files.
  559                  * IPS mode: Deny execution of non-monitored files.
  560                  */
  561                 if ((veriexec_strict >= VERIEXEC_LOCKDOWN) ||
  562                     ((veriexec_strict >= VERIEXEC_IPS) &&
  563                      (flag != VERIEXEC_FILE)))
  564                         return (EPERM);
  565 
  566                 return (0);
  567         }
  568 
  569         switch (vfe->status) {
  570         case FINGERPRINT_NOTEVAL:
  571                 /* Should not happen. */
  572                 veriexec_report("Not-evaluated status "
  573                     "post evaluation; inconsistency detected.", name,
  574                     NULL, REPORT_ALWAYS|REPORT_PANIC);
  575 
  576         case FINGERPRINT_VALID:
  577                 /* Valid fingerprint. */
  578                 veriexec_report("Match.", name, NULL,
  579                     REPORT_VERBOSE);
  580 
  581                 break;
  582 
  583         case FINGERPRINT_NOMATCH:
  584                 /* Fingerprint mismatch. */
  585                 veriexec_report("Mismatch.", name,
  586                     NULL, REPORT_ALWAYS|REPORT_ALARM);
  587 
  588                 /* IDS mode: Deny access on fingerprint mismatch. */
  589                 if (veriexec_strict >= VERIEXEC_IDS)
  590                         error = EPERM;
  591 
  592                 break;
  593 
  594         default:
  595                 /* Should never happen. */
  596                 veriexec_report("Invalid status "
  597                     "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC);
  598         }
  599 
  600         return (error);
  601 }
  602 
  603 /*
  604  * Evaluate per-page fingerprints.
  605  */
  606 int
  607 veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg,
  608     size_t idx, struct lwp *l)
  609 {
  610         void *ctx;
  611         u_char *fp;
  612         u_char *page_fp;
  613         int error;
  614         vaddr_t kva;
  615 
  616         if (vfe->page_fp_status == PAGE_FP_NONE)
  617                 return (0);
  618 
  619         if (vfe->page_fp_status == PAGE_FP_FAIL)
  620                 return (EPERM);
  621 
  622         if (idx >= vfe->npages)
  623                 return (0);
  624 
  625         ctx = malloc(vfe->ops->context_size, M_VERIEXEC, M_WAITOK);
  626         fp = malloc(vfe->ops->hash_len, M_VERIEXEC, M_WAITOK);
  627         kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
  628         pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ);
  629 
  630         page_fp = (u_char *) vfe->page_fp + (vfe->ops->hash_len * idx);
  631         (vfe->ops->init)(ctx);
  632         (vfe->ops->update)(ctx, (void *) kva,
  633                            ((vfe->npages - 1) == idx) ? vfe->last_page_size
  634                                                       : PAGE_SIZE);
  635         (vfe->ops->final)(fp, ctx);
  636 
  637         pmap_kremove(kva, PAGE_SIZE);
  638         uvm_km_free(kernel_map, kva, PAGE_SIZE, UVM_KMF_VAONLY);
  639 
  640         error = veriexec_fp_cmp(vfe->ops, page_fp, fp);
  641         if (error) {
  642                 const char *msg;
  643 
  644                 if (veriexec_strict > VERIEXEC_LEARNING) {
  645                         msg = "Pages modified: Killing process.";
  646                 } else {
  647                         msg = "Pages modified.";
  648                         error = 0;
  649                 }
  650 
  651                 veriexec_report(msg, "[page_in]", l, REPORT_ALWAYS|REPORT_ALARM);
  652 
  653                 if (error) {
  654                         ksiginfo_t ksi;
  655 
  656                         KSI_INIT(&ksi);
  657                         ksi.ksi_signo = SIGKILL;
  658                         ksi.ksi_code = SI_NOINFO;
  659                         ksi.ksi_pid = l->l_proc->p_pid;
  660                         ksi.ksi_uid = 0;
  661 
  662                         kpsignal(l->l_proc, &ksi, NULL);
  663                 }
  664         }
  665 
  666         free(ctx, M_VERIEXEC);
  667         free(fp, M_VERIEXEC);
  668 
  669         return (error);
  670 }
  671 
  672 /*
  673  * Veriexec remove policy code.
  674  */
  675 int
  676 veriexec_removechk(struct vnode *vp, const char *pathbuf, struct lwp *l)
  677 {
  678         struct veriexec_file_entry *vfe;
  679         struct veriexec_table_entry *vte;
  680 
  681         vfe = veriexec_get(vp);
  682         if (vfe == NULL) {
  683                 /* Lockdown mode: Deny access to non-monitored files. */
  684                 if (veriexec_strict >= VERIEXEC_LOCKDOWN)
  685                         return (EPERM);
  686 
  687                 return (0);
  688         }
  689 
  690         veriexec_report("Remove request.", pathbuf, l, REPORT_ALWAYS|REPORT_ALARM);
  691 
  692         /* IDS mode: Deny removal of monitored files. */
  693         if (veriexec_strict >= VERIEXEC_IDS)
  694                 return (EPERM);
  695 
  696         fileassoc_clear(vp, veriexec_hook);
  697 
  698         vte = veriexec_table_lookup(vp->v_mount);
  699         KASSERT(vte != NULL);
  700 
  701         vte->vte_count--;
  702 
  703         return (0);
  704 }
  705 
  706 /*
  707  * Veriexe rename policy.
  708  */
  709 int
  710 veriexec_renamechk(struct vnode *fromvp, const char *fromname,
  711     struct vnode *tovp, const char *toname, struct lwp *l)
  712 {
  713         struct veriexec_file_entry *vfe, *tvfe;
  714 
  715         if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
  716                 log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to "
  717                     "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname,
  718                     kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
  719                 return (EPERM);
  720         }
  721 
  722         vfe = veriexec_get(fromvp);
  723         tvfe = NULL;
  724         if (tovp != NULL)
  725                 tvfe = veriexec_get(tovp);
  726 
  727         if ((vfe != NULL) || (tvfe != NULL)) {
  728                 if (veriexec_strict >= VERIEXEC_IPS) {
  729                         log(LOG_ALERT, "Veriexec: Preventing rename of `%s' "
  730                             "to `%s', uid=%u, pid=%u: IPS mode, file "
  731                             "monitored.\n", fromname, toname,
  732                             kauth_cred_geteuid(l->l_cred),
  733                             l->l_proc->p_pid);
  734                         return (EPERM);
  735                 }
  736 
  737                 log(LOG_NOTICE, "Veriexec: Monitored file `%s' renamed to "
  738                     "`%s', uid=%u, pid=%u.\n", fromname, toname,
  739                     kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid);
  740         }
  741 
  742         return (0);
  743 }
  744 
  745 /*
  746  * Routine for maintaining mostly consistent message formats in Verified
  747  * Exec.
  748  */
  749 void
  750 veriexec_report(const u_char *msg, const u_char *filename, struct lwp *l, int f)
  751 {
  752         if (msg == NULL || filename == NULL)
  753                 return;
  754 
  755         if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) {
  756                 if (!(f & REPORT_ALARM) || (l == NULL))
  757                         log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg,
  758                             filename);
  759                 else
  760                         log(LOG_ALERT, "Veriexec: %s [%s, pid=%u, uid=%u, "
  761                             "gid=%u]\n", msg, filename, l->l_proc->p_pid,
  762                             kauth_cred_getuid(l->l_cred),
  763                             kauth_cred_getgid(l->l_cred));
  764         }
  765 
  766         if (f & REPORT_PANIC)
  767                 panic("Veriexec: Unrecoverable error.");
  768 }
  769 
  770 static void
  771 veriexec_clear(void *data, int file_specific)
  772 {
  773         if (file_specific) {
  774                 struct veriexec_file_entry *vfe = data;
  775 
  776                 if (vfe != NULL) {
  777                         if (vfe->fp != NULL)
  778                                 free(vfe->fp, M_VERIEXEC);
  779                         if (vfe->page_fp != NULL)
  780                                 free(vfe->page_fp, M_VERIEXEC);
  781                         free(vfe, M_VERIEXEC);
  782                 }
  783         } else {
  784                 struct veriexec_table_entry *vte = data;
  785 
  786                 if (vte != NULL)
  787                         free(vte, M_VERIEXEC);
  788         }
  789 }
  790 
  791 /*
  792  * Invalidate a Veriexec file entry.
  793  * XXX: This should be updated when per-page fingerprints are added.
  794  */
  795 static void
  796 veriexec_file_purge(struct veriexec_file_entry *vfe)
  797 {
  798         if (vfe == NULL)
  799                 return;
  800 
  801         vfe->status = FINGERPRINT_NOTEVAL;
  802 }
  803 
  804 void
  805 veriexec_purge(struct vnode *vp)
  806 {
  807         veriexec_file_purge(veriexec_get(vp));
  808 }
  809 
  810 /*
  811  * Enforce raw disk access policy.
  812  *
  813  * IDS mode: Invalidate fingerprints on a mount if it's opened for writing.
  814  * IPS mode: Don't allow raw writing to disks we monitor.
  815  * Lockdown mode: Don't allow raw writing to all disks.
  816  *
  817  * XXX: This is bogus. There's an obvious race condition between the time
  818  * XXX: the disk is open for writing, in which an attacker can access a
  819  * XXX: monitored file to get its signature cached again, and when the raw
  820  * XXX: file is overwritten on disk.
  821  * XXX:
  822  * XXX: To solve this, we need something like the following:
  823  * XXX:         open raw disk:
  824  * XXX:           - raise refcount,
  825  * XXX:           - invalidate fingerprints,
  826  * XXX:           - mark all entries for that disk with "no cache" flag
  827  * XXX:
  828  * XXX:         veriexec_verify:
  829  * XXX:           - if "no cache", don't cache evaluation result
  830  * XXX:
  831  * XXX:         close raw disk:
  832  * XXX:           - lower refcount,
  833  * XXX:           - if refcount == 0, remove "no cache" flag from all entries
  834  */
  835 static int
  836 veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
  837     void *arg0, void *arg1, void *arg2, void *arg3)
  838 {
  839         int result;
  840         enum kauth_device_req req;
  841         struct veriexec_table_entry *vte;
  842 
  843         result = KAUTH_RESULT_DENY;
  844         req = (enum kauth_device_req)arg0;
  845 
  846         switch (action) {
  847         case KAUTH_DEVICE_RAWIO_SPEC: {
  848                 struct vnode *vp, *bvp;
  849                 dev_t dev;
  850                 int d_type;
  851 
  852                 if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) {
  853                         result = KAUTH_RESULT_DEFER;
  854                         break;
  855                 }
  856 
  857                 vp = arg1;
  858                 KASSERT(vp != NULL);
  859 
  860                 dev = vp->v_un.vu_specinfo->si_rdev;
  861                 d_type = D_OTHER;
  862                 bvp = NULL;
  863 
  864                 /* Handle /dev/mem and /dev/kmem. */
  865                 if ((vp->v_type == VCHR) && iskmemdev(dev)) {
  866                         if (veriexec_strict < VERIEXEC_IPS)
  867                                 result = KAUTH_RESULT_DEFER;
  868 
  869                         break;
  870                 }
  871 
  872                 switch (vp->v_type) {
  873                 case VCHR: {
  874                         const struct cdevsw *cdev;
  875 
  876                         cdev = cdevsw_lookup(dev);
  877                         if (cdev != NULL) {
  878                                 dev_t blkdev;
  879 
  880                                 blkdev = devsw_chr2blk(dev);
  881                                 if (blkdev != NODEV) {
  882                                         vfinddev(blkdev, VBLK, &bvp);
  883                                         if (bvp != NULL)
  884                                                 d_type = cdev->d_type;
  885                                 }
  886                         }
  887 
  888                         break;
  889                         }
  890                 case VBLK: {
  891                         const struct bdevsw *bdev;
  892 
  893                         bdev = bdevsw_lookup(dev);
  894                         if (bdev != NULL)
  895                                 d_type = bdev->d_type;
  896 
  897                         bvp = vp;
  898 
  899                         break;
  900                         }
  901                 default:
  902                         result = KAUTH_RESULT_DEFER;
  903                         break;
  904                 }
  905 
  906                 if (d_type != D_DISK) {
  907                         result = KAUTH_RESULT_DEFER;
  908                         break;
  909                 }
  910 
  911                 /*
  912                  * XXX: See vfs_mountedon() comment in secmodel/bsd44.
  913                  */
  914                 vte = veriexec_table_lookup(bvp->v_mount);
  915                 if (vte == NULL) {
  916                         result = KAUTH_RESULT_DEFER;
  917                         break;
  918                 }
  919 
  920                 switch (veriexec_strict) {
  921                 case VERIEXEC_LEARNING:
  922                 case VERIEXEC_IDS:
  923                         result = KAUTH_RESULT_DEFER;
  924 
  925                         fileassoc_table_run(bvp->v_mount, veriexec_hook,
  926                             (fileassoc_cb_t)veriexec_file_purge);
  927 
  928                         break;
  929                 case VERIEXEC_IPS:
  930                         result = KAUTH_RESULT_DENY;
  931                         break;
  932                 case VERIEXEC_LOCKDOWN:
  933                         result = KAUTH_RESULT_DENY;
  934                         break;
  935                 }
  936 
  937                 break;
  938                 }
  939 
  940         case KAUTH_DEVICE_RAWIO_PASSTHRU:
  941                 /* XXX What can we do here? */
  942                 if (veriexec_strict < VERIEXEC_IPS)
  943                         result = KAUTH_RESULT_DEFER;
  944 
  945                 break;
  946 
  947         default:
  948                 result = KAUTH_RESULT_DEFER;
  949                 break;
  950         }
  951 
  952         return (result);
  953 }
  954 
  955 /*
  956  * Add a file to be monitored by Veriexec.
  957  *
  958  * Expected elements in dict: file, fp, fp-type, entry-type.
  959  */
  960 int
  961 veriexec_file_add(struct lwp *l, prop_dictionary_t dict)
  962 {
  963         struct veriexec_table_entry *vte;
  964         struct veriexec_file_entry *vfe, *hh;
  965         struct nameidata nid;
  966         const char *file, *fp_type;
  967         int error;
  968 
  969         file = prop_string_cstring_nocopy(prop_dictionary_get(dict, "file"));
  970         NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, file, l);
  971         error = namei(&nid);
  972         if (error)
  973                 return (error);
  974 
  975         /* Add only regular files. */
  976         if (nid.ni_vp->v_type != VREG) {
  977                 log(LOG_ERR, "Veriexec: Not adding `%s': Not a regular file.\n",
  978                     file);
  979                 error = EINVAL;
  980                 goto out;
  981         }
  982 
  983         vfe = malloc(sizeof(*vfe), M_VERIEXEC, M_WAITOK);
  984 
  985         /* Lookup fingerprint hashing algorithm. */
  986         fp_type = prop_string_cstring_nocopy(prop_dictionary_get(dict,
  987             "fp-type"));
  988         if ((vfe->ops = veriexec_fpops_lookup(fp_type)) == NULL) {
  989                 free(vfe, M_VERIEXEC);
  990                 log(LOG_ERR, "Veriexec: Invalid or unknown fingerprint type "
  991                     "`%s' for file `%s'.\n", fp_type, file);
  992                 error = EINVAL;
  993                 goto out;
  994         }
  995 
  996         if (prop_data_size(prop_dictionary_get(dict, "fp")) !=
  997             vfe->ops->hash_len) {
  998                 free(vfe, M_VERIEXEC);
  999                 log(LOG_ERR, "Veriexec: Bad fingerprint length for `%s'.\n",
 1000                     file);
 1001                 error = EINVAL;
 1002                 goto out;
 1003         }
 1004 
 1005         vfe->fp = malloc(vfe->ops->hash_len, M_VERIEXEC, M_WAITOK);
 1006         memcpy(vfe->fp, prop_data_data_nocopy(prop_dictionary_get(dict, "fp")),
 1007             vfe->ops->hash_len);
 1008 
 1009         /*
 1010          * See if we already have an entry for this file. If we do, then
 1011          * let the user know and silently pretend to succeed.
 1012          */
 1013         hh = veriexec_get(nid.ni_vp);
 1014         if (hh != NULL) {
 1015                 boolean_t fp_mismatch;
 1016 
 1017                 if (strcmp(vfe->ops->type, fp_type) ||
 1018                     memcmp(hh->fp, vfe->fp, hh->ops->hash_len))
 1019                         fp_mismatch = TRUE;
 1020                 else
 1021                         fp_mismatch = FALSE;
 1022 
 1023                 if ((veriexec_verbose >= 1) || fp_mismatch)
 1024                         log(LOG_NOTICE, "Veriexec: Duplicate entry for `%s' "
 1025                             "ignored. (%s fingerprint)\n", file, 
 1026                             fp_mismatch ? "different" : "same");
 1027 
 1028                 free(vfe->fp, M_VERIEXEC);
 1029                 free(vfe, M_VERIEXEC);
 1030 
 1031                 error = 0;
 1032                 goto out;
 1033         }
 1034 
 1035         /* Continue entry initialization. */
 1036         prop_dictionary_get_uint8(dict, "entry-type", &vfe->type);
 1037         vfe->status = FINGERPRINT_NOTEVAL;
 1038 
 1039         vfe->page_fp = NULL;
 1040         vfe->page_fp_status = PAGE_FP_NONE;
 1041         vfe->npages = 0;
 1042         vfe->last_page_size = 0;
 1043 
 1044         error = fileassoc_add(nid.ni_vp, veriexec_hook, vfe);
 1045         if (error) {
 1046                 free(vfe->fp, M_VERIEXEC);
 1047                 free(vfe, M_VERIEXEC);
 1048                 goto out;
 1049         }
 1050 
 1051         vte = veriexec_table_lookup(nid.ni_vp->v_mount);
 1052         vte->vte_count++;
 1053 
 1054         veriexec_report("New entry.", file, NULL, REPORT_DEBUG);
 1055 
 1056  out:
 1057         vrele(nid.ni_vp);
 1058 
 1059         return (error);
 1060 }
 1061 
 1062 /*
 1063  * Create a new Veriexec table using hints from userland.
 1064  *
 1065  * Expects dict to have mount and count.
 1066  */
 1067 int
 1068 veriexec_table_add(struct lwp *l, prop_dictionary_t dict)
 1069 {
 1070         struct veriexec_table_entry *vte;
 1071         struct nameidata nid;
 1072         u_char buf[16];
 1073         int error;
 1074 
 1075         NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE,
 1076             prop_string_cstring_nocopy(prop_dictionary_get(dict, "mount")), l);
 1077         error = namei(&nid);
 1078         if (error)
 1079                 return (error);
 1080 
 1081         error = fileassoc_table_add(nid.ni_vp->v_mount,
 1082             prop_number_integer_value(prop_dictionary_get(dict, "count")));
 1083         if (error && (error != EEXIST))
 1084                 goto out;
 1085 
 1086         vte = malloc(sizeof(*vte), M_VERIEXEC, M_WAITOK | M_ZERO);
 1087         error = fileassoc_tabledata_add(nid.ni_vp->v_mount, veriexec_hook, vte);
 1088 #ifdef DIAGNOSTIC
 1089         if (error)
 1090                 panic("Fileassoc: Inconsistency after adding table");
 1091 #endif /* DIAGNOSTIC */
 1092 
 1093         snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++);
 1094         sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node,
 1095                        0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL,
 1096                        0, CTL_CREATE, CTL_EOL);
 1097 
 1098         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1099                        CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt",
 1100                        NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_mntonname,
 1101                        0, CTL_CREATE, CTL_EOL);
 1102         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1103                        CTLFLAG_READONLY, CTLTYPE_STRING, "fstype",
 1104                        NULL, NULL, 0, nid.ni_vp->v_mount->mnt_stat.f_fstypename,
 1105                        0, CTL_CREATE, CTL_EOL);
 1106         sysctl_createv(NULL, 0, &vte->vte_node, NULL,
 1107                        CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries",
 1108                        NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL);
 1109 
 1110  out:
 1111         vrele(nid.ni_vp);
 1112         return (error);
 1113 }
 1114 
 1115 int
 1116 veriexec_table_delete(struct lwp *l, struct mount *mp) {
 1117         struct veriexec_table_entry *vte;
 1118 
 1119         vte = veriexec_table_lookup(mp);
 1120         if (vte == NULL)
 1121                 return (ENOENT);
 1122 
 1123         sysctl_free(__UNCONST(vte->vte_node));
 1124         veriexec_tablecount--;
 1125 
 1126         return (fileassoc_table_clear(mp, veriexec_hook));
 1127 }
 1128 
 1129 int
 1130 veriexec_file_delete(struct lwp *l, struct vnode *vp) {
 1131         struct veriexec_table_entry *vte;
 1132         int error;
 1133 
 1134         vte = veriexec_table_lookup(vp->v_mount);
 1135         if (vte == NULL)
 1136                 return (ENOENT);
 1137 
 1138         error = fileassoc_clear(vp, veriexec_hook);
 1139         if (!error)
 1140                 vte->vte_count--;
 1141 
 1142         return (error);
 1143 }
 1144 
 1145 /*
 1146  * Convert Veriexec entry data to a dictionary readable by userland tools.
 1147  */
 1148 int
 1149 veriexec_convert(struct vnode *vp, prop_dictionary_t rdict)
 1150 {
 1151         struct veriexec_file_entry *vfe;
 1152 
 1153         vfe = veriexec_get(vp);
 1154         if (vfe == NULL)
 1155                 return (ENOENT);
 1156 
 1157         prop_dictionary_set_uint8(rdict, "entry-type", vfe->type);
 1158         prop_dictionary_set_uint8(rdict, "status", vfe->status);
 1159         prop_dictionary_set(rdict, "fp-type",
 1160             prop_string_create_cstring(vfe->ops->type));
 1161         prop_dictionary_set(rdict, "fp",
 1162             prop_data_create_data(vfe->fp, vfe->ops->hash_len));
 1163 
 1164         return (0);
 1165 }
 1166 
 1167 int
 1168 veriexec_unmountchk(struct mount *mp)
 1169 {
 1170         int error;
 1171 
 1172         if (doing_shutdown)
 1173                 return (0);
 1174 
 1175         switch (veriexec_strict) {
 1176         case VERIEXEC_LEARNING:
 1177         case VERIEXEC_IDS:
 1178                 if (veriexec_table_delete(curlwp, mp) == 0) {
 1179                         log(LOG_INFO, "Veriexec: IDS mode, allowing  unmount "
 1180                             "of \"%s\".\n", mp->mnt_stat.f_mntonname);
 1181                 }
 1182 
 1183                 error = 0;
 1184                 break;
 1185 
 1186         case VERIEXEC_IPS: {
 1187                 struct veriexec_table_entry *vte;
 1188 
 1189                 vte = fileassoc_tabledata_lookup(mp, veriexec_hook);
 1190                 if ((vte != NULL) && (vte->vte_count > 0)) {
 1191                         log(LOG_ALERT, "Veriexec: IPS mode, preventing"
 1192                             " unmount of \"%s\" with monitored files.\n",
 1193                             mp->mnt_stat.f_mntonname);
 1194 
 1195                         error = EPERM;
 1196                 } else
 1197                         error = 0;
 1198                 break;
 1199                 }
 1200  
 1201         case VERIEXEC_LOCKDOWN:
 1202         default:
 1203                 log(LOG_ALERT, "Veriexec: Lockdown mode, preventing unmount "
 1204                     "of \"%s\".\n", mp->mnt_stat.f_mntonname);
 1205                 error = EPERM;
 1206                 break;
 1207         }
 1208 
 1209         return (error);
 1210 }
 1211 
 1212 int
 1213 veriexec_openchk(struct lwp *l, struct vnode *vp, const char *path, int fmode)
 1214 {
 1215         boolean_t monitored = FALSE;
 1216         int error = 0;
 1217 
 1218         if (vp == NULL) {
 1219                 /* If no creation requested, let this fail normally. */
 1220                 if (!(fmode & O_CREAT)) {
 1221                         error = 0;
 1222                         goto out;
 1223                 }
 1224 
 1225                 /* Lockdown mode: Prevent creation of new files. */
 1226                 if (veriexec_strict >= VERIEXEC_LOCKDOWN) {
 1227                         log(LOG_ALERT, "Veriexec: Preventing new file "
 1228                             "creation in `%s'.\n", path);
 1229                         error = EPERM;
 1230                 }
 1231 
 1232                 goto out;
 1233         }
 1234 
 1235         error = veriexec_verify(l, vp, path, VERIEXEC_FILE,
 1236             &monitored);
 1237         if (error)
 1238                 goto out;
 1239 
 1240         if (monitored && ((fmode & FWRITE) || (fmode & O_TRUNC))) {
 1241                 veriexec_report("Write access request.", path, l,
 1242                     REPORT_ALWAYS | REPORT_ALARM);
 1243 
 1244                 /* IPS mode: Deny writing to/truncating monitored files. */
 1245                 if (veriexec_strict >= VERIEXEC_IPS)
 1246                         error = EPERM;
 1247                 else
 1248                         veriexec_purge(vp);
 1249         }
 1250 
 1251  out:
 1252         return (error);
 1253 }

Cache object: b02fde6ba0521dfb003e1e20d0a036cc


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