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_metadata.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, 2019, 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/exec.h>
   39 #include <sys/lock.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mutex.h>
   42 #include <sys/proc.h>
   43 #include <sys/sbuf.h>
   44 #include <sys/vnode.h>
   45 
   46 #include "mac_veriexec.h"
   47 #include "mac_veriexec_internal.h"
   48 
   49 /**
   50  * @brief per-device meta-data storage
   51  */
   52 struct veriexec_dev_list {
   53         dev_t fsid;     /**< file system identifier of the mount point */
   54         LIST_HEAD(filehead, mac_veriexec_file_info) file_head;
   55             /**< list of per-file meta-data information */
   56         LIST_ENTRY(veriexec_dev_list) entries;
   57             /**< next entries in the device list */
   58 };
   59 
   60 typedef LIST_HEAD(veriexec_devhead, veriexec_dev_list) veriexec_devhead_t;
   61 
   62 /**
   63  * @brief Mutex to protect the meta-data store lists
   64  */
   65 struct mtx ve_mutex;
   66 
   67 /**
   68  * @brief Executables meta-data storage
   69  *
   70  * This is used to store the fingerprints for potentially-executable files.
   71  */
   72 veriexec_devhead_t veriexec_dev_head;
   73 
   74 /**
   75  * @brief Plain file meta-data storage
   76  *
   77  * This is used for files that are not allowed to be executed, but should
   78  * have fingerprint validation available.
   79  */
   80 veriexec_devhead_t veriexec_file_dev_head;
   81 
   82 /**
   83  * @internal
   84  * @brief Search the @p head meta-data list for the specified file identifier
   85  *     @p fileid in the file system identified by @p fsid
   86  *
   87  * If meta-data exists for file system identified by @p fsid, it has a
   88  * fingerprint list, and @p found_dev is not @c NULL then store true in the
   89  * location pointed to by @p found_dev
   90  *
   91  * @param head          meta-data list to search
   92  * @param fsid          file system identifier to look for
   93  * @param fileid        file to look for
   94  * @param gen           generation of file
   95  * @param found_dev     indicator that an entry for the file system was found
   96  *
   97  * @return A pointer to the meta-data inforation if meta-data exists for
   98  *     the specified file identifier, otherwise @c NULL
   99  */
  100 static struct mac_veriexec_file_info *
  101 get_veriexec_file(struct veriexec_devhead *head, dev_t fsid, long fileid,
  102     unsigned long gen, int *found_dev)
  103 {
  104         struct veriexec_dev_list *lp;
  105         struct mac_veriexec_file_info *ip, *tip;
  106 
  107         ip = NULL;
  108 
  109         /* Initialize the value found_dev, if non-NULL */
  110         if (found_dev != NULL)
  111                 *found_dev = 0;
  112 
  113         VERIEXEC_DEBUG(3, ("searching for file %ju.%lu on device %ju,"
  114             " files=%d\n", (uintmax_t)fileid, gen, (uintmax_t)fsid,
  115             (head == &veriexec_file_dev_head)));
  116 
  117         /* Get a lock to access the list */
  118         mtx_lock(&ve_mutex);
  119 
  120         /* First, look for the file system */
  121         for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries))
  122                 if (lp->fsid == fsid)
  123                         break;
  124 
  125         /* We found the file system in the list */
  126         if (lp != NULL) {
  127                 VERIEXEC_DEBUG(3, ("found matching dev number %ju\n",
  128                     (uintmax_t)lp->fsid));
  129 
  130                 /* If found_dev is non-NULL, store true there */
  131                 if (found_dev != NULL)
  132                         *found_dev = 1;
  133 
  134                 /* Next, look for the meta-data information for the file */
  135                 LIST_FOREACH_SAFE(ip, &(lp->file_head), entries, tip) {
  136                         if (ip->fileid == fileid) {
  137                                 if (ip->gen == gen)
  138                                         break;
  139                                 /* we need to garbage collect */
  140                                 LIST_REMOVE(ip, entries);
  141                                 if (ip->label)
  142                                         free(ip->label, M_VERIEXEC);
  143                                 free(ip, M_VERIEXEC);
  144                         }
  145                 }
  146         }
  147 
  148         /* Release the lock we obtained earlier */
  149         mtx_unlock(&ve_mutex);
  150 
  151         /* Return the meta-data information we found, if anything */
  152         return (ip);
  153 }
  154 
  155 /**
  156  * @internal
  157  * @brief Display the fingerprint for each entry in the device list
  158  *
  159  * @param sbp           sbuf to write output to
  160  * @param lp            pointer to device list
  161  */
  162 static void
  163 mac_veriexec_print_db_dev_list(struct sbuf *sbp, struct veriexec_dev_list *lp)
  164 {
  165         struct mac_veriexec_file_info *ip;
  166 
  167 #define FPB(i) (ip->fingerprint[i])
  168         for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL;
  169             ip = LIST_NEXT(ip, entries))
  170                 sbuf_printf(sbp, "  %ld: %u %ld [%02x %02x %02x %02x %02x "
  171                     "%02x %02x %02x...]\n", ip->fileid, ip->flags, ip->gen,
  172                     FPB(0), FPB(1), FPB(2), FPB(3), FPB(4), FPB(5), FPB(6),
  173                     FPB(7));
  174 }
  175 
  176 /**
  177  * @internal
  178  * @brief Display the device list
  179  *
  180  * @param sbp           sbuf to write output to
  181  * @param head          pointer to head of the device list
  182  */
  183 static void
  184 mac_veriexec_print_db_head(struct sbuf *sbp, struct veriexec_devhead *head)
  185 {
  186         struct veriexec_dev_list *lp;
  187 
  188         for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) {
  189                 sbuf_printf(sbp, " FS id: %ju\n", (uintmax_t)lp->fsid);
  190                 mac_veriexec_print_db_dev_list(sbp, lp);
  191         }
  192 
  193 }
  194 
  195 /**
  196  * @internal
  197  * @brief Generate human-readable output for the current fingerprint database
  198  *
  199  * @param sbp   sbuf to write output to
  200  */
  201 void
  202 mac_veriexec_metadata_print_db(struct sbuf *sbp)
  203 {
  204         struct {
  205                 struct veriexec_devhead *h;
  206                 const char *name;
  207         } fpdbs[] = {
  208                 { &veriexec_file_dev_head, "regular files" },
  209                 { &veriexec_dev_head, "executable files" },
  210         };
  211         int i;
  212 
  213         mtx_lock(&ve_mutex);
  214         for (i = 0; i < sizeof(fpdbs)/sizeof(fpdbs[0]); i++) {
  215                 sbuf_printf(sbp, "%s fingerprint db:\n", fpdbs[i].name);
  216                 mac_veriexec_print_db_head(sbp, fpdbs[i].h);
  217         }
  218         mtx_unlock(&ve_mutex);
  219 }
  220 /**
  221  * @brief Determine if the meta-data store has an entry for the specified file.
  222  *
  223  * @param fsid          file system identifier to look for
  224  * @param fileid        file to look for
  225  * @param gen           generation of file
  226  *
  227  * @return 1 if there is an entry in the meta-data store, 0 otherwise.
  228  */
  229 int
  230 mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen)
  231 {
  232 
  233         return (mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL,
  234             VERIEXEC_FILES_FIRST) != NULL);
  235 }
  236 
  237 /**
  238  * @brief Search the list of devices looking for the one given, in order to
  239  *     release the resources used by it.
  240  *
  241  * If found, free all file entries for it, and remove it from the list.
  242  *
  243  * @note Called with @a ve_mutex held
  244  *
  245  * @param fsid          file system identifier to look for
  246  * @param head          meta-data list to search
  247  *
  248  * @return 0 if the device entry was freed, otherwise an error code
  249  */
  250 static int
  251 free_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
  252 {
  253         struct veriexec_dev_list *lp;
  254         struct mac_veriexec_file_info *ip, *nip;
  255 
  256         /* Look for the file system */
  257         for (lp = LIST_FIRST(head); lp != NULL;
  258              lp = LIST_NEXT(lp, entries))
  259                 if (lp->fsid == fsid) break;
  260 
  261         /* If lp is NULL, we did not find it */
  262         if (lp == NULL)
  263                 return ENOENT;
  264 
  265         /* Unhook lp, before we free it and its content */
  266         LIST_REMOVE(lp, entries);
  267 
  268         /* Release the lock */
  269         mtx_unlock(&ve_mutex);
  270 
  271         /* Free the file entries in the list */
  272         for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = nip) {
  273                 nip = LIST_NEXT(ip, entries);
  274                 LIST_REMOVE(ip, entries);
  275                 if (ip->label)
  276                         free(ip->label, M_VERIEXEC);
  277                 free(ip, M_VERIEXEC);
  278         }
  279 
  280         /* Free the meta-data entry for the device */
  281         free(lp, M_VERIEXEC);
  282 
  283         /* Re-acquire the lock */
  284         mtx_lock(&ve_mutex);
  285         return 0;
  286 }
  287 
  288 /**
  289  * @brief Search the list of devices looking for the one given.
  290  *
  291  * If it is not in the list then add it.
  292  *
  293  * @note Called with @a ve_mutex held
  294  *
  295  * @param fsid          file system identifier to look for
  296  * @param head          meta-data list to search
  297  *
  298  * @return A pointer to the meta-data entry for the device, if found or added,
  299  *     otherwise @c NULL
  300  */
  301 static struct veriexec_dev_list *
  302 find_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
  303 {
  304         struct veriexec_dev_list *lp;
  305         struct veriexec_dev_list *np = NULL;
  306 
  307 search:
  308         /* Look for the file system */
  309         for (lp = LIST_FIRST(head); lp != NULL;
  310              lp = LIST_NEXT(lp, entries))
  311                 if (lp->fsid == fsid) break;
  312 
  313         if (lp == NULL) {
  314                 if (np == NULL) {
  315                         /*
  316                          * If pointer is null then entry not there,
  317                          * add a new one, first try to malloc while
  318                          * we hold mutex - should work most of the time.
  319                          */
  320                         np = malloc(sizeof(struct veriexec_dev_list),
  321                             M_VERIEXEC, M_NOWAIT);
  322                         if (np == NULL) {
  323                                 /*
  324                                  * So much for that plan, dop the mutex
  325                                  * and repeat...
  326                                  */
  327                                 mtx_unlock(&ve_mutex);
  328                                 np = malloc(sizeof(struct veriexec_dev_list),
  329                                     M_VERIEXEC, M_WAITOK);
  330                                 mtx_lock(&ve_mutex);
  331                                 /*
  332                                  * Repeat the search, in case someone
  333                                  * added this while we slept.
  334                                  */
  335                                 goto search;
  336                         }
  337                 }
  338                 if (np) {
  339                         /* Add the entry to the list */
  340                         lp = np;
  341                         LIST_INIT(&(lp->file_head));
  342                         lp->fsid = fsid;
  343                         LIST_INSERT_HEAD(head, lp, entries);
  344                 }
  345         } else if (np) {
  346                 /*
  347                  * Someone else did it while we slept.
  348                  */
  349                 mtx_unlock(&ve_mutex);
  350                 free(np, M_VERIEXEC);
  351                 mtx_lock(&ve_mutex);
  352         }
  353 
  354         return (lp);
  355 }
  356 
  357 /**
  358  * @internal
  359  * @brief Allocate and initialize label record with the provided data.
  360  *
  361  * @param labelp        Location to store the initialized label
  362  * @param src           Pointer to label string to copy
  363  * @param srclen        Length of label string to copy
  364  *
  365  * @return Length of resulting label
  366  *
  367  * @note Called with ve_mutex locked.
  368  */
  369 static size_t
  370 mac_veriexec_init_label(char **labelp, size_t labellen, char *src,
  371     size_t srclen)
  372 {
  373         char *label;
  374 
  375         label = *labelp;
  376         if (labellen < srclen) {
  377                 mtx_unlock(&ve_mutex);
  378                 if (label != NULL)
  379                         free(label, M_VERIEXEC);
  380                 label = malloc(srclen, M_VERIEXEC, M_WAITOK);
  381                 mtx_lock(&ve_mutex);
  382                 labellen = srclen;
  383                 *labelp = label;
  384         }
  385         memcpy(label, src, srclen);
  386         return labellen;
  387 }
  388 
  389 /**
  390  * @brief When a device is unmounted, we want to toss the signatures recorded
  391  *     against it.
  392  *
  393  * We are being called from unmount() with the root vnode just before it is
  394  * freed.
  395  *
  396  * @param fsid          file system identifier to look for
  397  * @param td            calling thread
  398  *
  399  * @return 0 on success, otherwise an error code.
  400  */
  401 int
  402 mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td)
  403 {
  404     int error;
  405 
  406     /*
  407      * The device can have entries on both lists.
  408      */
  409     mtx_lock(&ve_mutex);
  410     error = free_veriexec_dev(fsid, &veriexec_dev_head);
  411     if (error && error != ENOENT) {
  412             mtx_unlock(&ve_mutex);
  413             return error;
  414     }
  415     error = free_veriexec_dev(fsid, &veriexec_file_dev_head);
  416     mtx_unlock(&ve_mutex);
  417     if (error && error != ENOENT) {
  418             return error;
  419     }
  420     return 0;
  421 }
  422 
  423 /**
  424  * @brief Return the flags assigned to the file identified by file system
  425  *        identifier @p fsid and file identifier @p fileid.
  426  *
  427  * @param fsid          file system identifier
  428  * @param fileid        file identifier within the file system
  429  * @param gen           generation of file
  430  * @param flags         pointer to location to store the flags
  431  * @param check_files   if 1, check the files list first, otherwise check the
  432  *                      exectuables list first
  433  *
  434  * @return 0 on success, otherwise an error code.
  435  */
  436 int
  437 mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen,
  438     int *flags, int check_files)
  439 {
  440         struct mac_veriexec_file_info *ip;
  441         int found_dev;
  442 
  443         ip = mac_veriexec_metadata_get_file_info(fsid, fileid, gen, &found_dev,
  444             check_files);
  445         if (ip == NULL)
  446                 return (ENOENT);
  447 
  448         *flags = ip->flags;
  449         return (0);
  450 }
  451 
  452 /**
  453  * @brief get the files for the specified process
  454  *
  455  * @param cred          credentials to use
  456  * @param p             process to get the flags for
  457  * @param flags         where to store the flags
  458  * @param check_files   if 1, check the files list first, otherwise check the
  459  *                      exectuables list first
  460  *
  461  * @return 0 if the process has an entry in the meta-data store, otherwise an
  462  *     error code
  463  */
  464 int
  465 mac_veriexec_metadata_get_executable_flags(struct ucred *cred, struct proc *p,
  466     int *flags, int check_files)
  467 {
  468         struct vnode *proc_vn;
  469         struct vattr vap;
  470         int error;
  471 
  472         /* Get the text vnode for the process */
  473         proc_vn = p->p_textvp;
  474         if (proc_vn == NULL)
  475                 return EINVAL;
  476 
  477         /* Get vnode attributes */
  478         error = VOP_GETATTR(proc_vn, &vap, cred);
  479         if (error)
  480                 return error;
  481 
  482         error = mac_veriexec_metadata_get_file_flags(vap.va_fsid,
  483             vap.va_fileid, vap.va_gen, flags,
  484             (check_files == VERIEXEC_FILES_FIRST));
  485 
  486         return (error);
  487 }
  488 
  489 /**
  490  * @brief Ensure the fingerprint status for the vnode @p vp is assigned to its
  491  *     MAC label.
  492  *
  493  * @param vp            vnode to check
  494  * @param vap           vnode attributes to use
  495  * @param td            calling thread
  496  * @param check_files   if 1, check the files list first, otherwise check the
  497  *                      exectuables list first
  498  *
  499  * @return 0 on success, otherwise an error code.
  500  */
  501 int
  502 mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp,
  503     struct vattr *vap, struct thread *td, int check_files)
  504 {
  505         unsigned char digest[MAXFINGERPRINTLEN];
  506         struct mac_veriexec_file_info *ip;
  507         int error, found_dev;
  508         fingerprint_status_t status;
  509 
  510         error = 0;
  511         ip = NULL;
  512 
  513         status = mac_veriexec_get_fingerprint_status(vp);
  514         if (status == FINGERPRINT_INVALID || status == FINGERPRINT_NODEV) {
  515                 found_dev = 0;
  516                 ip = mac_veriexec_metadata_get_file_info(vap->va_fsid,
  517                     vap->va_fileid, vap->va_gen, &found_dev, check_files);
  518                 if (ip == NULL) {
  519                         status = (found_dev) ? FINGERPRINT_NOENTRY :
  520                             FINGERPRINT_NODEV;
  521                         VERIEXEC_DEBUG(3,
  522                             ("fingerprint status is %d for dev %ju, file "
  523                             "%ju.%lu\n", status, (uintmax_t)vap->va_fsid,
  524                             (uintmax_t)vap->va_fileid, vap->va_gen));
  525                 } else {
  526                         /*
  527                          * evaluate and compare fingerprint
  528                          */
  529                         error = mac_veriexec_fingerprint_check_vnode(vp, ip,
  530                             td, vap->va_size, digest);
  531                         switch (error) {
  532                         case 0:
  533                                 /* Process flags */
  534                                 if ((ip->flags & VERIEXEC_INDIRECT))
  535                                         status = FINGERPRINT_INDIRECT;
  536                                 else if ((ip->flags & VERIEXEC_FILE))
  537                                         status = FINGERPRINT_FILE;
  538                                 else
  539                                         status = FINGERPRINT_VALID;
  540                                 VERIEXEC_DEBUG(2,
  541                                     ("%sfingerprint matches for dev %ju, file "
  542                                     "%ju.%lu\n",
  543                                      (status == FINGERPRINT_INDIRECT) ?
  544                                      "indirect " :
  545                                      (status == FINGERPRINT_FILE) ?
  546                                      "file " : "", (uintmax_t)vap->va_fsid,
  547                                      (uintmax_t)vap->va_fileid, vap->va_gen));
  548                                 break;
  549 
  550                         case EAUTH:
  551 #ifdef VERIFIED_EXEC_DEBUG_VERBOSE
  552                                 {
  553                                         char have[MAXFINGERPRINTLEN * 2 + 1];
  554                                         char want[MAXFINGERPRINTLEN * 2 + 1];
  555                                         int i, len;
  556 
  557                                         len = ip->ops->digest_len;
  558                                         for (i = 0; i < len; i++) {
  559                                                 sprintf(&want[i * 2], "%02x",
  560                                                     ip->fingerprint[i]);
  561                                                 sprintf(&have[i * 2], "%02x",
  562                                                     digest[i]);
  563                                         }
  564                                         log(LOG_ERR, MAC_VERIEXEC_FULLNAME
  565                                             ": fingerprint for dev %ju, file "
  566                                             "%ju.%lu %s != %s\n",
  567                                             (uintmax_t)vap->va_fsid,
  568                                             (uintmax_t)vap->va_fileid,
  569                                             vap->va_gen,
  570                                             have, want);
  571                                 }
  572 #endif
  573                                 status = FINGERPRINT_NOMATCH;
  574                                 break;
  575                         default:
  576                                 VERIEXEC_DEBUG(2,
  577                                     ("fingerprint status error %d\n", error));
  578                                 break;
  579                         }
  580                 }
  581                 mac_veriexec_set_fingerprint_status(vp, status);
  582         }
  583         return (error);
  584 }
  585 
  586 /**
  587  * Add a file and its fingerprint to the list of files attached
  588  * to the device @p fsid.
  589  *
  590  * Only add the entry if it is not already on the list.
  591  *
  592  * @note Called with @a ve_mutex held
  593  *
  594  * @param file_dev      if 1, the entry should be added on the file list,
  595  *                      otherwise it should be added on the executable list
  596  * @param fsid          file system identifier of device
  597  * @param fileid        file to add
  598  * @param gen           generation of file
  599  * @param fingerprint   fingerprint to add to the store
  600  * @param flags         flags to set in the store
  601  * @param fp_type       digest type
  602  * @param override      if 1, override any values already stored
  603  *
  604  * @return 0 on success, otherwise an error code.
  605  */
  606 int
  607 mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid,
  608     unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN],
  609     char *label, size_t labellen, int flags, const char *fp_type, int override)
  610 {
  611         struct mac_veriexec_fpops *fpops;
  612         struct veriexec_dev_list *lp;
  613         struct veriexec_devhead *head;
  614         struct mac_veriexec_file_info *ip;
  615         struct mac_veriexec_file_info *np = NULL;
  616 
  617         /* Label and labellen must be set if VERIEXEC_LABEL is set */
  618         if ((flags & VERIEXEC_LABEL) != 0 && (label == NULL || labellen == 0))
  619                 return (EINVAL);
  620 
  621         /* Look up the device entry */
  622         if (file_dev)
  623                 head = &veriexec_file_dev_head;
  624         else
  625                 head = &veriexec_dev_head;
  626         lp = find_veriexec_dev(fsid, head);
  627 
  628         /* Look up the fingerprint operations for the digest type */
  629         fpops = mac_veriexec_fingerprint_lookup_ops(fp_type);
  630         if (fpops == NULL)
  631                 return (EOPNOTSUPP);
  632 
  633 search:
  634         for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL;
  635              ip = LIST_NEXT(ip, entries)) {
  636                   /* check for a dupe file in the list, skip if an entry
  637                    * exists for this file except for when the flags contains
  638                    * VERIEXEC_INDIRECT, always set the flags when it is so
  639                    * we don't get a hole caused by conflicting flags on
  640                    * hardlinked files.  XXX maybe we should validate
  641                    * fingerprint is same and complain if it is not...
  642                    */
  643                 if (ip->fileid == fileid && ip->gen == gen) {
  644                         if (override) {
  645                                 /*
  646                                  * for a signed load we allow overrides,
  647                                  * otherwise fingerpints needed for pkg loads
  648                                  * can fail (the files are on temp device).
  649                                  */
  650                                 ip->flags = flags;
  651                                 ip->ops = fpops;
  652                                 memcpy(ip->fingerprint, fingerprint,
  653                                     fpops->digest_len);
  654                                 if (flags & VERIEXEC_LABEL) {
  655                                         ip->labellen = mac_veriexec_init_label(
  656                                             &ip->label, ip->labellen, label,
  657                                             labellen);
  658                                 } else if (ip->labellen > 0) {
  659                                         free(ip->label, M_VERIEXEC);
  660                                         ip->labellen = 0;
  661                                         ip->label = NULL;
  662                                 }
  663                         } else if ((flags & (VERIEXEC_INDIRECT|VERIEXEC_FILE)))
  664                                 ip->flags |= flags;
  665 
  666                         if (np) {
  667                                 /* unlikely but... we don't need it now. */
  668                                 mtx_unlock(&ve_mutex);
  669                                 free(np, M_VERIEXEC);
  670                                 mtx_lock(&ve_mutex);
  671                         }
  672                         return (0);
  673                 }
  674         }
  675 
  676         /*
  677          * We may have been past here before...
  678          */
  679         if (np == NULL) {
  680                 /*
  681                  * We first try with mutex held and nowait.
  682                  */
  683                 np = malloc(sizeof(struct mac_veriexec_file_info), M_VERIEXEC,
  684                     M_NOWAIT);
  685                 if (np == NULL) {
  686                         /*
  687                          * It was worth a try, now
  688                          * drop mutex while we malloc.
  689                          */
  690                         mtx_unlock(&ve_mutex);
  691                         np = malloc(sizeof(struct mac_veriexec_file_info),
  692                             M_VERIEXEC, M_WAITOK);
  693                         mtx_lock(&ve_mutex);
  694                         /*
  695                          * We now have to repeat our search!
  696                          */
  697                         goto search;
  698                 }
  699         }
  700 
  701         /* Set up the meta-data entry */
  702         ip = np;
  703         ip->flags = flags;
  704         ip->ops = fpops;
  705         ip->fileid = fileid;
  706         ip->gen = gen;
  707         memcpy(ip->fingerprint, fingerprint, fpops->digest_len);
  708         if (flags & VERIEXEC_LABEL)
  709                 ip->labellen = mac_veriexec_init_label(&ip->label,
  710                     ip->labellen, label, labellen);
  711         else {
  712                 ip->label = NULL;
  713                 ip->labellen = 0;
  714         }
  715 
  716         VERIEXEC_DEBUG(3, ("add file %ju.%lu (files=%d)\n",
  717             (uintmax_t)ip->fileid,
  718             ip->gen, file_dev));
  719 
  720         /* Add the entry to the list */
  721         LIST_INSERT_HEAD(&(lp->file_head), ip, entries);
  722 #ifdef DEBUG_VERIEXEC_FINGERPRINT
  723         {
  724                 off_t offset;
  725 
  726                 printf("Stored %s fingerprint:\n", fp_type);
  727                 for (offset = 0; offset < fpops->digest_len; offset++)
  728                         printf("%02x", fingerprint[offset]);
  729                 printf("\n");
  730         }
  731 #endif
  732         return (0);
  733 }
  734 
  735 /**
  736  * @brief Search the meta-data store for information on the specified file.
  737  *
  738  * @param fsid          file system identifier to look for
  739  * @param fileid        file to look for
  740  * @param gen           generation of file
  741  * @param found_dev     indicator that an entry for the file system was found
  742  * @param check_files   if 1, check the files list first, otherwise check the
  743  *                      exectuables list first
  744  *
  745  * @return A pointer to the meta-data inforation if meta-data exists for
  746  *     the specified file identifier, otherwise @c NULL
  747  */
  748 struct mac_veriexec_file_info *
  749 mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, unsigned long gen,
  750     int *found_dev, int check_files)
  751 {
  752         struct veriexec_devhead *search[3];
  753         struct mac_veriexec_file_info *ip;
  754         int x;
  755 
  756         /* Determine the order of the lists to search */
  757         if (check_files) {
  758                 search[0] = &veriexec_file_dev_head;
  759                 search[1] = &veriexec_dev_head;
  760         } else {
  761                 search[0] = &veriexec_dev_head;
  762                 search[1] = &veriexec_file_dev_head;
  763         }
  764         search[2] = NULL;
  765 
  766         VERIEXEC_DEBUG(3, ("%s: searching for dev %ju, file %lu\n",
  767             __func__, (uintmax_t)fsid, fileid));
  768 
  769         /* Search for the specified file */
  770         for (ip = NULL, x = 0; ip == NULL && search[x]; x++)
  771                 ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev);
  772 
  773         return (ip);
  774 }
  775 
  776 /**
  777  * @brief Intialize the meta-data store
  778  */
  779 void
  780 mac_veriexec_metadata_init(void)
  781 {
  782 
  783         mtx_init(&ve_mutex, "veriexec lock", NULL, MTX_DEF);
  784         LIST_INIT(&veriexec_dev_head);
  785         LIST_INIT(&veriexec_file_dev_head);
  786 }

Cache object: cf9beaf2fb3d352f81a436d5cee1efea


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