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/mac_veriexec.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  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 
   31 #include "opt_capsicum.h"
   32 #include "opt_mac.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/capsicum.h>
   37 #include <sys/eventhandler.h>
   38 #include <sys/fcntl.h>
   39 #include <sys/file.h>
   40 #include <sys/filedesc.h>
   41 #include <sys/imgact.h>
   42 #include <sys/jail.h>
   43 #include <sys/kernel.h>
   44 #include <sys/mac.h>
   45 #include <sys/mount.h>
   46 #include <sys/namei.h>
   47 #include <sys/priv.h>
   48 #include <sys/proc.h>
   49 #include <sys/sbuf.h>
   50 #include <sys/stat.h>
   51 #include <sys/sysctl.h>
   52 #include <sys/vnode.h>
   53 #include <fs/nullfs/null.h>
   54 #include <security/mac/mac_policy.h>
   55 
   56 #include "mac_veriexec.h"
   57 #include "mac_veriexec_internal.h"
   58 
   59 #define SLOT(l) \
   60         mac_label_get((l), mac_veriexec_slot)
   61 #define SLOT_SET(l, v) \
   62         mac_label_set((l), mac_veriexec_slot, (v))
   63 
   64 #ifdef MAC_DEBUG
   65 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...)                               \
   66         do {                                                            \
   67                 VERIEXEC_DEBUG((_lvl), (MAC_VERIEXEC_FULLNAME ": " _fmt \
   68                      "\n", ##__VA_ARGS__));                             \
   69         } while(0)
   70 #else
   71 #define MAC_VERIEXEC_DBG(_lvl, _fmt, ...)
   72 #endif
   73 
   74 static int sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS);
   75 static int sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS);
   76 
   77 SYSCTL_DECL(_security_mac);
   78 
   79 SYSCTL_NODE(_security_mac, OID_AUTO, veriexec, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   80     "MAC/veriexec policy controls");
   81 
   82 int     mac_veriexec_debug;
   83 SYSCTL_INT(_security_mac_veriexec, OID_AUTO, debug, CTLFLAG_RW,
   84     &mac_veriexec_debug, 0, "Debug level");
   85 
   86 static int      mac_veriexec_state;
   87 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, state,
   88     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
   89     0, 0, sysctl_mac_veriexec_state, "A",
   90     "Verified execution subsystem state");
   91 
   92 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, db,
   93     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT,
   94     0, 0, sysctl_mac_veriexec_db,
   95     "A", "Verified execution fingerprint database");
   96 
   97 static int mac_veriexec_slot;
   98 
   99 MALLOC_DEFINE(M_VERIEXEC, "veriexec", "Verified execution data");
  100 
  101 /**
  102  * @internal
  103  * @brief Handler for security.mac.veriexec.db sysctl
  104  *
  105  * Display a human-readable form of the current fingerprint database.
  106  */
  107 static int
  108 sysctl_mac_veriexec_db(SYSCTL_HANDLER_ARGS)
  109 {
  110         struct sbuf sb;
  111         int error;
  112 
  113         error = sysctl_wire_old_buffer(req, 0);
  114         if (error != 0)
  115                 return (error);
  116 
  117         sbuf_new_for_sysctl(&sb, NULL, 1024, req);
  118         mac_veriexec_metadata_print_db(&sb);
  119         error = sbuf_finish(&sb);
  120         sbuf_delete(&sb);
  121 
  122         return (error);
  123 }
  124 
  125 /**
  126  * @internal
  127  * @brief Generate human-readable output about the current verified execution
  128  *        state.
  129  *
  130  * @param sbp           sbuf to write output to
  131  */
  132 static void
  133 mac_veriexec_print_state(struct sbuf *sbp)
  134 {
  135 
  136         if (mac_veriexec_state & VERIEXEC_STATE_INACTIVE)
  137                 sbuf_printf(sbp, "inactive ");
  138         if (mac_veriexec_state & VERIEXEC_STATE_LOADED)
  139                 sbuf_printf(sbp, "loaded ");
  140         if (mac_veriexec_state & VERIEXEC_STATE_ACTIVE)
  141                 sbuf_printf(sbp, "active ");
  142         if (mac_veriexec_state & VERIEXEC_STATE_ENFORCE)
  143                 sbuf_printf(sbp, "enforce ");
  144         if (mac_veriexec_state & VERIEXEC_STATE_LOCKED)
  145                 sbuf_printf(sbp, "locked ");
  146         if (mac_veriexec_state != 0)
  147                 sbuf_trim(sbp);
  148 }
  149 
  150 /**
  151  * @internal
  152  * @brief Handler for security.mac.veriexec.state sysctl
  153  *
  154  * Display a human-readable form of the current verified execution subsystem
  155  * state.
  156  */
  157 static int
  158 sysctl_mac_veriexec_state(SYSCTL_HANDLER_ARGS)
  159 {
  160         struct sbuf sb;
  161         int error;
  162 
  163         sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
  164         mac_veriexec_print_state(&sb);
  165         sbuf_finish(&sb);
  166 
  167         error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
  168         sbuf_delete(&sb);
  169         return (error);
  170 }
  171 
  172 /**
  173  * @internal
  174  * @brief Event handler called when a virtual file system is mounted.
  175  *
  176  * We need to record the file system identifier in the MAC per-policy slot
  177  * assigned to veriexec, so we have a key to use in order to reference the
  178  * mount point in the meta-data store.
  179  *
  180  * @param arg           unused argument
  181  * @param mp            mount point that is being mounted
  182  * @param fsrootvp      vnode of the file system root
  183  * @param td            calling thread
  184  */
  185 static void
  186 mac_veriexec_vfs_mounted(void *arg __unused, struct mount *mp,
  187     struct vnode *fsrootvp, struct thread *td)
  188 {
  189         struct vattr va;
  190         int error;
  191 
  192         error = VOP_GETATTR(fsrootvp, &va, td->td_ucred);
  193         if (error)
  194                 return;
  195 
  196         SLOT_SET(mp->mnt_label, va.va_fsid);
  197 #ifdef MAC_DEBUG
  198         MAC_VERIEXEC_DBG(3, "set fsid to %ju for mount %p",
  199             (uintmax_t)va.va_fsid, mp);
  200 #endif
  201 }
  202 
  203 /**
  204  * @internal
  205  * @brief Event handler called when a virtual file system is unmounted.
  206  *
  207  * If we recorded a file system identifier in the MAC per-policy slot assigned
  208  * to veriexec, then we need to tell the meta-data store to clean up.
  209  *
  210  * @param arg           unused argument
  211  * @param mp            mount point that is being unmounted
  212  * @param td            calling thread
  213  */
  214 static void
  215 mac_veriexec_vfs_unmounted(void *arg __unused, struct mount *mp,
  216     struct thread *td)
  217 {
  218         dev_t fsid;
  219 
  220         fsid = SLOT(mp->mnt_label);
  221         if (fsid) {
  222                 MAC_VERIEXEC_DBG(3, "fsid %ju, cleaning up mount",
  223                     (uintmax_t)fsid);
  224                 mac_veriexec_metadata_unmounted(fsid, td);
  225         }
  226 }
  227 
  228 /**
  229  * @internal
  230  * @brief The mount point is being initialized, set the value in the MAC
  231  *     per-policy slot for veriexec to zero.
  232  *
  233  * @note A value of zero in this slot indicates no file system identifier
  234  *     is assigned.
  235  *
  236  * @param label the label that is being initialized
  237  */
  238 static void 
  239 mac_veriexec_mount_init_label(struct label *label) 
  240 {
  241 
  242         SLOT_SET(label, 0);
  243 }
  244 
  245 /**
  246  * @internal
  247  * @brief The mount-point is being destroyed, reset the value in the MAC
  248  *     per-policy slot for veriexec back to zero.
  249  *
  250  * @note A value of zero in this slot indicates no file system identifier
  251  *     is assigned.
  252  *
  253  * @param label the label that is being destroyed
  254  */
  255 static void 
  256 mac_veriexec_mount_destroy_label(struct label *label) 
  257 {
  258 
  259         SLOT_SET(label, 0);
  260 }
  261 
  262 /**
  263  * @internal
  264  * @brief The vnode label is being initialized, set the value in the MAC
  265  *     per-policy slot for veriexec to @c FINGERPRINT_INVALID
  266  *
  267  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
  268  *
  269  * @param label         the label that is being initialized
  270  */
  271 static void
  272 mac_veriexec_vnode_init_label(struct label *label)
  273 {
  274 
  275         SLOT_SET(label, FINGERPRINT_INVALID);
  276 }
  277 
  278 /**
  279  * @internal
  280  * @brief The vnode label is being destroyed, reset the value in the MAC
  281  *        per-policy slot for veriexec back to @c FINGERPRINT_INVALID
  282  *
  283  * @note @c FINGERPRINT_INVALID indicates the fingerprint is invalid.
  284  *
  285  * @param label         the label that is being destroyed
  286  */
  287 static void
  288 mac_veriexec_vnode_destroy_label(struct label *label)
  289 {
  290 
  291         SLOT_SET(label, FINGERPRINT_INVALID);
  292 }
  293 
  294 /**
  295  * @internal
  296  * @brief Copy the value in the MAC per-policy slot assigned to veriexec from
  297  *        the @p src label to the @p dest label
  298  */
  299 static void 
  300 mac_veriexec_copy_label(struct label *src, struct label *dest)
  301 {
  302 
  303         SLOT_SET(dest, SLOT(src));
  304 }
  305 
  306 /**
  307  * @internal
  308  * @brief Check if the requested process can be debugged
  309  *
  310  * @param cred          credentials to use
  311  * @param p             process to debug
  312  *
  313  * @return 0 if debugging is allowed, otherwise an error code.
  314  */
  315 static int
  316 mac_veriexec_proc_check_debug(struct ucred *cred, struct proc *p)
  317 {
  318         int error, flags;
  319 
  320         /* If we are not enforcing veriexec, nothing for us to check */
  321         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
  322                 return (0);
  323 
  324         error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
  325         if (error != 0)
  326                 return (0);
  327 
  328         return ((flags & VERIEXEC_NOTRACE) ? EACCES : 0);
  329 }
  330 
  331 /**
  332  * @internal
  333  * @brief A KLD load has been requested and needs to be validated.
  334  *
  335  * @param cred          credentials to use
  336  * @param vp            vnode of the KLD that has been requested
  337  * @param vlabel        vnode label assigned to the vnode
  338  *
  339  * @return 0 if the KLD load is allowed, otherwise an error code.
  340  */
  341 static int
  342 mac_veriexec_kld_check_load(struct ucred *cred, struct vnode *vp,
  343     struct label *vlabel)
  344 {
  345         struct vattr va;
  346         struct thread *td = curthread;
  347         fingerprint_status_t status;
  348         int error;
  349 
  350         /*
  351          * If we are not actively enforcing, allow it
  352          */
  353         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
  354                 return (0);
  355 
  356         /* Get vnode attributes */
  357         error = VOP_GETATTR(vp, &va, cred);
  358         if (error)
  359                 return (error);
  360 
  361         /*
  362          * Fetch the fingerprint status for the vnode
  363          * (starting with files first)
  364          */
  365         error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
  366             VERIEXEC_FILES_FIRST);
  367         if (error && error != EAUTH)
  368                 return (error);
  369 
  370         /*
  371          * By now we should have status...
  372          */
  373         status = mac_veriexec_get_fingerprint_status(vp);
  374         switch (status) {
  375         case FINGERPRINT_FILE:
  376         case FINGERPRINT_VALID:
  377         case FINGERPRINT_INDIRECT:
  378                 if (error)
  379                         return (error);
  380                 break;
  381         default:
  382                 /*
  383                  * kldload should fail unless there is a valid fingerprint
  384                  * registered.
  385                  */
  386                 MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev %ju, "
  387                     "file %ju.%ju\n", status, (uintmax_t)va.va_fsid,
  388                     (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
  389                 return (EAUTH);
  390         }
  391 
  392         /* Everything is good, allow the KLD to be loaded */
  393         return (0);
  394 }
  395 
  396 /**
  397  * @internal
  398  * @brief Check privileges that veriexec needs to be concerned about.
  399  *
  400  * The following privileges are checked by this function:
  401  *  - PRIV_KMEM_WRITE\n
  402  *    Check if writes to /dev/mem and /dev/kmem are allowed\n
  403  *    (Only trusted processes are allowed)
  404  *
  405  * @param cred          credentials to use
  406  * @param priv          privilege to check
  407  *
  408  * @return 0 if the privilege is allowed, error code otherwise.
  409  */
  410 static int
  411 mac_veriexec_priv_check(struct ucred *cred, int priv)
  412 {
  413 
  414         /* If we are not enforcing veriexec, nothing for us to check */
  415         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
  416                 return (0);
  417 
  418         switch (priv) {
  419         case PRIV_KMEM_WRITE:
  420                 if (!mac_veriexec_proc_is_trusted(cred, curproc))
  421                         return (EPERM);
  422                 break;
  423         default:
  424                 break;
  425         }
  426         return (0);
  427 }
  428 
  429 static int
  430 mac_veriexec_sysctl_check(struct ucred *cred, struct sysctl_oid *oidp,
  431     void *arg1, int arg2, struct sysctl_req *req)
  432 {
  433         struct sysctl_oid *oid;
  434 
  435         /* If we are not enforcing veriexec, nothing for us to check */
  436         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
  437                 return (0);
  438 
  439         oid = oidp;
  440         if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
  441                 return (EPERM);         /* XXX call mac_veriexec_priv_check? */
  442         }
  443         return 0;
  444 }
  445 
  446 /**
  447  * @internal
  448  * @brief A program is being executed and needs to be validated.
  449  *
  450  * @param cred          credentials to use
  451  * @param vp            vnode of the program that is being executed
  452  * @param label         vnode label assigned to the vnode
  453  * @param imgp          parameters for the image to be executed
  454  * @param execlabel     optional exec label
  455  *
  456  * @return 0 if the program should be allowed to execute, otherwise an error
  457  *     code.
  458  */
  459 static int
  460 mac_veriexec_vnode_check_exec(struct ucred *cred __unused,
  461     struct vnode *vp __unused, struct label *label __unused,
  462     struct image_params *imgp, struct label *execlabel __unused)
  463 {
  464         struct thread *td = curthread;
  465         int error;
  466 
  467         error = mac_veriexec_fingerprint_check_image(imgp, 0, td);
  468         return (error);
  469 }
  470 
  471 /**
  472  * @brief Check fingerprint for the specified vnode and validate it
  473  *
  474  * @param cred          credentials to use
  475  * @param vp            vnode of the file
  476  * @param accmode       access mode to check (read, write, append, create,
  477  *                      verify, etc.)
  478  *
  479  * @return 0 if the file validated, otherwise an error code.
  480  */
  481 static int
  482 mac_veriexec_check_vp(struct ucred *cred, struct vnode *vp, accmode_t accmode)
  483 {
  484         struct vattr va;
  485         struct thread *td = curthread;
  486         fingerprint_status_t status;
  487         int error;
  488 
  489         /* Get vnode attributes */
  490         error = VOP_GETATTR(vp, &va, cred);
  491         if (error)
  492                 return (error);
  493 
  494         /* Get the fingerprint status for the file */
  495         error = mac_veriexec_metadata_fetch_fingerprint_status(vp, &va, td,
  496             VERIEXEC_FILES_FIRST);
  497         if (error && error != EAUTH)
  498                 return (error);
  499 
  500         /*
  501          * By now we should have status...
  502          */
  503         status = mac_veriexec_get_fingerprint_status(vp);
  504         if (accmode & VWRITE) {
  505                 /*
  506                  * If file has a fingerprint then deny the write request,
  507                  * otherwise invalidate the status so we don't keep checking
  508                  * for the file having a fingerprint. 
  509                  */
  510                 switch (status) {
  511                 case FINGERPRINT_FILE:
  512                 case FINGERPRINT_VALID:
  513                 case FINGERPRINT_INDIRECT:
  514                         MAC_VERIEXEC_DBG(2,
  515                             "attempted write to fingerprinted file for dev "
  516                             "%ju, file %ju.%ju\n", (uintmax_t)va.va_fsid,
  517                             (uintmax_t)va.va_fileid, (uintmax_t)va.va_gen);
  518                         return (EPERM);
  519                 default:
  520                         break;
  521                 }
  522         }
  523         if (accmode & VVERIFY) {
  524                 switch (status) {
  525                 case FINGERPRINT_FILE:
  526                 case FINGERPRINT_VALID:
  527                 case FINGERPRINT_INDIRECT:
  528                         if (error)
  529                                 return (error);
  530                         break;
  531                 default:
  532                         /*
  533                          * Caller wants open to fail unless there is a valid
  534                          * fingerprint registered. 
  535                          */
  536                         MAC_VERIEXEC_DBG(2, "fingerprint status is %d for dev "
  537                             "%ju, file %ju.%ju\n", status,
  538                             (uintmax_t)va.va_fsid, (uintmax_t)va.va_fileid,
  539                             (uintmax_t)va.va_gen);
  540                         return (EAUTH);
  541                 }
  542         }
  543         return (0);
  544 }
  545 
  546 /**
  547  * @brief Opening a file has been requested and may need to be validated.
  548  *
  549  * @param cred          credentials to use
  550  * @param vp            vnode of the file to open
  551  * @param label         vnode label assigned to the vnode
  552  * @param accmode       access mode to use for opening the file (read, write,
  553  *                      append, create, verify, etc.)
  554  *
  555  * @return 0 if opening the file should be allowed, otherwise an error code.
  556  */
  557 static int
  558 mac_veriexec_vnode_check_open(struct ucred *cred, struct vnode *vp,
  559         struct label *label __unused, accmode_t accmode)
  560 {
  561         int error;
  562 
  563         /*
  564          * Look for the file on the fingerprint lists iff it has not been seen
  565          * before.
  566          */
  567         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
  568                 return (0);
  569 
  570         error = mac_veriexec_check_vp(cred, vp, accmode);
  571         return (error);
  572 }
  573 
  574 /**
  575  * @brief Check mode changes on file to ensure they should be allowed.
  576  *
  577  * We cannot allow chmod of SUID or SGID on verified files.
  578  *
  579  * @param cred          credentials to use
  580  * @param vp            vnode of the file to open
  581  * @param label         vnode label assigned to the vnode
  582  * @param mode          mode flags to set
  583  *
  584  * @return 0 if the mode change should be allowed, EAUTH otherwise.
  585  */
  586 static int
  587 mac_veriexec_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
  588     struct label *label __unused, mode_t mode)
  589 {
  590         int error;
  591 
  592         if ((mac_veriexec_state & VERIEXEC_STATE_ENFORCE) == 0)
  593                 return (0);
  594 
  595         /*
  596          * Do not allow chmod (set-[gu]id) of verified file
  597          */
  598         error = mac_veriexec_check_vp(cred, vp, VVERIFY);
  599         if (error == EAUTH)             /* it isn't verified */
  600                 return (0);
  601         if (error == 0 && (mode & (S_ISUID|S_ISGID)) != 0)
  602                 return (EAUTH);
  603         return (0);
  604 }
  605 
  606 /**
  607  * @internal
  608  * @brief Initialize the mac_veriexec MAC policy
  609  *
  610  * @param mpc           MAC policy configuration
  611  */
  612 static void
  613 mac_veriexec_init(struct mac_policy_conf *mpc __unused)
  614 {
  615         /* Initialize state */
  616         mac_veriexec_state = VERIEXEC_STATE_INACTIVE;
  617 
  618         /* Initialize meta-data storage */
  619         mac_veriexec_metadata_init();
  620 
  621         /* Initialize fingerprint ops */
  622         mac_veriexec_fingerprint_init();
  623 
  624         /* Register event handlers */
  625         EVENTHANDLER_REGISTER(vfs_mounted, mac_veriexec_vfs_mounted, NULL,
  626             EVENTHANDLER_PRI_FIRST);
  627         EVENTHANDLER_REGISTER(vfs_unmounted, mac_veriexec_vfs_unmounted, NULL,
  628             EVENTHANDLER_PRI_LAST);
  629 }
  630 
  631 /**
  632  * @internal
  633  * @brief MAC policy-specific syscall for mac_veriexec
  634  *
  635  * The following syscalls are implemented:
  636  *   - @c MAC_VERIEXEC_CHECK_SYSCALL
  637  *        Check if the file referenced by a file descriptor has a fingerprint
  638  *        registered in the meta-data store.
  639  *
  640  * @param td            calling thread
  641  * @param call          system call number
  642  * @param arg           arugments to the syscall
  643  *
  644  * @return 0 on success, otherwise an error code.
  645  */
  646 static int
  647 mac_veriexec_syscall(struct thread *td, int call, void *arg)
  648 {
  649         struct image_params img;
  650         struct nameidata nd;
  651         cap_rights_t rights;
  652         struct vattr va;
  653         struct file *fp;
  654         int error;
  655 
  656         switch (call) {
  657         case MAC_VERIEXEC_CHECK_FD_SYSCALL:
  658                 /* Get the vnode associated with the file descriptor passed */
  659                 error = getvnode(td, (uintptr_t) arg,
  660                     cap_rights_init_one(&rights, CAP_READ), &fp);
  661                 if (error)
  662                         return (error);
  663                 if (fp->f_type != DTYPE_VNODE) {
  664                         MAC_VERIEXEC_DBG(3, "MAC_VERIEXEC_CHECK_SYSCALL: "
  665                             "file is not vnode type (type=0x%x)",
  666                             fp->f_type);
  667                         error = EINVAL;
  668                         goto cleanup_file;
  669                 }
  670 
  671                 /*
  672                  * setup the bits of image_params that are used by
  673                  * mac_veriexec_check_fingerprint().
  674                  */
  675                 bzero(&img, sizeof(img));
  676                 img.proc = td->td_proc;
  677                 img.vp = fp->f_vnode;
  678                 img.attr = &va;
  679 
  680                 /*
  681                  * Get vnode attributes
  682                  * (need to obtain a lock on the vnode first)
  683                  */
  684                 vn_lock(img.vp, LK_EXCLUSIVE | LK_RETRY);
  685                 error = VOP_GETATTR(fp->f_vnode, &va,  td->td_ucred);
  686                 if (error)
  687                         goto check_done;
  688                        
  689                 MAC_VERIEXEC_DBG(2, "mac_veriexec_fingerprint_check_image: "
  690                     "va_mode=%o, check_files=%d\n", va.va_mode,
  691                     ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0));
  692                 error = mac_veriexec_fingerprint_check_image(&img,
  693                     ((va.va_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0), td);
  694 check_done:
  695                 /* Release the lock we obtained earlier */
  696                 VOP_UNLOCK(img.vp);
  697 cleanup_file:
  698                 fdrop(fp, td);
  699                 break;
  700         case MAC_VERIEXEC_CHECK_PATH_SYSCALL:
  701                 /* Look up the path to get the vnode */
  702                 NDINIT(&nd, LOOKUP,
  703                     FOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1,
  704                     UIO_USERSPACE, arg);
  705                 error = namei(&nd);
  706                 if (error != 0)
  707                         break;
  708                 NDFREE_PNBUF(&nd);
  709 
  710                 /* Check the fingerprint status of the vnode */
  711                 error = mac_veriexec_check_vp(td->td_ucred, nd.ni_vp, VVERIFY);
  712                 vput(nd.ni_vp);
  713                 break;
  714         default:
  715                 error = EOPNOTSUPP;
  716         }
  717         return (error);
  718 }
  719 
  720 static struct mac_policy_ops mac_veriexec_ops =
  721 {
  722         .mpo_init = mac_veriexec_init,
  723         .mpo_kld_check_load = mac_veriexec_kld_check_load,
  724         .mpo_mount_destroy_label = mac_veriexec_mount_destroy_label,
  725         .mpo_mount_init_label = mac_veriexec_mount_init_label,
  726         .mpo_priv_check = mac_veriexec_priv_check,
  727         .mpo_proc_check_debug = mac_veriexec_proc_check_debug,
  728         .mpo_syscall = mac_veriexec_syscall,
  729         .mpo_system_check_sysctl = mac_veriexec_sysctl_check,
  730         .mpo_vnode_check_exec = mac_veriexec_vnode_check_exec,
  731         .mpo_vnode_check_open = mac_veriexec_vnode_check_open,
  732         .mpo_vnode_check_setmode = mac_veriexec_vnode_check_setmode,
  733         .mpo_vnode_copy_label = mac_veriexec_copy_label,
  734         .mpo_vnode_destroy_label = mac_veriexec_vnode_destroy_label,
  735         .mpo_vnode_init_label = mac_veriexec_vnode_init_label,
  736 };
  737 
  738 MAC_POLICY_SET(&mac_veriexec_ops, mac_veriexec, MAC_VERIEXEC_FULLNAME,
  739     MPC_LOADTIME_FLAG_NOTLATE, &mac_veriexec_slot);
  740 MODULE_VERSION(mac_veriexec, MAC_VERIEXEC_VERSION);
  741 
  742 static struct vnode *
  743 mac_veriexec_bottom_vnode(struct vnode *vp)
  744 {
  745         struct vnode *ldvp = NULL;
  746 
  747         /*
  748          * XXX This code is bogus. nullfs is not the only stacking
  749          * filesystem. Less bogus code would add a VOP to reach bottom
  750          * vnode and would not make assumptions how to get there.
  751          */
  752         if (vp->v_mount != NULL &&
  753             strcmp(vp->v_mount->mnt_vfc->vfc_name, "nullfs") == 0)
  754                 ldvp = NULLVPTOLOWERVP(vp);
  755         return (ldvp);
  756 }
  757 
  758 /**
  759  * @brief Get the fingerprint status set on a vnode.
  760  *
  761  * @param vp            vnode to obtain fingerprint status from
  762  *
  763  * @return Fingerprint status assigned to the vnode.
  764  */
  765 fingerprint_status_t
  766 mac_veriexec_get_fingerprint_status(struct vnode *vp)
  767 {
  768         fingerprint_status_t fps;
  769         struct vnode *ldvp;
  770 
  771         fps = SLOT(vp->v_label);
  772         switch (fps) {
  773         case FINGERPRINT_VALID:
  774         case FINGERPRINT_INDIRECT:
  775         case FINGERPRINT_FILE:
  776                 break;
  777         default:
  778                 /* we may need to recurse */
  779                 ldvp = mac_veriexec_bottom_vnode(vp);
  780                 if (ldvp != NULL)
  781                         return mac_veriexec_get_fingerprint_status(ldvp);
  782                 break;
  783         }
  784         return fps;
  785 }
  786 
  787 /**
  788  * @brief Get the current verified execution subsystem state.
  789  *
  790  * @return Current set of verified execution subsystem state flags.
  791  */
  792 int
  793 mac_veriexec_get_state(void)
  794 {
  795 
  796         return (mac_veriexec_state);
  797 }
  798 
  799 /**
  800  * @brief Determine if the verified execution subsystem state has specific
  801  *     flags set.
  802  *
  803  * @param state         mask of flags to check
  804  *
  805  * @return State flags set within the masked bits
  806  */
  807 int
  808 mac_veriexec_in_state(int state)
  809 {
  810 
  811         return (mac_veriexec_state & state);
  812 }
  813 
  814 /**
  815  * @brief Set the fingerprint status for a vnode
  816  *
  817  * Fingerprint status is stored in the MAC per-policy slot assigned to
  818  * mac_veriexec.
  819  *
  820  * @param vp            vnode to store the fingerprint status on
  821  * @param fp_status     fingerprint status to store
  822  */
  823 void
  824 mac_veriexec_set_fingerprint_status(struct vnode *vp,
  825     fingerprint_status_t fp_status)
  826 {
  827         struct vnode *ldvp;
  828 
  829         /* recurse until we find the real storage */
  830         ldvp = mac_veriexec_bottom_vnode(vp);
  831         if (ldvp != NULL) {
  832                 mac_veriexec_set_fingerprint_status(ldvp, fp_status);
  833                 return;
  834         }
  835         SLOT_SET(vp->v_label, fp_status);
  836 }
  837 
  838 /**
  839  * @brief Set verified execution subsystem state flags
  840  *
  841  * @note Flags can only be added to the current state, not removed.
  842  *
  843  * @param state         state flags to add to the current state
  844  */
  845 void
  846 mac_veriexec_set_state(int state)
  847 {
  848 
  849         mac_veriexec_state |= state;
  850 }
  851 
  852 /**
  853  * @brief Determine if the process is trusted
  854  *
  855  * @param cred          credentials to use
  856  * @param p             the process in question
  857  *
  858  * @return 1 if the process is trusted, otherwise 0.
  859  */
  860 int
  861 mac_veriexec_proc_is_trusted(struct ucred *cred, struct proc *p)
  862 {
  863         int already_locked, error, flags;
  864 
  865         /* Make sure we lock the process if we do not already have the lock */
  866         already_locked = PROC_LOCKED(p);
  867         if (!already_locked)
  868                 PROC_LOCK(p);
  869 
  870         error = mac_veriexec_metadata_get_executable_flags(cred, p, &flags, 0);
  871 
  872         /* Unlock the process if we locked it previously */
  873         if (!already_locked)
  874                 PROC_UNLOCK(p);
  875 
  876         /* Any errors, deny access */
  877         if (error != 0)
  878                 return (0);
  879 
  880         /* Check that the trusted flag is set */
  881         return ((flags & VERIEXEC_TRUSTED) == VERIEXEC_TRUSTED);
  882 }

Cache object: fb1490fcb40c5173d931c56c12f6cbbb


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