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

Cache object: da0740d0d05c9447335407e309dee143


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