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/dev/verified_exec.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: verified_exec.c,v 1.5.2.16 2005/08/16 12:43:17 tron Exp $      */
    2 
    3 /*-
    4  * Copyright 2005 Elad Efrat <elad@bsd.org.il>
    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 #if defined(__NetBSD__)
   34 __KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.5.2.16 2005/08/16 12:43:17 tron Exp $");
   35 #else
   36 __RCSID("$Id: verified_exec.c,v 1.5.2.16 2005/08/16 12:43:17 tron Exp $\n$NetBSD: verified_exec.c,v 1.5.2.16 2005/08/16 12:43:17 tron Exp $");
   37 #endif
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/proc.h>
   42 #include <sys/errno.h>
   43 #include <sys/buf.h>
   44 #include <sys/malloc.h>
   45 
   46 #ifdef __FreeBSD__
   47 #include <sys/kernel.h>
   48 #include <sys/device_port.h>
   49 #include <sys/ioccom.h>
   50 #else
   51 #include <sys/ioctl.h>
   52 #include <sys/device.h>
   53 #define DEVPORT_DEVICE struct device
   54 #endif
   55 
   56 #include <sys/conf.h>
   57 #include <sys/lock.h>
   58 #include <sys/queue.h>
   59 #include <sys/vnode.h>
   60 #include <sys/fcntl.h>
   61 #include <sys/namei.h>
   62 #include <sys/sysctl.h>
   63 #define VERIEXEC_NEED_NODE
   64 #include <sys/verified_exec.h>
   65 
   66 /* count of number of times device is open (we really only allow one open) */
   67 static unsigned int veriexec_dev_usage;
   68 
   69 struct veriexec_softc {
   70         DEVPORT_DEVICE veriexec_dev;
   71 };
   72 
   73 #if defined(__FreeBSD__)
   74 # define CDEV_MAJOR 216
   75 # define BDEV_MAJOR -1
   76 #endif
   77 
   78 const struct cdevsw veriexec_cdevsw = {
   79         veriexecopen,
   80         veriexecclose,
   81         noread,
   82         nowrite,
   83         veriexecioctl,
   84 #ifdef __NetBSD__
   85         nostop,
   86         notty,
   87 #endif
   88         nopoll,
   89         nommap,
   90 #if defined(__NetBSD__)
   91        nokqfilter,
   92 #elif defined(__FreeBSD__)
   93        nostrategy,
   94        "veriexec",
   95        CDEV_MAJOR,
   96        nodump,
   97        nopsize,
   98        0,                              /* flags */
   99        BDEV_MAJOR
  100 #endif
  101 };
  102 
  103 /* Autoconfiguration glue */
  104 void    veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
  105                         void *aux);
  106 int     veriexecopen(dev_t dev, int flags, int fmt, struct proc *p);
  107 int     veriexecclose(dev_t dev, int flags, int fmt, struct proc *p);
  108 int     veriexecioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
  109                        struct proc *p);
  110 
  111 void
  112 veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
  113                    void *aux)
  114 {
  115         veriexec_dev_usage = 0;
  116 
  117         if (veriexec_verbose >= 2)
  118                 printf("Veriexec: veriexecattach: Veriexec pseudo-device"
  119                        "attached.\n");
  120 }
  121 
  122 int
  123 veriexecopen(dev_t dev __unused, int flags __unused,
  124                  int fmt __unused, struct proc *p __unused)
  125 {
  126         if (veriexec_verbose >= 2) {
  127                 printf("Veriexec: veriexecopen: Veriexec load device "
  128                        "open attempt by uid=%u, pid=%u. (dev=%u)\n",
  129                        p->p_ucred->cr_uid, p->p_pid, dev);
  130         }
  131 
  132         if (suser(p->p_ucred, &p->p_acflag) != 0)
  133                 return (EPERM);
  134 
  135         if (veriexec_dev_usage > 0) {
  136                 if (veriexec_verbose >= 2)
  137                         printf("Veriexec: load device already in use.\n");
  138 
  139                 return(EBUSY);
  140         }
  141 
  142         veriexec_dev_usage++;
  143         return (0);
  144 }
  145 
  146 int
  147 veriexecclose(dev_t dev __unused, int flags __unused,
  148                   int fmt __unused, struct proc *p __unused)
  149 {
  150         if (veriexec_dev_usage > 0)
  151                 veriexec_dev_usage--;
  152         return (0);
  153 }
  154 
  155 int
  156 veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
  157                   int flags __unused, struct proc *p)
  158 {
  159         struct veriexec_hashtbl *tbl;
  160         struct nameidata nid;
  161         struct vattr va;
  162         int error = 0;
  163         u_long hashmask;
  164 
  165         if (veriexec_strict > 0) {
  166                 printf("Veriexec: veriexecioctl: Strict mode, modifying "
  167                        "veriexec tables is not permitted.\n"); 
  168 
  169                 return (EPERM);
  170         }
  171         
  172         switch (cmd) {
  173         case VERIEXEC_TABLESIZE: {
  174                 struct veriexec_sizing_params *params =
  175                         (struct veriexec_sizing_params *) data;
  176                 u_char node_name[16];
  177 
  178                 /* Check for existing table for device. */
  179                 if (veriexec_tblfind(params->dev) != NULL)
  180                         return (EEXIST);
  181 
  182                 /* Allocate and initialize a Veriexec hash table. */
  183                 tbl = malloc(sizeof(struct veriexec_hashtbl), M_TEMP,
  184                              M_WAITOK);
  185                 tbl->hash_size = params->hash_size;
  186                 tbl->hash_dev = params->dev;
  187                 tbl->hash_tbl = hashinit(params->hash_size, HASH_LIST, M_TEMP,
  188                                          M_WAITOK, &hashmask);
  189                 tbl->hash_count = 0;
  190 
  191                 LIST_INSERT_HEAD(&veriexec_tables, tbl, hash_list);
  192 
  193                 snprintf(node_name, sizeof(node_name), "dev_%u",
  194                          tbl->hash_dev);
  195 
  196                 sysctl_createv(NULL, 0, &veriexec_count_node, NULL,
  197                                CTLFLAG_READONLY, CTLTYPE_QUAD, node_name,
  198                                NULL, NULL, 0, &tbl->hash_count, 0,
  199                                tbl->hash_dev, CTL_EOL);
  200 
  201                 break;
  202                 }
  203 
  204         case VERIEXEC_LOAD: {
  205                 struct veriexec_params *params =
  206                         (struct veriexec_params *) data;
  207                 struct veriexec_hash_entry *hh;
  208                 struct veriexec_hash_entry *e;
  209 
  210                 NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, params->file, p);
  211                 error = namei(&nid);
  212                 if (error)
  213                         return (error);
  214 
  215                 /* Add only regular files. */
  216                 if (nid.ni_vp->v_type != VREG) {
  217                         printf("Veriexec: veriexecioctl: Not adding \"%s\": "
  218                             "Not a regular file.\n", params->file);
  219                         vrele(nid.ni_vp);
  220                         return (EINVAL);
  221                 }
  222 
  223                 /* Get attributes for device and inode. */
  224                 error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p);
  225                 if (error)
  226                         return (error);
  227 
  228                 /* Release our reference to the vnode. (namei) */
  229                 vrele(nid.ni_vp);
  230 
  231                 /* Get table for the device. */
  232                 /*
  233                  * XXX: va_fsid is long (32/64 bits) and veriexec_tblfind()
  234                  * XXX: is passed a dev_t - uint32_t.
  235                  */
  236                 tbl = veriexec_tblfind((dev_t)va.va_fsid);
  237                 if (tbl == NULL) {
  238                         return (EINVAL);
  239                 }
  240 
  241                 /*
  242                  * XXX: Both va_fsid and va_fileid are long (32/64 bits), while
  243                  * XXX: veriexec_lookup() is passed dev_t and ino_t - uint32_t.
  244                  */
  245                 hh = veriexec_lookup((dev_t)va.va_fsid, (ino_t)va.va_fileid);
  246                 if (hh != NULL) {
  247                         /*
  248                          * Duplicate entry means something is wrong in
  249                          * the signature file. Just give collision info
  250                          * and return.
  251                          */
  252                         printf("veriexec: Duplicate entry. [%s, %ld:%ld] "
  253                                "old[type=0x%02x, algorithm=%s], "
  254                                "new[type=0x%02x, algorithm=%s] "
  255                                "(%s fingerprint)\n",
  256                                params->file, va.va_fsid, va.va_fileid,
  257                                hh->type, hh->ops->type,
  258                                params->type, params->fp_type,
  259                                (((hh->ops->hash_len != params->size) ||
  260                                 (memcmp(hh->fp, params->fingerprint,
  261                                         min(hh->ops->hash_len, params->size))
  262                                         != 0)) ? "different" : "same"));
  263 
  264                         return (0);
  265                 }
  266 
  267                 e = malloc(sizeof(*e), M_TEMP, M_WAITOK);
  268                 /* XXX: va_fileid is long (32/64 bits), ino_t is uint32_t. */
  269                 e->inode = (ino_t)va.va_fileid;
  270                 e->type = params->type;
  271                 e->status = FINGERPRINT_NOTEVAL;
  272                 if ((e->ops = veriexec_find_ops(params->fp_type)) == NULL) {
  273                         free(e, M_TEMP);
  274                         printf("Veriexec: veriexecioctl: Invalid or unknown "
  275                                "fingerprint type \"%s\" for file \"%s\" "
  276                                "(dev=%ld, inode=%ld)\n", params->fp_type,
  277                                params->file, va.va_fsid, va.va_fileid);
  278                         return(EINVAL);
  279                 }
  280 
  281                 /*
  282                  * Just a bit of a sanity check - require the size of
  283                  * the fp to be passed in, check this against the expected
  284                  * size.  Of course userland could lie deliberately, this
  285                  * really only protects against the obvious fumble of
  286                  * changing the fp type but not updating the fingerprint
  287                  * string.
  288                  */
  289                 if (e->ops->hash_len != params->size) {
  290                         printf("Veriexec: veriexecioctl: Inconsistent "
  291                                "fingerprint size for type \"%s\" for file "
  292                                "\"%s\" (dev=%ld, inode=%ld), size was %u "
  293                                "was expecting %zu\n", params->fp_type,
  294                                params->file, va.va_fsid, va.va_fileid,
  295                                params->size, e->ops->hash_len);
  296                         free(e, M_TEMP);
  297                         return(EINVAL);
  298                 }
  299                         
  300                 e->fp = malloc(e->ops->hash_len, M_TEMP, M_WAITOK);
  301                 memcpy(e->fp, params->fingerprint, e->ops->hash_len);
  302 
  303                 veriexec_report("New entry.", params->file, &va, NULL,
  304                                 REPORT_VERBOSE_HIGH, REPORT_NOALARM,
  305                                 REPORT_NOPANIC);
  306 
  307                 error = veriexec_hashadd(tbl, e);
  308 
  309                 break;
  310                 }
  311 
  312         default:
  313                 /* Invalid operation. */
  314                 error = ENODEV;
  315 
  316                 break;
  317         }
  318 
  319         return (error);
  320 }
  321 
  322 #if defined(__FreeBSD__)
  323 static void
  324 veriexec_drvinit(void *unused __unused)
  325 {
  326         make_dev(&verifiedexec_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
  327                  "veriexec");
  328         verifiedexecattach(0, 0, 0);
  329 }
  330 
  331 SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL);
  332 #endif

Cache object: 23fdbf326cb74f14e58603685bdbdc79


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