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

Cache object: 075c000af75b5bde95b1f2e981f61a50


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