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/9.1/sys/security/audit/audit_bsm_klib.c 212425 2010-09-10 16:42:16Z mdf $");
   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         case KERN_MAXID:
  277                 return ((valid_arg & ARG_VALUE) ?
  278                     AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
  279 
  280         default:
  281                 return (AUE_SYSCTL);
  282         }
  283         /* NOTREACHED */
  284 }
  285 
  286 /*
  287  * Convert an open flags specifier into a specific type of open event for
  288  * auditing purposes.
  289  */
  290 au_event_t
  291 audit_flags_and_error_to_openevent(int oflags, int error)
  292 {
  293         int i;
  294 
  295         /*
  296          * Need to check only those flags we care about.
  297          */
  298         oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
  299         for (i = 0; i < aue_open_count; i++) {
  300                 if (aue_open[i].aoe_flags == oflags)
  301                         return (aue_open[i].aoe_event);
  302         }
  303         return (AUE_OPEN);
  304 }
  305 
  306 au_event_t
  307 audit_flags_and_error_to_openatevent(int oflags, int error)
  308 {
  309         int i;
  310 
  311         /*
  312          * Need to check only those flags we care about.
  313          */
  314         oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
  315         for (i = 0; i < aue_openat_count; i++) {
  316                 if (aue_openat[i].aoe_flags == oflags)
  317                         return (aue_openat[i].aoe_event);
  318         }
  319         return (AUE_OPENAT);
  320 }
  321 
  322 /*
  323  * Convert a MSGCTL command to a specific event.
  324  */
  325 au_event_t
  326 audit_msgctl_to_event(int cmd)
  327 {
  328 
  329         switch (cmd) {
  330         case IPC_RMID:
  331                 return (AUE_MSGCTL_RMID);
  332 
  333         case IPC_SET:
  334                 return (AUE_MSGCTL_SET);
  335 
  336         case IPC_STAT:
  337                 return (AUE_MSGCTL_STAT);
  338 
  339         default:
  340                 /* We will audit a bad command. */
  341                 return (AUE_MSGCTL);
  342         }
  343 }
  344 
  345 /*
  346  * Convert a SEMCTL command to a specific event.
  347  */
  348 au_event_t
  349 audit_semctl_to_event(int cmd)
  350 {
  351 
  352         switch (cmd) {
  353         case GETALL:
  354                 return (AUE_SEMCTL_GETALL);
  355 
  356         case GETNCNT:
  357                 return (AUE_SEMCTL_GETNCNT);
  358 
  359         case GETPID:
  360                 return (AUE_SEMCTL_GETPID);
  361 
  362         case GETVAL:
  363                 return (AUE_SEMCTL_GETVAL);
  364 
  365         case GETZCNT:
  366                 return (AUE_SEMCTL_GETZCNT);
  367 
  368         case IPC_RMID:
  369                 return (AUE_SEMCTL_RMID);
  370 
  371         case IPC_SET:
  372                 return (AUE_SEMCTL_SET);
  373 
  374         case SETALL:
  375                 return (AUE_SEMCTL_SETALL);
  376 
  377         case SETVAL:
  378                 return (AUE_SEMCTL_SETVAL);
  379 
  380         case IPC_STAT:
  381                 return (AUE_SEMCTL_STAT);
  382 
  383         default:
  384                 /* We will audit a bad command. */
  385                 return (AUE_SEMCTL);
  386         }
  387 }
  388 
  389 /*
  390  * Convert a command for the auditon() system call to a audit event.
  391  */
  392 au_event_t
  393 auditon_command_event(int cmd)
  394 {
  395 
  396         switch(cmd) {
  397         case A_GETPOLICY:
  398                 return (AUE_AUDITON_GPOLICY);
  399 
  400         case A_SETPOLICY:
  401                 return (AUE_AUDITON_SPOLICY);
  402 
  403         case A_GETKMASK:
  404                 return (AUE_AUDITON_GETKMASK);
  405 
  406         case A_SETKMASK:
  407                 return (AUE_AUDITON_SETKMASK);
  408 
  409         case A_GETQCTRL:
  410                 return (AUE_AUDITON_GQCTRL);
  411 
  412         case A_SETQCTRL:
  413                 return (AUE_AUDITON_SQCTRL);
  414 
  415         case A_GETCWD:
  416                 return (AUE_AUDITON_GETCWD);
  417 
  418         case A_GETCAR:
  419                 return (AUE_AUDITON_GETCAR);
  420 
  421         case A_GETSTAT:
  422                 return (AUE_AUDITON_GETSTAT);
  423 
  424         case A_SETSTAT:
  425                 return (AUE_AUDITON_SETSTAT);
  426 
  427         case A_SETUMASK:
  428                 return (AUE_AUDITON_SETUMASK);
  429 
  430         case A_SETSMASK:
  431                 return (AUE_AUDITON_SETSMASK);
  432 
  433         case A_GETCOND:
  434                 return (AUE_AUDITON_GETCOND);
  435 
  436         case A_SETCOND:
  437                 return (AUE_AUDITON_SETCOND);
  438 
  439         case A_GETCLASS:
  440                 return (AUE_AUDITON_GETCLASS);
  441 
  442         case A_SETCLASS:
  443                 return (AUE_AUDITON_SETCLASS);
  444 
  445         case A_GETPINFO:
  446         case A_SETPMASK:
  447         case A_SETFSIZE:
  448         case A_GETFSIZE:
  449         case A_GETPINFO_ADDR:
  450         case A_GETKAUDIT:
  451         case A_SETKAUDIT:
  452         default:
  453                 return (AUE_AUDITON);   /* No special record */
  454         }
  455 }
  456 
  457 /*
  458  * Create a canonical path from given path by prefixing either the root
  459  * directory, or the current working directory.  If the process working
  460  * directory is NULL, we could use 'rootvnode' to obtain the root directory,
  461  * but this results in a volfs name written to the audit log. So we will
  462  * leave the filename starting with '/' in the audit log in this case.
  463  */
  464 void
  465 audit_canon_path(struct thread *td, char *path, char *cpath)
  466 {
  467         struct vnode *cvnp, *rvnp;
  468         char *rbuf, *fbuf, *copy;
  469         struct filedesc *fdp;
  470         struct sbuf sbf;
  471         int error, cwir;
  472 
  473         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
  474             __func__,  __FILE__, __LINE__);
  475 
  476         copy = path;
  477         rvnp = cvnp = NULL;
  478         fdp = td->td_proc->p_fd;
  479         FILEDESC_SLOCK(fdp);
  480         /*
  481          * Make sure that we handle the chroot(2) case.  If there is an
  482          * alternate root directory, prepend it to the audited pathname.
  483          */
  484         if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) {
  485                 rvnp = fdp->fd_rdir;
  486                 vhold(rvnp);
  487         }
  488         /*
  489          * If the supplied path is relative, make sure we capture the current
  490          * working directory so we can prepend it to the supplied relative
  491          * path.
  492          */
  493         if (*path != '/') {
  494                 cvnp = fdp->fd_cdir;
  495                 vhold(cvnp);
  496         }
  497         cwir = (fdp->fd_rdir == fdp->fd_cdir);
  498         FILEDESC_SUNLOCK(fdp);
  499         /*
  500          * NB: We require that the supplied array be at least MAXPATHLEN bytes
  501          * long.  If this is not the case, then we can run into serious trouble.
  502          */
  503         (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
  504         /*
  505          * Strip leading forward slashes.
  506          */
  507         while (*copy == '/')
  508                 copy++;
  509         /*
  510          * Make sure we handle chroot(2) and prepend the global path to these
  511          * environments.
  512          *
  513          * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
  514          * on Darwin.  As a result, this may need some additional attention
  515          * in the future.
  516          */
  517         if (rvnp != NULL) {
  518                 error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf);
  519                 vdrop(rvnp);
  520                 if (error) {
  521                         cpath[0] = '\0';
  522                         if (cvnp != NULL)
  523                                 vdrop(cvnp);
  524                         return;
  525                 }
  526                 (void) sbuf_cat(&sbf, rbuf);
  527                 free(fbuf, M_TEMP);
  528         }
  529         if (cvnp != NULL) {
  530                 error = vn_fullpath(td, cvnp, &rbuf, &fbuf);
  531                 vdrop(cvnp);
  532                 if (error) {
  533                         cpath[0] = '\0';
  534                         return;
  535                 }
  536                 (void) sbuf_cat(&sbf, rbuf);
  537                 free(fbuf, M_TEMP);
  538         }
  539         if (cwir == 0 || (cwir != 0 && cvnp == NULL))
  540                 (void) sbuf_putc(&sbf, '/');
  541         /*
  542          * Now that we have processed any alternate root and relative path
  543          * names, add the supplied pathname.
  544          */
  545         (void) sbuf_cat(&sbf, copy);
  546         /*
  547          * One or more of the previous sbuf operations could have resulted in
  548          * the supplied buffer being overflowed.  Check to see if this is the
  549          * case.
  550          */
  551         if (sbuf_error(&sbf) != 0) {
  552                 cpath[0] = '\0';
  553                 return;
  554         }
  555         sbuf_finish(&sbf);
  556 }

Cache object: 684d722a5165594af435fafe783f97be


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