The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_verifiedexec.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Brett Lymn and Jason R Fink
    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  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $");
   41 
   42 #include <sys/param.h>
   43 #include <sys/mount.h> 
   44 #include <sys/malloc.h>
   45 #include <sys/vnode.h>
   46 #include <sys/exec.h>
   47 #include <sys/md5.h>
   48 #include <sys/sha1.h>
   49 #include <sys/verified_exec.h>
   50 
   51 /* Set the buffer to a single page for md5 and sha1 */
   52 #define BUF_SIZE PAGE_SIZE
   53 
   54 extern LIST_HEAD(veriexec_devhead, veriexec_dev_list) veriexec_dev_head;
   55 
   56 static int
   57 md5_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
   58                 struct proc *p, u_quad_t file_size, char *fingerprint);
   59 
   60 static int
   61 sha1_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
   62                 struct proc *p, u_quad_t file_size, char *fingerprint);
   63 
   64 
   65 /*
   66  * md5_fingerprint:
   67  *   Evaluate the md5 fingerprint of the given file.
   68  *
   69  */
   70 static int
   71 md5_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
   72                 struct proc *p, u_quad_t file_size, char *fingerprint)
   73 {
   74         u_quad_t        j;
   75         MD5_CTX         md5context;
   76         char            *filebuf;
   77         size_t          resid;
   78         int             count, error;
   79         
   80         filebuf = malloc(BUF_SIZE, M_TEMP, M_WAITOK);
   81         MD5Init(&md5context);
   82         
   83         for (j = 0; j < file_size; j+= BUF_SIZE) {
   84                 if ((j + BUF_SIZE) > file_size) {
   85                         count = file_size - j;
   86                 } else
   87                         count = BUF_SIZE;
   88 
   89                 error = vn_rdwr(UIO_READ, vp, filebuf, count, j,
   90                                 UIO_SYSSPACE, 0, p->p_ucred, &resid, p);
   91 
   92                 if (error) {
   93                         free(filebuf, M_TEMP);
   94                         return error;
   95                 }
   96                 
   97                 MD5Update(&md5context, filebuf, (unsigned int) count);
   98 
   99         }
  100 
  101         MD5Final(fingerprint, &md5context);
  102         free(filebuf, M_TEMP);
  103         return 0;
  104 }
  105 
  106 static int
  107 sha1_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
  108                  struct proc *p, u_quad_t file_size, char *fingerprint)
  109 {
  110         u_quad_t        j;
  111         SHA1_CTX        sha1context;
  112         char            *filebuf;
  113         size_t          resid;
  114         int             count, error;
  115 
  116         filebuf = malloc(BUF_SIZE, M_TEMP, M_WAITOK);
  117         SHA1Init(&sha1context);
  118 
  119         for (j = 0; j < file_size; j+= BUF_SIZE) {
  120                 if ((j + BUF_SIZE) > file_size) {
  121                         count = file_size - j;
  122                 } else
  123                         count = BUF_SIZE;
  124 
  125                 error = vn_rdwr(UIO_READ, vp, filebuf, count, j,
  126                                 UIO_SYSSPACE, 0, p->p_ucred, &resid, p);
  127 
  128                 if (error) {
  129                         free(filebuf, M_TEMP);
  130                         return error;
  131                 }
  132 
  133                 SHA1Update(&sha1context, filebuf, (unsigned int) count);
  134 
  135         }
  136 
  137         SHA1Final(fingerprint, &sha1context);
  138         free(filebuf, M_TEMP);
  139         return 0;
  140 }
  141 
  142 /*
  143  * evaluate_fingerprint:
  144  *   Check the fingerprint type for the given file and evaluate the
  145  * fingerprint for that file.  It is assumed that fingerprint has sufficient
  146  * storage to hold the resulting fingerprint string.
  147  *
  148  */
  149 int
  150 evaluate_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
  151                      struct proc *p, u_quad_t file_size, char *fingerprint)
  152 {
  153         int error;
  154         
  155         switch (ip->fp_type) {
  156         case FINGERPRINT_TYPE_MD5:
  157                 error = md5_fingerprint(vp, ip, p, file_size, fingerprint);
  158                 break;
  159 
  160         case FINGERPRINT_TYPE_SHA1:
  161                 error = sha1_fingerprint(vp, ip, p, file_size, fingerprint);
  162                 break;
  163 
  164         default:
  165                 error = EINVAL;
  166                 break;
  167         }
  168 
  169         return error;
  170 }
  171 
  172 /*
  173  * fingerprintcmp:
  174  *    Compare the two given fingerprints to see if they are the same
  175  * Differing fingerprint methods may have differing lengths which
  176  * is handled by this routine.  This function follows the convention
  177  * of other cmp functions and returns 0 if the fingerprints match and
  178  * 1 if they don't.
  179  */
  180 int
  181 fingerprintcmp(struct veriexec_inode_list *ip, unsigned char *digest)
  182 {
  183         switch(ip->fp_type) {
  184         case FINGERPRINT_TYPE_MD5:
  185                 return memcmp(ip->fingerprint, digest, MD5_FINGERPRINTLEN);
  186                 break;
  187 
  188         case FINGERPRINT_TYPE_SHA1:
  189                 return memcmp(ip->fingerprint, digest, SHA1_FINGERPRINTLEN);
  190                 break;
  191 
  192         default:
  193                   /* unknown fingerprint type, just fail it after whining */
  194                 printf("fingerprintcmp: unknown fingerprint type\n");
  195                 return 1;
  196                 break;
  197         }
  198 }
  199 
  200 
  201 /*
  202  * get_veriexec_inode:
  203  *   Search the given verified exec fingerprint list for the given
  204  * fileid.  If it exists then return a pointer to the list entry,
  205  * otherwise return NULL.  If found_dev is non-NULL set this to true
  206  * iff the given device has a fingerprint list.
  207  *
  208  */
  209 struct veriexec_inode_list *
  210 get_veriexec_inode(struct veriexec_devhead *head, long fsid, long fileid,
  211                 char *found_dev)
  212 {
  213         struct  veriexec_dev_list        *lp;
  214         struct  veriexec_inode_list *ip;
  215 
  216         ip = NULL;
  217         if (found_dev != NULL)
  218                 *found_dev = 0;
  219         
  220 #ifdef VERIFIED_EXEC_DEBUG
  221         printf("searching for file %lu on device %lu\n", fileid, fsid);
  222 #endif
  223         
  224         for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries))
  225                 if (lp->id == fsid)
  226                         break;
  227 
  228         if (lp != NULL) {
  229 #ifdef VERIFIED_EXEC_DEBUG
  230                 printf("found matching dev number %lu\n", lp->id);
  231 #endif
  232                 if (found_dev != NULL)
  233                         *found_dev = 1;
  234                 
  235                 for (ip = LIST_FIRST(&(lp->inode_head)); ip != NULL;
  236                      ip = LIST_NEXT(ip, entries))
  237                         if (ip->inode == fileid)
  238                                 break;
  239         }
  240 
  241         return ip;
  242 }
  243 
  244 /*
  245  * check veriexec:
  246  *   check a file signature and return a status to check_exec.
  247  */
  248 int
  249 check_veriexec(struct proc *p, struct vnode *vp, struct exec_package *epp,
  250                 int direct_exec)
  251 {
  252         int             error;
  253         char            digest[MAXFINGERPRINTLEN], found_dev;
  254         struct  veriexec_inode_list *ip;
  255 
  256         error = 0;
  257         found_dev = 0;
  258         if (vp->fp_status == FINGERPRINT_INVALID) {
  259 
  260 #ifdef VERIFIED_EXEC_DEBUG
  261                 printf("looking for loaded signature\n");
  262 #endif
  263                 ip = get_veriexec_inode(&veriexec_dev_head, epp->ep_vap->va_fsid,
  264                                      epp->ep_vap->va_fileid, &found_dev);
  265 
  266                 if (found_dev == 0) {
  267 #ifdef VERIFIED_EXEC_DEBUG
  268                         printf("No device entry found\n");
  269 #endif
  270                         vp->fp_status = FINGERPRINT_NODEV;
  271                 }
  272  
  273                 if (ip != NULL) {
  274 #ifdef VERIFIED_EXEC_DEBUG
  275                         printf("found matching inode number %lu\n", ip->inode);
  276 #endif
  277                         error = evaluate_fingerprint(vp, ip, p,
  278                                                      epp->ep_vap->va_size,
  279                                                      digest);
  280                         if (error)
  281                                 return error;
  282 
  283                         if (fingerprintcmp(ip, digest) == 0) {
  284                                 if (ip->type == VERIEXEC_DIRECT) {
  285 #ifdef VERIFIED_EXEC_DEBUG
  286                                         printf("Evaluated fingerprint matches\n");
  287 #endif
  288                                         vp->fp_status = FINGERPRINT_VALID;
  289                                 } else {
  290 #ifdef VERIFIED_EXEC_DEBUG
  291                                         printf("Evaluated indirect fingerprint matches\n");
  292 #endif
  293                                         vp->fp_status = FINGERPRINT_INDIRECT;
  294                                 }
  295                         } else {
  296 #ifdef VERIFIED_EXEC_DEBUG
  297                                 printf("Evaluated fingerprint match failed\n");
  298 #endif
  299                                 vp->fp_status = FINGERPRINT_NOMATCH;
  300                         }
  301                 } else {
  302 #ifdef VERIFIED_EXEC_DEBUG
  303                         printf("No fingerprint entry found\n");
  304 #endif
  305                         vp->fp_status = FINGERPRINT_NOENTRY;
  306                 }
  307         }
  308 
  309         switch (vp->fp_status) {
  310           case FINGERPRINT_INVALID: /* should not happen */
  311                   printf("Got unexpected FINGERPRINT_INVALID!!!\n");
  312                   error = EPERM;
  313                   break; 
  314           case FINGERPRINT_VALID: /* is ok - report so if debug is on */
  315 #ifdef VERIFIED_EXEC_DEBUG
  316                   printf("Fingerprint matches\n");
  317 #endif
  318                   break;
  319 
  320           case FINGERPRINT_INDIRECT: /* fingerprint ok but need to check
  321                                         for direct execution */
  322                   if (direct_exec == 1) {
  323                           printf("Attempt to execute %s (dev %lu, inode %lu) "
  324                                  "directly by pid %u (ppid %u, gppid %u)\n",
  325                                  epp->ep_name, epp->ep_vap->va_fsid,
  326                                  epp->ep_vap->va_fileid, p->p_pid,
  327                                  p->p_pptr->p_pid, p->p_pptr->p_pptr->p_pid);
  328                           if (securelevel > 1)
  329                                   error = EPERM;
  330                   }
  331                   break;
  332 
  333           case FINGERPRINT_NOMATCH: /* does not match - whine about it */
  334                   printf("Fingerprint for %s (dev %lu, inode %lu) does not "
  335                          "match loaded value\n",
  336                          epp->ep_name, epp->ep_vap->va_fsid,
  337                          epp->ep_vap->va_fileid);
  338                   if (securelevel > 1)
  339                           error = EPERM;
  340                   break;
  341 
  342           case FINGERPRINT_NOENTRY: /* no entry in the list, complain */
  343                   printf("No fingerprint for %s (dev %lu, inode %lu)\n",
  344                          epp->ep_name, epp->ep_vap->va_fsid,
  345                          epp->ep_vap->va_fileid);
  346                   if (securelevel > 1)
  347                           error = EPERM;
  348                   break;
  349 
  350           case FINGERPRINT_NODEV: /* no signatures for the device, complain */
  351 #ifdef VERIFIED_EXEC_DEBUG
  352                   printf("No signatures for device %lu\n",
  353                          epp->ep_vap->va_fsid);
  354 #endif
  355                   if (securelevel > 1)
  356                           error = EPERM;
  357                   break;
  358 
  359           default: /* this should never happen. */
  360                   printf("Invalid fp_status field for vnode %p\n", vp);
  361                   error = EPERM;
  362         }
  363 
  364         return error; 
  365 
  366 }

Cache object: 78e818b397187edf57d57dd02e2cb545


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