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-2009 Apple 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 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 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/11.0/sys/security/audit/audit_bsm_klib.c 298411 2016-04-21 15:38:28Z pfg $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/capsicum.h>
   36 #include <sys/fcntl.h>
   37 #include <sys/filedesc.h>
   38 #include <sys/libkern.h>
   39 #include <sys/malloc.h>
   40 #include <sys/mount.h>
   41 #include <sys/proc.h>
   42 #include <sys/rwlock.h>
   43 #include <sys/sem.h>
   44 #include <sys/sbuf.h>
   45 #include <sys/syscall.h>
   46 #include <sys/sysctl.h>
   47 #include <sys/sysent.h>
   48 #include <sys/vnode.h>
   49 
   50 #include <bsm/audit.h>
   51 #include <bsm/audit_kevents.h>
   52 #include <security/audit/audit.h>
   53 #include <security/audit/audit_private.h>
   54 
   55 /*
   56  * Hash table functions for the audit event number to event class mask
   57  * mapping.
   58  */
   59 #define EVCLASSMAP_HASH_TABLE_SIZE      251
   60 struct evclass_elem {
   61         au_event_t event;
   62         au_class_t class;
   63         LIST_ENTRY(evclass_elem) entry;
   64 };
   65 struct evclass_list {
   66         LIST_HEAD(, evclass_elem) head;
   67 };
   68 
   69 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
   70 static struct rwlock            evclass_lock;
   71 static struct evclass_list      evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
   72 
   73 #define EVCLASS_LOCK_INIT()     rw_init(&evclass_lock, "evclass_lock")
   74 #define EVCLASS_RLOCK()         rw_rlock(&evclass_lock)
   75 #define EVCLASS_RUNLOCK()       rw_runlock(&evclass_lock)
   76 #define EVCLASS_WLOCK()         rw_wlock(&evclass_lock)
   77 #define EVCLASS_WUNLOCK()       rw_wunlock(&evclass_lock)
   78 
   79 struct aue_open_event {
   80         int             aoe_flags;
   81         au_event_t      aoe_event;
   82 };
   83 
   84 static const struct aue_open_event aue_open[] = {
   85         { O_RDONLY,                                     AUE_OPEN_R },
   86         { (O_RDONLY | O_CREAT),                         AUE_OPEN_RC },
   87         { (O_RDONLY | O_CREAT | O_TRUNC),               AUE_OPEN_RTC },
   88         { (O_RDONLY | O_TRUNC),                         AUE_OPEN_RT },
   89         { O_RDWR,                                       AUE_OPEN_RW },
   90         { (O_RDWR | O_CREAT),                           AUE_OPEN_RWC },
   91         { (O_RDWR | O_CREAT | O_TRUNC),                 AUE_OPEN_RWTC },
   92         { (O_RDWR | O_TRUNC),                           AUE_OPEN_RWT },
   93         { O_WRONLY,                                     AUE_OPEN_W },
   94         { (O_WRONLY | O_CREAT),                         AUE_OPEN_WC },
   95         { (O_WRONLY | O_CREAT | O_TRUNC),               AUE_OPEN_WTC },
   96         { (O_WRONLY | O_TRUNC),                         AUE_OPEN_WT },
   97 };
   98 
   99 static const struct aue_open_event aue_openat[] = {
  100         { O_RDONLY,                                     AUE_OPENAT_R },
  101         { (O_RDONLY | O_CREAT),                         AUE_OPENAT_RC },
  102         { (O_RDONLY | O_CREAT | O_TRUNC),               AUE_OPENAT_RTC },
  103         { (O_RDONLY | O_TRUNC),                         AUE_OPENAT_RT },
  104         { O_RDWR,                                       AUE_OPENAT_RW },
  105         { (O_RDWR | O_CREAT),                           AUE_OPENAT_RWC },
  106         { (O_RDWR | O_CREAT | O_TRUNC),                 AUE_OPENAT_RWTC },
  107         { (O_RDWR | O_TRUNC),                           AUE_OPENAT_RWT },
  108         { O_WRONLY,                                     AUE_OPENAT_W },
  109         { (O_WRONLY | O_CREAT),                         AUE_OPENAT_WC },
  110         { (O_WRONLY | O_CREAT | O_TRUNC),               AUE_OPENAT_WTC },
  111         { (O_WRONLY | O_TRUNC),                         AUE_OPENAT_WT },
  112 };
  113 
  114 /*
  115  * Look up the class for an audit event in the class mapping table.
  116  */
  117 au_class_t
  118 au_event_class(au_event_t event)
  119 {
  120         struct evclass_list *evcl;
  121         struct evclass_elem *evc;
  122         au_class_t class;
  123 
  124         EVCLASS_RLOCK();
  125         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
  126         class = 0;
  127         LIST_FOREACH(evc, &evcl->head, entry) {
  128                 if (evc->event == event) {
  129                         class = evc->class;
  130                         goto out;
  131                 }
  132         }
  133 out:
  134         EVCLASS_RUNLOCK();
  135         return (class);
  136 }
  137 
  138 /*
  139  * Insert a event to class mapping. If the event already exists in the
  140  * mapping, then replace the mapping with the new one.
  141  *
  142  * XXX There is currently no constraints placed on the number of mappings.
  143  * May want to either limit to a number, or in terms of memory usage.
  144  */
  145 void
  146 au_evclassmap_insert(au_event_t event, au_class_t class)
  147 {
  148         struct evclass_list *evcl;
  149         struct evclass_elem *evc, *evc_new;
  150 
  151         /*
  152          * Pessimistically, always allocate storage before acquiring mutex.
  153          * Free if there is already a mapping for this event.
  154          */
  155         evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
  156 
  157         EVCLASS_WLOCK();
  158         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
  159         LIST_FOREACH(evc, &evcl->head, entry) {
  160                 if (evc->event == event) {
  161                         evc->class = class;
  162                         EVCLASS_WUNLOCK();
  163                         free(evc_new, M_AUDITEVCLASS);
  164                         return;
  165                 }
  166         }
  167         evc = evc_new;
  168         evc->event = event;
  169         evc->class = class;
  170         LIST_INSERT_HEAD(&evcl->head, evc, entry);
  171         EVCLASS_WUNLOCK();
  172 }
  173 
  174 void
  175 au_evclassmap_init(void)
  176 {
  177         int i;
  178 
  179         EVCLASS_LOCK_INIT();
  180         for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
  181                 LIST_INIT(&evclass_hash[i].head);
  182 
  183         /*
  184          * Set up the initial event to class mapping for system calls.
  185          *
  186          * XXXRW: Really, this should walk all possible audit events, not all
  187          * native ABI system calls, as there may be audit events reachable
  188          * only through non-native system calls.  It also seems a shame to
  189          * frob the mutex this early.
  190          */
  191         for (i = 0; i < SYS_MAXSYSCALL; i++) {
  192                 if (sysent[i].sy_auevent != AUE_NULL)
  193                         au_evclassmap_insert(sysent[i].sy_auevent, 0);
  194         }
  195 }
  196 
  197 /*
  198  * Check whether an event is aditable by comparing the mask of classes this
  199  * event is part of against the given mask.
  200  */
  201 int
  202 au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
  203 {
  204         au_class_t effmask = 0;
  205 
  206         if (mask_p == NULL)
  207                 return (-1);
  208 
  209         /*
  210          * Perform the actual check of the masks against the event.
  211          */
  212         if (sorf & AU_PRS_SUCCESS)
  213                 effmask |= (mask_p->am_success & class);
  214 
  215         if (sorf & AU_PRS_FAILURE)
  216                 effmask |= (mask_p->am_failure & class);
  217 
  218         if (effmask)
  219                 return (1);
  220         else
  221                 return (0);
  222 }
  223 
  224 /*
  225  * Convert sysctl names and present arguments to events.
  226  */
  227 au_event_t
  228 audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
  229 {
  230 
  231         /* can't parse it - so return the worst case */
  232         if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
  233                 return (AUE_SYSCTL);
  234 
  235         switch (name[0]) {
  236         /* non-admin "lookups" treat them special */
  237         case KERN_OSTYPE:
  238         case KERN_OSRELEASE:
  239         case KERN_OSREV:
  240         case KERN_VERSION:
  241         case KERN_ARGMAX:
  242         case KERN_CLOCKRATE:
  243         case KERN_BOOTTIME:
  244         case KERN_POSIX1:
  245         case KERN_NGROUPS:
  246         case KERN_JOB_CONTROL:
  247         case KERN_SAVED_IDS:
  248         case KERN_OSRELDATE:
  249         case KERN_DUMMY:
  250                 return (AUE_SYSCTL_NONADMIN);
  251 
  252         /* only treat the changeable controls as admin */
  253         case KERN_MAXVNODES:
  254         case KERN_MAXPROC:
  255         case KERN_MAXFILES:
  256         case KERN_MAXPROCPERUID:
  257         case KERN_MAXFILESPERPROC:
  258         case KERN_HOSTID:
  259         case KERN_SECURELVL:
  260         case KERN_HOSTNAME:
  261         case KERN_VNODE:
  262         case KERN_PROC:
  263         case KERN_FILE:
  264         case KERN_PROF:
  265         case KERN_NISDOMAINNAME:
  266         case KERN_UPDATEINTERVAL:
  267         case KERN_NTP_PLL:
  268         case KERN_BOOTFILE:
  269         case KERN_DUMPDEV:
  270         case KERN_IPC:
  271         case KERN_PS_STRINGS:
  272         case KERN_USRSTACK:
  273         case KERN_LOGSIGEXIT:
  274         case KERN_IOV_MAX:
  275                 return ((valid_arg & ARG_VALUE) ?
  276                     AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
  277 
  278         default:
  279                 return (AUE_SYSCTL);
  280         }
  281         /* NOTREACHED */
  282 }
  283 
  284 /*
  285  * Convert an open flags specifier into a specific type of open event for
  286  * auditing purposes.
  287  */
  288 au_event_t
  289 audit_flags_and_error_to_openevent(int oflags, int error)
  290 {
  291         int i;
  292 
  293         /*
  294          * Need to check only those flags we care about.
  295          */
  296         oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
  297         for (i = 0; i < nitems(aue_open); i++) {
  298                 if (aue_open[i].aoe_flags == oflags)
  299                         return (aue_open[i].aoe_event);
  300         }
  301         return (AUE_OPEN);
  302 }
  303 
  304 au_event_t
  305 audit_flags_and_error_to_openatevent(int oflags, int error)
  306 {
  307         int i;
  308 
  309         /*
  310          * Need to check only those flags we care about.
  311          */
  312         oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
  313         for (i = 0; i < nitems(aue_openat); i++) {
  314                 if (aue_openat[i].aoe_flags == oflags)
  315                         return (aue_openat[i].aoe_event);
  316         }
  317         return (AUE_OPENAT);
  318 }
  319 
  320 /*
  321  * Convert a MSGCTL command to a specific event.
  322  */
  323 au_event_t
  324 audit_msgctl_to_event(int cmd)
  325 {
  326 
  327         switch (cmd) {
  328         case IPC_RMID:
  329                 return (AUE_MSGCTL_RMID);
  330 
  331         case IPC_SET:
  332                 return (AUE_MSGCTL_SET);
  333 
  334         case IPC_STAT:
  335                 return (AUE_MSGCTL_STAT);
  336 
  337         default:
  338                 /* We will audit a bad command. */
  339                 return (AUE_MSGCTL);
  340         }
  341 }
  342 
  343 /*
  344  * Convert a SEMCTL command to a specific event.
  345  */
  346 au_event_t
  347 audit_semctl_to_event(int cmd)
  348 {
  349 
  350         switch (cmd) {
  351         case GETALL:
  352                 return (AUE_SEMCTL_GETALL);
  353 
  354         case GETNCNT:
  355                 return (AUE_SEMCTL_GETNCNT);
  356 
  357         case GETPID:
  358                 return (AUE_SEMCTL_GETPID);
  359 
  360         case GETVAL:
  361                 return (AUE_SEMCTL_GETVAL);
  362 
  363         case GETZCNT:
  364                 return (AUE_SEMCTL_GETZCNT);
  365 
  366         case IPC_RMID:
  367                 return (AUE_SEMCTL_RMID);
  368 
  369         case IPC_SET:
  370                 return (AUE_SEMCTL_SET);
  371 
  372         case SETALL:
  373                 return (AUE_SEMCTL_SETALL);
  374 
  375         case SETVAL:
  376                 return (AUE_SEMCTL_SETVAL);
  377 
  378         case IPC_STAT:
  379                 return (AUE_SEMCTL_STAT);
  380 
  381         default:
  382                 /* We will audit a bad command. */
  383                 return (AUE_SEMCTL);
  384         }
  385 }
  386 
  387 /*
  388  * Convert a command for the auditon() system call to a audit event.
  389  */
  390 au_event_t
  391 auditon_command_event(int cmd)
  392 {
  393 
  394         switch(cmd) {
  395         case A_GETPOLICY:
  396                 return (AUE_AUDITON_GPOLICY);
  397 
  398         case A_SETPOLICY:
  399                 return (AUE_AUDITON_SPOLICY);
  400 
  401         case A_GETKMASK:
  402                 return (AUE_AUDITON_GETKMASK);
  403 
  404         case A_SETKMASK:
  405                 return (AUE_AUDITON_SETKMASK);
  406 
  407         case A_GETQCTRL:
  408                 return (AUE_AUDITON_GQCTRL);
  409 
  410         case A_SETQCTRL:
  411                 return (AUE_AUDITON_SQCTRL);
  412 
  413         case A_GETCWD:
  414                 return (AUE_AUDITON_GETCWD);
  415 
  416         case A_GETCAR:
  417                 return (AUE_AUDITON_GETCAR);
  418 
  419         case A_GETSTAT:
  420                 return (AUE_AUDITON_GETSTAT);
  421 
  422         case A_SETSTAT:
  423                 return (AUE_AUDITON_SETSTAT);
  424 
  425         case A_SETUMASK:
  426                 return (AUE_AUDITON_SETUMASK);
  427 
  428         case A_SETSMASK:
  429                 return (AUE_AUDITON_SETSMASK);
  430 
  431         case A_GETCOND:
  432                 return (AUE_AUDITON_GETCOND);
  433 
  434         case A_SETCOND:
  435                 return (AUE_AUDITON_SETCOND);
  436 
  437         case A_GETCLASS:
  438                 return (AUE_AUDITON_GETCLASS);
  439 
  440         case A_SETCLASS:
  441                 return (AUE_AUDITON_SETCLASS);
  442 
  443         case A_GETPINFO:
  444         case A_SETPMASK:
  445         case A_SETFSIZE:
  446         case A_GETFSIZE:
  447         case A_GETPINFO_ADDR:
  448         case A_GETKAUDIT:
  449         case A_SETKAUDIT:
  450         default:
  451                 return (AUE_AUDITON);   /* No special record */
  452         }
  453 }
  454 
  455 /*
  456  * Create a canonical path from given path by prefixing either the root
  457  * directory, or the current working directory.  If the process working
  458  * directory is NULL, we could use 'rootvnode' to obtain the root directory,
  459  * but this results in a volfs name written to the audit log. So we will
  460  * leave the filename starting with '/' in the audit log in this case.
  461  */
  462 void
  463 audit_canon_path(struct thread *td, int dirfd, char *path, char *cpath)
  464 {
  465         struct vnode *cvnp, *rvnp;
  466         char *rbuf, *fbuf, *copy;
  467         struct filedesc *fdp;
  468         struct sbuf sbf;
  469         cap_rights_t rights;
  470         int error, needslash;
  471 
  472         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
  473             __func__,  __FILE__, __LINE__);
  474 
  475         copy = path;
  476         rvnp = cvnp = NULL;
  477         fdp = td->td_proc->p_fd;
  478         FILEDESC_SLOCK(fdp);
  479         /*
  480          * Make sure that we handle the chroot(2) case.  If there is an
  481          * alternate root directory, prepend it to the audited pathname.
  482          */
  483         if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) {
  484                 rvnp = fdp->fd_rdir;
  485                 vhold(rvnp);
  486         }
  487         /*
  488          * If the supplied path is relative, make sure we capture the current
  489          * working directory so we can prepend it to the supplied relative
  490          * path.
  491          */
  492         if (*path != '/') {
  493                 if (dirfd == AT_FDCWD) {
  494                         cvnp = fdp->fd_cdir;
  495                         vhold(cvnp);
  496                 } else {
  497                         /* XXX: fgetvp() that vhold()s vnode instead of vref()ing it would be better */
  498                         error = fgetvp(td, dirfd, cap_rights_init(&rights), &cvnp);
  499                         if (error) {
  500                                 FILEDESC_SUNLOCK(fdp);
  501                                 cpath[0] = '\0';
  502                                 if (rvnp != NULL)
  503                                         vdrop(rvnp);
  504                                 return;
  505                         }
  506                         vhold(cvnp);
  507                         vrele(cvnp);
  508                 }
  509                 needslash = (fdp->fd_rdir != cvnp);
  510         } else {
  511                 needslash = 1;
  512         }
  513         FILEDESC_SUNLOCK(fdp);
  514         /*
  515          * NB: We require that the supplied array be at least MAXPATHLEN bytes
  516          * long.  If this is not the case, then we can run into serious trouble.
  517          */
  518         (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
  519         /*
  520          * Strip leading forward slashes.
  521          */
  522         while (*copy == '/')
  523                 copy++;
  524         /*
  525          * Make sure we handle chroot(2) and prepend the global path to these
  526          * environments.
  527          *
  528          * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
  529          * on Darwin.  As a result, this may need some additional attention
  530          * in the future.
  531          */
  532         if (rvnp != NULL) {
  533                 error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf);
  534                 vdrop(rvnp);
  535                 if (error) {
  536                         cpath[0] = '\0';
  537                         if (cvnp != NULL)
  538                                 vdrop(cvnp);
  539                         return;
  540                 }
  541                 (void) sbuf_cat(&sbf, rbuf);
  542                 free(fbuf, M_TEMP);
  543         }
  544         if (cvnp != NULL) {
  545                 error = vn_fullpath(td, cvnp, &rbuf, &fbuf);
  546                 vdrop(cvnp);
  547                 if (error) {
  548                         cpath[0] = '\0';
  549                         return;
  550                 }
  551                 (void) sbuf_cat(&sbf, rbuf);
  552                 free(fbuf, M_TEMP);
  553         }
  554         if (needslash)
  555                 (void) sbuf_putc(&sbf, '/');
  556         /*
  557          * Now that we have processed any alternate root and relative path
  558          * names, add the supplied pathname.
  559          */
  560         (void) sbuf_cat(&sbf, copy);
  561         /*
  562          * One or more of the previous sbuf operations could have resulted in
  563          * the supplied buffer being overflowed.  Check to see if this is the
  564          * case.
  565          */
  566         if (sbuf_error(&sbf) != 0) {
  567                 cpath[0] = '\0';
  568                 return;
  569         }
  570         sbuf_finish(&sbf);
  571 }

Cache object: 060aadc1c351874603b3d72ffe02b38f


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