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/security/mac_veriexec/veriexec_fingerprint.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 /*
    2  * $FreeBSD$
    3  *
    4  * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc.
    5  * All rights reserved.
    6  *
    7  * Originally derived from:
    8  *      $NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $
    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. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 
   34 #include "opt_mac.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/imgact.h>
   39 #include <sys/jail.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mount.h> 
   44 #include <sys/mutex.h>
   45 #include <sys/proc.h>
   46 #include <sys/sbuf.h>
   47 #include <sys/syslog.h>
   48 #include <sys/vnode.h>
   49 
   50 #include "mac_veriexec.h"
   51 #include "mac_veriexec_internal.h"
   52 
   53 /**
   54  * @var fpops_list
   55  * @internal
   56  * @brief Fingerprint operations list
   57  *
   58  * This is essentially the list of fingerprint modules currently loaded
   59  */
   60 static LIST_HEAD(fpopshead, mac_veriexec_fpops) fpops_list;
   61 
   62 static int mac_veriexec_late;
   63 
   64 static int sysctl_mac_veriexec_algorithms(SYSCTL_HANDLER_ARGS);
   65 
   66 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, algorithms,
   67     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
   68     0, 0, sysctl_mac_veriexec_algorithms, "A",
   69     "Verified execution supported hashing algorithms");
   70 
   71 static int
   72 sysctl_mac_veriexec_algorithms(SYSCTL_HANDLER_ARGS)
   73 {
   74         struct sbuf sb;
   75         struct mac_veriexec_fpops *fpops;
   76         int algorithms, error;
   77 
   78         algorithms = 0;
   79         sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
   80         LIST_FOREACH(fpops, &fpops_list, entries) {
   81                 if (algorithms++)
   82                         sbuf_printf(&sb, " ");
   83                 sbuf_printf(&sb, "%s", fpops->type);
   84         }
   85         sbuf_finish(&sb);
   86         error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
   87         sbuf_delete(&sb);
   88         return (error);
   89 }
   90 
   91 /**
   92  * @internal
   93  * @brief Consistently identify file encountering errors
   94  *
   95  * @param imgp          image params to display
   96  * @param td            calling thread
   97  * @param msg           message to display
   98  *
   99  * @return String form of the information stored in @p imgp
  100  */
  101 static void
  102 identify_error (struct image_params *imgp, struct thread *td, const char *msg)
  103 {
  104         struct proc *parent;
  105         pid_t ppid, gppid;
  106 
  107         parent = imgp->proc->p_pptr;
  108         ppid = (parent != NULL) ? parent->p_pid : 0;
  109         gppid = (parent != NULL && parent->p_pptr != NULL) ?
  110             parent->p_pptr->p_pid : 0;
  111 
  112         log(LOG_ERR, MAC_VERIEXEC_FULLNAME ": %s (file=%s fsid=%ju fileid=%ju "
  113             "gen=%lu uid=%u pid=%u ppid=%u gppid=%u)", msg,
  114             (imgp->args != NULL) ? imgp->args->fname : "",
  115             (uintmax_t)imgp->attr->va_fsid, (uintmax_t)imgp->attr->va_fileid,
  116             imgp->attr->va_gen, td->td_ucred->cr_ruid, imgp->proc->p_pid,
  117             ppid, gppid);
  118 }
  119 
  120 /**
  121  * @internal
  122  * @brief Check the fingerprint type for the given file and evaluate the
  123  * fingerprint for that file.
  124  *
  125  * It is assumed that @p fingerprint has sufficient storage to hold the
  126  * resulting fingerprint string.
  127  *
  128  * @param vp            vnode to check
  129  * @param ip            file info from the meta-data store
  130  * @param td            calling thread
  131  * @param file_size     size of the file to read
  132  * @param fingerprint   resulting fingerprint
  133  *
  134  * @return 0 on success, otherwise an error code.
  135  */
  136 static int
  137 evaluate_fingerprint(struct vnode *vp, struct mac_veriexec_file_info *ip,
  138     struct thread *td, off_t file_size, unsigned char *fingerprint)
  139 {
  140         uint8_t *filebuf;
  141         void *ctx;
  142         off_t offset;
  143         size_t count, nread, resid;
  144         int error = EINVAL;
  145 
  146         filebuf = malloc(PAGE_SIZE, M_VERIEXEC, M_WAITOK);
  147         ctx = malloc(ip->ops->context_size, M_VERIEXEC, M_WAITOK);
  148 
  149         (ip->ops->init)(ctx);
  150         for (offset = 0; offset < file_size; offset += nread) {
  151                 if ((offset + PAGE_SIZE) > file_size)
  152                         count = file_size - offset;
  153                 else
  154                         count = PAGE_SIZE;
  155 
  156                 error = vn_rdwr_inchunks(UIO_READ, vp, filebuf, count, offset,
  157                     UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid,
  158                     td);
  159                 if (error)
  160                         goto failed;
  161 
  162                 nread = count - resid;
  163                 (ip->ops->update)(ctx, filebuf, nread);
  164         }
  165         (ip->ops->final)(fingerprint, ctx);
  166 
  167 #ifdef DEBUG_VERIEXEC_FINGERPRINT
  168         for (offset = 0; offset < ip->ops->digest_len; offset++)
  169                 printf("%02x", fingerprint[offset]);
  170         printf("\n");
  171 #endif
  172 
  173 failed:
  174         free(ctx, M_VERIEXEC);
  175         free(filebuf, M_VERIEXEC);
  176         return (error);
  177 }
  178 
  179 /**
  180  * @internal
  181  * @brief Compare the two given fingerprints to see if they are the same.
  182  *
  183  * Differing fingerprint methods may have differing lengths which
  184  * is handled by this routine.
  185  *
  186  * @param ip            file info from the meta-data store
  187  * @param digest        digest to compare
  188  *
  189  * @return 0 if the fingerprints match and non-zero if they do not.
  190  */
  191 static int
  192 fingerprintcmp(struct mac_veriexec_file_info *ip, unsigned char *digest)
  193 {
  194 
  195         return memcmp(ip->fingerprint, digest, ip->ops->digest_len);
  196 }
  197 
  198 /**
  199  * @brief Check if @p fingerprint matches the one associated with the vnode
  200  *     @p vp
  201  *
  202  * @param vp            vnode to check
  203  * @param ip            file info from the meta-data store
  204  * @param td            calling thread
  205  * @param file_size     size of the file to read
  206  * @param fingerprint   fingerprint to compare
  207  *
  208  * @return 0 if they match, otherwise an error code.
  209  */
  210 int
  211 mac_veriexec_fingerprint_check_vnode(struct vnode *vp,
  212     struct mac_veriexec_file_info *ip, struct thread *td, off_t file_size,
  213     unsigned char *fingerprint)
  214 {
  215         int error;
  216 
  217         /* reject fingerprint if writers are active */
  218         if (vp->v_writecount > 0)
  219                 return (ETXTBSY);
  220 
  221         if ((vp->v_mount->mnt_flag & MNT_VERIFIED) != 0) {
  222                 VERIEXEC_DEBUG(2, ("file %ju.%lu on verified %s mount\n",
  223                     (uintmax_t)ip->fileid, ip->gen,
  224                     vp->v_mount->mnt_vfc->vfc_name));
  225 
  226                 /*
  227                  * The VFS is backed by a file which has been verified.
  228                  * No need to waste time here.
  229                  */
  230                 return (0);
  231         }
  232 
  233         error = evaluate_fingerprint(vp, ip, td, file_size, fingerprint);
  234         if (error)
  235                 return (error);
  236 
  237         if (fingerprintcmp(ip, fingerprint) != 0)
  238                 return (EAUTH);
  239 
  240         return (0);
  241 }
  242 
  243 /**
  244  * @brief Check a file signature and validate it.
  245  *
  246  * @param imgp          parameters for the image to check
  247  * @param check_files   if 1, check the files list first, otherwise check the
  248  *                      exectuables list first
  249  * @param td            calling thread
  250  *
  251  * @note Called with imgp->vp locked.
  252  *
  253  * @return 0 if the signature is valid, otherwise an error code.
  254  */
  255 int
  256 mac_veriexec_fingerprint_check_image(struct image_params *imgp,
  257     int check_files, struct thread *td)
  258 {
  259         struct vnode *vp = imgp->vp;
  260         int error;
  261         fingerprint_status_t status;
  262 
  263         if (!mac_veriexec_in_state(VERIEXEC_STATE_ACTIVE))
  264                 return 0;
  265 
  266         error = mac_veriexec_metadata_fetch_fingerprint_status(vp, imgp->attr,
  267             td, check_files);
  268         if (error && error != EAUTH)
  269                 return (error);
  270 
  271         /*
  272          * By now status is set.
  273          */
  274         status = mac_veriexec_get_fingerprint_status(vp);
  275         switch (status) {
  276         case FINGERPRINT_INVALID: /* should not happen */
  277                 identify_error(imgp, td, "got unexpected FINGERPRINT_INVALID");
  278                 error = EPERM;
  279                 break;
  280 
  281         case FINGERPRINT_FILE:
  282                 if (!check_files) {
  283                         if (prison0.pr_securelevel > 1 ||
  284                             mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
  285                                 error = EPERM;
  286                 }
  287                 break;
  288 
  289         case FINGERPRINT_VALID: /* is ok - report so if debug is on */
  290                 VERIEXEC_DEBUG(4, ("Fingerprint matches\n"));
  291                 break;
  292 
  293         case FINGERPRINT_INDIRECT: /* fingerprint ok but need to check
  294                                       for direct execution */
  295                 if (!imgp->interpreted) {
  296                         identify_error(imgp, td, "attempted direct execution");
  297                         if (prison0.pr_securelevel > 1 ||
  298                             mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
  299                                 error = EPERM;
  300                 }
  301                 break;
  302 
  303         case FINGERPRINT_NOMATCH: /* does not match - whine about it */
  304                 identify_error(imgp, td,
  305                     "fingerprint does not match loaded value");
  306                 if (prison0.pr_securelevel > 1 ||
  307                     mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
  308                         error = EAUTH;
  309                 break;
  310 
  311         case FINGERPRINT_NOENTRY: /* no entry in the list, complain */
  312                 identify_error(imgp, td, "no fingerprint");
  313                 if (prison0.pr_securelevel > 1 ||
  314                     mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
  315                         error = EAUTH;
  316                 break;
  317 
  318         case FINGERPRINT_NODEV: /* no signatures for the device, complain */
  319                 identify_error(imgp, td, "no signatures for device");
  320                 if (prison0.pr_securelevel > 1 ||
  321                     mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE))
  322                         error = EAUTH;
  323                 break;
  324 
  325         default: /* this should never happen. */
  326                 identify_error(imgp, td, "invalid status field for vnode");
  327                 error = EPERM;
  328         }
  329         return error; 
  330 }
  331 
  332 /**
  333  * @brief Look up the fingerprint operations for a specific digest type
  334  *
  335  * @return A pointer to fingerprint operations, if found, or else @c NULL.
  336  */
  337 struct mac_veriexec_fpops *
  338 mac_veriexec_fingerprint_lookup_ops(const char *type)
  339 {
  340         struct mac_veriexec_fpops *fpops;
  341 
  342         if (type == NULL)
  343                 return (NULL);
  344 
  345         LIST_FOREACH(fpops, &fpops_list, entries) {
  346                 if (!strcasecmp(type, fpops->type))
  347                         break;
  348         }
  349         return (fpops);
  350 }
  351 
  352 /**
  353  * @brief Add fingerprint operations for a specific digest type
  354  *
  355  * Any attempts to add a duplicate digest type results in an error.
  356  *
  357  * @return 0 if the ops were added successfully, otherwise an error code.
  358  */
  359 int
  360 mac_veriexec_fingerprint_add_ops(struct mac_veriexec_fpops *fpops)
  361 {
  362 
  363         /* Sanity check the ops */
  364         if (fpops->type == NULL || fpops->digest_len == 0 ||
  365             fpops->context_size == 0 || fpops->init == NULL ||
  366             fpops->update == NULL || fpops->final == NULL)
  367                 return (EINVAL);
  368 
  369         /* Make sure we do not already have ops for this digest type */
  370         if (mac_veriexec_fingerprint_lookup_ops(fpops->type))
  371                 return (EEXIST);
  372 
  373         /* Add the ops to the list */
  374         LIST_INSERT_HEAD(&fpops_list, fpops, entries);
  375 
  376         printf("MAC/veriexec fingerprint module loaded: %s\n", fpops->type);
  377 
  378         return (0);
  379 }
  380 
  381 /**
  382  * @brief Initialize the fingerprint operations list
  383  */
  384 void
  385 mac_veriexec_fingerprint_init(void)
  386 {
  387 
  388         LIST_INIT(&fpops_list);
  389 }
  390 
  391 /**
  392  * @brief Handle fingerprint module events
  393  *
  394  * This function is called by the @c MAC_VERIEXEC_FPMOD macro.
  395  *
  396  * @param mod           module information
  397  * @param type          event type
  398  * @param data          event-specific data
  399  *
  400  * @return On @c MOD_LOAD, 0 if the fingerprint ops were added successfully,
  401  *     otherwise an error code. All other event types result in an error code.
  402  */
  403 int
  404 mac_veriexec_fingerprint_modevent(module_t mod, int type, void *data)
  405 {
  406         struct mac_veriexec_fpops *fpops;
  407         int error;
  408 
  409         error = 0;
  410         fpops = (struct mac_veriexec_fpops *) data;
  411 
  412         switch (type) {
  413         case MOD_LOAD:
  414                 /* We do not allow late loading of fingerprint modules */
  415                 if (mac_veriexec_late) {
  416                         printf("%s: can't load %s fingerprint module after "
  417                             "booting\n", __func__, fpops->type);
  418                         error = EBUSY;
  419                         break;
  420                 }
  421                 error = mac_veriexec_fingerprint_add_ops(fpops);
  422                 break;
  423         case MOD_UNLOAD:
  424                 error = EBUSY;
  425                 break;
  426         default:
  427                 error = EOPNOTSUPP;
  428                 break;
  429         }
  430 
  431         return (error);
  432 }
  433 
  434 /**
  435  * @internal
  436  * @brief Mark veriexec late initialization flag
  437  */
  438 static void
  439 mac_veriexec_late_init(void)
  440 {
  441 
  442         mac_veriexec_late = 1;
  443 }
  444 
  445 SYSINIT(mac_veriexec_late, SI_SUB_MAC_LATE, SI_ORDER_ANY,
  446     mac_veriexec_late_init, NULL);

Cache object: 4a51c255a84282921026d01206398415


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