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/audit/audit_bsm_klib.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  * Copyright (c) 1999-2005 Apple Computer, Inc.
    3  * Copyright (c) 2005 Robert N. M. Watson
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1.  Redistributions of source code must retain the above copyright
   10  *     notice, this list of conditions and the following disclaimer.
   11  * 2.  Redistributions in binary form must reproduce the above copyright
   12  *     notice, this list of conditions and the following disclaimer in the
   13  *     documentation and/or other materials provided with the distribution.
   14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
   15  *     its contributors may be used to endorse or promote products derived
   16  *     from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
   22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   28  * POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  * $FreeBSD$
   31  */
   32 
   33 #include <sys/param.h>
   34 #include <sys/fcntl.h>
   35 #include <sys/filedesc.h>
   36 #include <sys/libkern.h>
   37 #include <sys/malloc.h>
   38 #include <sys/mount.h>
   39 #include <sys/proc.h>
   40 #include <sys/sem.h>
   41 #include <sys/syscall.h>
   42 #include <sys/sysctl.h>
   43 #include <sys/sysent.h>
   44 #include <sys/vnode.h>
   45 
   46 #include <bsm/audit.h>
   47 #include <bsm/audit_kevents.h>
   48 #include <security/audit/audit.h>
   49 #include <security/audit/audit_private.h>
   50 
   51 /*
   52  * Hash table functions for the audit event number to event class mask
   53  * mapping.
   54  */
   55 #define EVCLASSMAP_HASH_TABLE_SIZE 251
   56 struct evclass_elem {
   57         au_event_t event;
   58         au_class_t class;
   59         LIST_ENTRY(evclass_elem) entry;
   60 };
   61 struct evclass_list {
   62         LIST_HEAD(, evclass_elem) head;
   63 };
   64 
   65 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
   66 static struct mtx               evclass_mtx;
   67 static struct evclass_list      evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
   68 
   69 /*
   70  * Look up the class for an audit event in the class mapping table.
   71  */
   72 au_class_t
   73 au_event_class(au_event_t event)
   74 {
   75         struct evclass_list *evcl;
   76         struct evclass_elem *evc;
   77         au_class_t class;
   78 
   79         mtx_lock(&evclass_mtx);
   80         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
   81         class = 0;
   82         LIST_FOREACH(evc, &evcl->head, entry) {
   83                 if (evc->event == event) {
   84                         class = evc->class;
   85                         goto out;
   86                 }
   87         }
   88 out:
   89         mtx_unlock(&evclass_mtx);
   90         return (class);
   91 }
   92 
   93 /*
   94  * Insert a event to class mapping. If the event already exists in the
   95  * mapping, then replace the mapping with the new one.
   96  *
   97  * XXX There is currently no constraints placed on the number of mappings.
   98  * May want to either limit to a number, or in terms of memory usage.
   99  */
  100 void
  101 au_evclassmap_insert(au_event_t event, au_class_t class)
  102 {
  103         struct evclass_list *evcl;
  104         struct evclass_elem *evc, *evc_new;
  105 
  106         /*
  107          * Pessimistically, always allocate storage before acquiring mutex.
  108          * Free if there is already a mapping for this event.
  109          */
  110         evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
  111 
  112         mtx_lock(&evclass_mtx);
  113         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
  114         LIST_FOREACH(evc, &evcl->head, entry) {
  115                 if (evc->event == event) {
  116                         evc->class = class;
  117                         mtx_unlock(&evclass_mtx);
  118                         free(evc_new, M_AUDITEVCLASS);
  119                         return;
  120                 }
  121         }
  122         evc = evc_new;
  123         evc->event = event;
  124         evc->class = class;
  125         LIST_INSERT_HEAD(&evcl->head, evc, entry);
  126         mtx_unlock(&evclass_mtx);
  127 }
  128 
  129 void
  130 au_evclassmap_init(void)
  131 {
  132         int i;
  133 
  134         mtx_init(&evclass_mtx, "evclass_mtx", NULL, MTX_DEF);
  135         for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
  136                 LIST_INIT(&evclass_hash[i].head);
  137 
  138         /*
  139          * Set up the initial event to class mapping for system calls.
  140          *
  141          * XXXRW: Really, this should walk all possible audit events, not all
  142          * native ABI system calls, as there may be audit events reachable
  143          * only through non-native system calls.  It also seems a shame to
  144          * frob the mutex this early.
  145          */
  146         for (i = 0; i < SYS_MAXSYSCALL; i++) {
  147                 if (sysent[i].sy_auevent != AUE_NULL)
  148                         au_evclassmap_insert(sysent[i].sy_auevent, 0);
  149         }
  150 }
  151 
  152 /*
  153  * Check whether an event is aditable by comparing the mask of classes this
  154  * event is part of against the given mask.
  155  */
  156 int
  157 au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
  158 {
  159         au_class_t effmask = 0;
  160 
  161         if (mask_p == NULL)
  162                 return (-1);
  163 
  164         /*
  165          * Perform the actual check of the masks against the event.
  166          */
  167         if (sorf & AU_PRS_SUCCESS)
  168                 effmask |= (mask_p->am_success & class);
  169 
  170         if (sorf & AU_PRS_FAILURE)
  171                 effmask |= (mask_p->am_failure & class);
  172 
  173         if (effmask)
  174                 return (1);
  175         else
  176                 return (0);
  177 }
  178 
  179 /*
  180  * Convert sysctl names and present arguments to events.
  181  */
  182 au_event_t
  183 ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
  184 {
  185 
  186         /* can't parse it - so return the worst case */
  187         if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
  188                 return (AUE_SYSCTL);
  189 
  190         switch (name[0]) {
  191         /* non-admin "lookups" treat them special */
  192         case KERN_OSTYPE:
  193         case KERN_OSRELEASE:
  194         case KERN_OSREV:
  195         case KERN_VERSION:
  196         case KERN_ARGMAX:
  197         case KERN_CLOCKRATE:
  198         case KERN_BOOTTIME:
  199         case KERN_POSIX1:
  200         case KERN_NGROUPS:
  201         case KERN_JOB_CONTROL:
  202         case KERN_SAVED_IDS:
  203         case KERN_OSRELDATE:
  204         case KERN_DUMMY:
  205                 return (AUE_SYSCTL_NONADMIN);
  206 
  207         /* only treat the changeable controls as admin */
  208         case KERN_MAXVNODES:
  209         case KERN_MAXPROC:
  210         case KERN_MAXFILES:
  211         case KERN_MAXPROCPERUID:
  212         case KERN_MAXFILESPERPROC:
  213         case KERN_HOSTID:
  214         case KERN_SECURELVL:
  215         case KERN_HOSTNAME:
  216         case KERN_VNODE:
  217         case KERN_PROC:
  218         case KERN_FILE:
  219         case KERN_PROF:
  220         case KERN_NISDOMAINNAME:
  221         case KERN_UPDATEINTERVAL:
  222         case KERN_NTP_PLL:
  223         case KERN_BOOTFILE:
  224         case KERN_DUMPDEV:
  225         case KERN_IPC:
  226         case KERN_PS_STRINGS:
  227         case KERN_USRSTACK:
  228         case KERN_LOGSIGEXIT:
  229         case KERN_IOV_MAX:
  230         case KERN_MAXID:
  231                 return ((valid_arg & ARG_VALUE) ?
  232                         AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
  233 
  234         default:
  235                 return (AUE_SYSCTL);
  236         }
  237         /* NOTREACHED */
  238 }
  239 
  240 /*
  241  * Convert an open flags specifier into a specific type of open event for
  242  * auditing purposes.
  243  */
  244 au_event_t
  245 flags_and_error_to_openevent(int oflags, int error)
  246 {
  247         au_event_t aevent;
  248 
  249         /*
  250          * Need to check only those flags we care about.
  251          */
  252         oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
  253 
  254         /*
  255          * These checks determine what flags are on with the condition that
  256          * ONLY that combination is on, and no other flags are on.
  257          */
  258         switch (oflags) {
  259         case O_RDONLY:
  260                 aevent = AUE_OPEN_R;
  261                 break;
  262 
  263         case (O_RDONLY | O_CREAT):
  264                 aevent = AUE_OPEN_RC;
  265                 break;
  266 
  267         case (O_RDONLY | O_CREAT | O_TRUNC):
  268                 aevent = AUE_OPEN_RTC;
  269                 break;
  270 
  271         case (O_RDONLY | O_TRUNC):
  272                 aevent = AUE_OPEN_RT;
  273                 break;
  274 
  275         case O_RDWR:
  276                 aevent = AUE_OPEN_RW;
  277                 break;
  278 
  279         case (O_RDWR | O_CREAT):
  280                 aevent = AUE_OPEN_RWC;
  281                 break;
  282 
  283         case (O_RDWR | O_CREAT | O_TRUNC):
  284                 aevent = AUE_OPEN_RWTC;
  285                 break;
  286 
  287         case (O_RDWR | O_TRUNC):
  288                 aevent = AUE_OPEN_RWT;
  289                 break;
  290 
  291         case O_WRONLY:
  292                 aevent = AUE_OPEN_W;
  293                 break;
  294 
  295         case (O_WRONLY | O_CREAT):
  296                 aevent = AUE_OPEN_WC;
  297                 break;
  298 
  299         case (O_WRONLY | O_CREAT | O_TRUNC):
  300                 aevent = AUE_OPEN_WTC;
  301                 break;
  302 
  303         case (O_WRONLY | O_TRUNC):
  304                 aevent = AUE_OPEN_WT;
  305                 break;
  306 
  307         default:
  308                 aevent = AUE_OPEN;
  309                 break;
  310         }
  311 
  312 #if 0
  313         /*
  314          * Convert chatty errors to better matching events.  Failures to
  315          * find a file are really just attribute events -- so recast them as
  316          * such.
  317          *
  318          * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
  319          * is just a placeholder.  However, in Darwin we return that in
  320          * preference to other events.  For now, comment this out as we don't
  321          * have a BSM conversion routine for AUE_OPEN.
  322          */
  323         switch (aevent) {
  324         case AUE_OPEN_R:
  325         case AUE_OPEN_RT:
  326         case AUE_OPEN_RW:
  327         case AUE_OPEN_RWT:
  328         case AUE_OPEN_W:
  329         case AUE_OPEN_WT:
  330                 if (error == ENOENT)
  331                         aevent = AUE_OPEN;
  332         }
  333 #endif
  334         return (aevent);
  335 }
  336 
  337 /*
  338  * Convert a MSGCTL command to a specific event.
  339  */
  340 int
  341 msgctl_to_event(int cmd)
  342 {
  343 
  344         switch (cmd) {
  345         case IPC_RMID:
  346                 return (AUE_MSGCTL_RMID);
  347 
  348         case IPC_SET:
  349                 return (AUE_MSGCTL_SET);
  350 
  351         case IPC_STAT:
  352                 return (AUE_MSGCTL_STAT);
  353 
  354         default:
  355                 /* We will audit a bad command. */
  356                 return (AUE_MSGCTL);
  357         }
  358 }
  359 
  360 /*
  361  * Convert a SEMCTL command to a specific event.
  362  */
  363 int
  364 semctl_to_event(int cmd)
  365 {
  366 
  367         switch (cmd) {
  368         case GETALL:
  369                 return (AUE_SEMCTL_GETALL);
  370 
  371         case GETNCNT:
  372                 return (AUE_SEMCTL_GETNCNT);
  373 
  374         case GETPID:
  375                 return (AUE_SEMCTL_GETPID);
  376 
  377         case GETVAL:
  378                 return (AUE_SEMCTL_GETVAL);
  379 
  380         case GETZCNT:
  381                 return (AUE_SEMCTL_GETZCNT);
  382 
  383         case IPC_RMID:
  384                 return (AUE_SEMCTL_RMID);
  385 
  386         case IPC_SET:
  387                 return (AUE_SEMCTL_SET);
  388 
  389         case SETALL:
  390                 return (AUE_SEMCTL_SETALL);
  391 
  392         case SETVAL:
  393                 return (AUE_SEMCTL_SETVAL);
  394 
  395         case IPC_STAT:
  396                 return (AUE_SEMCTL_STAT);
  397 
  398         default:
  399                 /* We will audit a bad command */
  400                 return (AUE_SEMCTL);
  401         }
  402 }
  403 
  404 /*
  405  * Convert a command for the auditon() system call to a audit event.
  406  */
  407 int
  408 auditon_command_event(int cmd)
  409 {
  410 
  411         switch(cmd) {
  412         case A_GETPOLICY:
  413                 return (AUE_AUDITON_GPOLICY);
  414 
  415         case A_SETPOLICY:
  416                 return (AUE_AUDITON_SPOLICY);
  417 
  418         case A_GETKMASK:
  419                 return (AUE_AUDITON_GETKMASK);
  420 
  421         case A_SETKMASK:
  422                 return (AUE_AUDITON_SETKMASK);
  423 
  424         case A_GETQCTRL:
  425                 return (AUE_AUDITON_GQCTRL);
  426 
  427         case A_SETQCTRL:
  428                 return (AUE_AUDITON_SQCTRL);
  429 
  430         case A_GETCWD:
  431                 return (AUE_AUDITON_GETCWD);
  432 
  433         case A_GETCAR:
  434                 return (AUE_AUDITON_GETCAR);
  435 
  436         case A_GETSTAT:
  437                 return (AUE_AUDITON_GETSTAT);
  438 
  439         case A_SETSTAT:
  440                 return (AUE_AUDITON_SETSTAT);
  441 
  442         case A_SETUMASK:
  443                 return (AUE_AUDITON_SETUMASK);
  444 
  445         case A_SETSMASK:
  446                 return (AUE_AUDITON_SETSMASK);
  447 
  448         case A_GETCOND:
  449                 return (AUE_AUDITON_GETCOND);
  450 
  451         case A_SETCOND:
  452                 return (AUE_AUDITON_SETCOND);
  453 
  454         case A_GETCLASS:
  455                 return (AUE_AUDITON_GETCLASS);
  456 
  457         case A_SETCLASS:
  458                 return (AUE_AUDITON_SETCLASS);
  459 
  460         case A_GETPINFO:
  461         case A_SETPMASK:
  462         case A_SETFSIZE:
  463         case A_GETFSIZE:
  464         case A_GETPINFO_ADDR:
  465         case A_GETKAUDIT:
  466         case A_SETKAUDIT:
  467         default:
  468                 return (AUE_AUDITON);   /* No special record */
  469         }
  470 }
  471 
  472 /*
  473  * Create a canonical path from given path by prefixing either the root
  474  * directory, or the current working directory.  If the process working
  475  * directory is NULL, we could use 'rootvnode' to obtain the root directory,
  476  * but this results in a volfs name written to the audit log. So we will
  477  * leave the filename starting with '/' in the audit log in this case.
  478  *
  479  * XXXRW: Since we combine two paths here, ideally a buffer of size
  480  * MAXPATHLEN * 2 would be passed in.
  481  */
  482 void
  483 canon_path(struct thread *td, char *path, char *cpath)
  484 {
  485         char *bufp;
  486         char *retbuf, *freebuf;
  487         struct vnode *vnp;
  488         struct filedesc *fdp;
  489         int cisr, error, vfslocked;
  490 
  491         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
  492             "canon_path() at %s:%d", __FILE__, __LINE__);
  493 
  494         fdp = td->td_proc->p_fd;
  495         bufp = path;
  496         cisr = 0;
  497         FILEDESC_SLOCK(fdp);
  498         if (*(path) == '/') {
  499                 while (*(bufp) == '/')
  500                         bufp++;                 /* Skip leading '/'s. */
  501                 /*
  502                  * If no process root, or it is the same as the system root,
  503                  * audit the path as passed in with a single '/'.
  504                  */
  505                 if ((fdp->fd_rdir == NULL) ||
  506                     (fdp->fd_rdir == rootvnode)) {
  507                         vnp = NULL;
  508                         bufp--;                 /* Restore one '/'. */
  509                 } else {
  510                         vnp = fdp->fd_rdir;     /* Use process root. */
  511                         vref(vnp);
  512                 }
  513         } else {
  514                 vnp = fdp->fd_cdir;     /* Prepend the current dir. */
  515                 cisr = (fdp->fd_rdir == fdp->fd_cdir);
  516                 vref(vnp);
  517                 bufp = path;
  518         }
  519         FILEDESC_SUNLOCK(fdp);
  520         if (vnp != NULL) {
  521                 /*
  522                  * XXX: vn_fullpath() on FreeBSD is "less reliable" than
  523                  * vn_getpath() on Darwin, so this will need more attention
  524                  * in the future.  Also, the question and string bounding
  525                  * here seems a bit questionable and will also require
  526                  * attention.
  527                  */
  528                 vfslocked = VFS_LOCK_GIANT(vnp->v_mount);
  529                 vn_lock(vnp, LK_EXCLUSIVE | LK_RETRY, td);
  530                 error = vn_fullpath(td, vnp, &retbuf, &freebuf);
  531                 if (error == 0) {
  532                         /* Copy and free buffer allocated by vn_fullpath().
  533                          * If the current working directory was the same as
  534                          * the root directory, and the path was a relative
  535                          * pathname, do not separate the two components with
  536                          * the '/' character.
  537                          */
  538                         snprintf(cpath, MAXPATHLEN, "%s%s%s", retbuf,
  539                             cisr ? "" : "/", bufp);
  540                         free(freebuf, M_TEMP);
  541                 } else
  542                         cpath[0] = '\0';
  543                 vput(vnp);
  544                 VFS_UNLOCK_GIANT(vfslocked);
  545         } else
  546                 strlcpy(cpath, bufp, MAXPATHLEN);
  547 }

Cache object: ea832f0b6fe605de4cb0132418efd56e


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