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_db.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, 2016-2018 Robert N. M. Watson
    4  * All rights reserved.
    5  *
    6  * Portions of this software were developed by BAE Systems, the University of
    7  * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
    8  * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
    9  * Computing (TC) research program.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1.  Redistributions of source code must retain the above copyright
   15  *     notice, this list of conditions and the following disclaimer.
   16  * 2.  Redistributions in binary form must reproduce the above copyright
   17  *     notice, this list of conditions and the following disclaimer in the
   18  *     documentation and/or other materials provided with the distribution.
   19  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
   20  *     its contributors may be used to endorse or promote products derived
   21  *     from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
   27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33  * POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/param.h>
   40 #include <sys/capsicum.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/filedesc.h>
   43 #include <sys/libkern.h>
   44 #include <sys/linker.h>
   45 #include <sys/malloc.h>
   46 #include <sys/mount.h>
   47 #include <sys/proc.h>
   48 #include <sys/rwlock.h>
   49 #include <sys/sem.h>
   50 #include <sys/sbuf.h>
   51 #include <sys/sx.h>
   52 #include <sys/syscall.h>
   53 #include <sys/sysctl.h>
   54 #include <sys/sysent.h>
   55 #include <sys/vnode.h>
   56 
   57 #include <bsm/audit.h>
   58 #include <bsm/audit_kevents.h>
   59 #include <security/audit/audit.h>
   60 #include <security/audit/audit_private.h>
   61 
   62 /*
   63  * Hash table functions for the audit event number to event class mask
   64  * mapping.
   65  */
   66 #define EVCLASSMAP_HASH_TABLE_SIZE      251
   67 struct evclass_elem {
   68         au_event_t event;
   69         au_class_t class;
   70         LIST_ENTRY(evclass_elem) entry;
   71 };
   72 struct evclass_list {
   73         LIST_HEAD(, evclass_elem) head;
   74 };
   75 
   76 static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
   77 static struct rwlock            evclass_lock;
   78 static struct evclass_list      evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
   79 
   80 #define EVCLASS_LOCK_INIT()     rw_init(&evclass_lock, "evclass_lock")
   81 #define EVCLASS_RLOCK()         rw_rlock(&evclass_lock)
   82 #define EVCLASS_RUNLOCK()       rw_runlock(&evclass_lock)
   83 #define EVCLASS_WLOCK()         rw_wlock(&evclass_lock)
   84 #define EVCLASS_WUNLOCK()       rw_wunlock(&evclass_lock)
   85 
   86 /*
   87  * Hash table maintaining a mapping from audit event numbers to audit event
   88  * names.  For now, used only by DTrace, but present always so that userspace
   89  * tools can register and inspect fields consistently even if DTrace is not
   90  * present.
   91  *
   92  * struct evname_elem is defined in audit_private.h so that audit_dtrace.c can
   93  * use the definition.
   94  */
   95 #define EVNAMEMAP_HASH_TABLE_MODULE     "etc_security_audit_event"
   96 #define EVNAMEMAP_HASH_TABLE_SIZE       251
   97 struct evname_list {
   98         LIST_HEAD(, evname_elem)        enl_head;
   99 };
  100 
  101 static MALLOC_DEFINE(M_AUDITEVNAME, "audit_evname", "Audit event name");
  102 static struct sx                evnamemap_lock;
  103 static struct evname_list       evnamemap_hash[EVNAMEMAP_HASH_TABLE_SIZE];
  104 
  105 #define EVNAMEMAP_LOCK_INIT()   sx_init(&evnamemap_lock, "evnamemap_lock");
  106 #define EVNAMEMAP_RLOCK()       sx_slock(&evnamemap_lock)
  107 #define EVNAMEMAP_RUNLOCK()     sx_sunlock(&evnamemap_lock)
  108 #define EVNAMEMAP_WLOCK()       sx_xlock(&evnamemap_lock)
  109 #define EVNAMEMAP_WUNLOCK()     sx_xunlock(&evnamemap_lock)
  110 
  111 /*
  112  * Look up the class for an audit event in the class mapping table.
  113  */
  114 au_class_t
  115 au_event_class(au_event_t event)
  116 {
  117         struct evclass_list *evcl;
  118         struct evclass_elem *evc;
  119         au_class_t class;
  120 
  121         EVCLASS_RLOCK();
  122         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
  123         class = 0;
  124         LIST_FOREACH(evc, &evcl->head, entry) {
  125                 if (evc->event == event) {
  126                         class = evc->class;
  127                         goto out;
  128                 }
  129         }
  130 out:
  131         EVCLASS_RUNLOCK();
  132         return (class);
  133 }
  134 
  135 /*
  136  * Insert a event to class mapping. If the event already exists in the
  137  * mapping, then replace the mapping with the new one.
  138  *
  139  * XXX There is currently no constraints placed on the number of mappings.
  140  * May want to either limit to a number, or in terms of memory usage.
  141  */
  142 void
  143 au_evclassmap_insert(au_event_t event, au_class_t class)
  144 {
  145         struct evclass_list *evcl;
  146         struct evclass_elem *evc, *evc_new;
  147 
  148         /*
  149          * Pessimistically, always allocate storage before acquiring mutex.
  150          * Free if there is already a mapping for this event.
  151          */
  152         evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
  153 
  154         EVCLASS_WLOCK();
  155         evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
  156         LIST_FOREACH(evc, &evcl->head, entry) {
  157                 if (evc->event == event) {
  158                         evc->class = class;
  159                         EVCLASS_WUNLOCK();
  160                         free(evc_new, M_AUDITEVCLASS);
  161                         return;
  162                 }
  163         }
  164         evc = evc_new;
  165         evc->event = event;
  166         evc->class = class;
  167         LIST_INSERT_HEAD(&evcl->head, evc, entry);
  168         EVCLASS_WUNLOCK();
  169 }
  170 
  171 void
  172 au_evclassmap_init(void)
  173 {
  174         int i;
  175 
  176         EVCLASS_LOCK_INIT();
  177         for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
  178                 LIST_INIT(&evclass_hash[i].head);
  179 
  180         /*
  181          * Set up the initial event to class mapping for system calls.
  182          *
  183          * XXXRW: Really, this should walk all possible audit events, not all
  184          * native ABI system calls, as there may be audit events reachable
  185          * only through non-native system calls.  It also seems a shame to
  186          * frob the mutex this early.
  187          */
  188         for (i = 0; i < SYS_MAXSYSCALL; i++) {
  189                 if (sysent[i].sy_auevent != AUE_NULL)
  190                         au_evclassmap_insert(sysent[i].sy_auevent, 0);
  191         }
  192 }
  193 
  194 /*
  195  * Look up the name for an audit event in the event-to-name mapping table.
  196  */
  197 int
  198 au_event_name(au_event_t event, char *name)
  199 {
  200         struct evname_list *enl;
  201         struct evname_elem *ene;
  202         int error;
  203 
  204         error = ENOENT;
  205         EVNAMEMAP_RLOCK();
  206         enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE];
  207         LIST_FOREACH(ene, &enl->enl_head, ene_entry) {
  208                 if (ene->ene_event == event) {
  209                         strlcpy(name, ene->ene_name, EVNAMEMAP_NAME_SIZE);
  210                         error = 0;
  211                         goto out;
  212                 }
  213         }
  214 out:
  215         EVNAMEMAP_RUNLOCK();
  216         return (error);
  217 }
  218 
  219 /*
  220  * Insert a event-to-name mapping.  If the event already exists in the
  221  * mapping, then replace the mapping with the new one.
  222  *
  223  * XXX There is currently no constraints placed on the number of mappings.
  224  * May want to either limit to a number, or in terms of memory usage.
  225  *
  226  * XXXRW: Accepts truncated name -- but perhaps should return failure instead?
  227  *
  228  * XXXRW: It could be we need a way to remove existing names...?
  229  *
  230  * XXXRW: We handle collisions between numbers, but I wonder if we also need a
  231  * way to handle name collisions, for DTrace, where probe names must be
  232  * unique?
  233  */
  234 void
  235 au_evnamemap_insert(au_event_t event, const char *name)
  236 {
  237         struct evname_list *enl;
  238         struct evname_elem *ene, *ene_new;
  239 
  240         /*
  241          * Pessimistically, always allocate storage before acquiring lock.
  242          * Free if there is already a mapping for this event.
  243          */
  244         ene_new = malloc(sizeof(*ene_new), M_AUDITEVNAME, M_WAITOK | M_ZERO);
  245         EVNAMEMAP_WLOCK();
  246         enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE];
  247         LIST_FOREACH(ene, &enl->enl_head, ene_entry) {
  248                 if (ene->ene_event == event) {
  249                         EVNAME_LOCK(ene);
  250                         (void)strlcpy(ene->ene_name, name,
  251                             sizeof(ene->ene_name));
  252                         EVNAME_UNLOCK(ene);
  253                         EVNAMEMAP_WUNLOCK();
  254                         free(ene_new, M_AUDITEVNAME);
  255                         return;
  256                 }
  257         }
  258         ene = ene_new;
  259         mtx_init(&ene->ene_lock, "au_evnamemap", NULL, MTX_DEF);
  260         ene->ene_event = event;
  261         (void)strlcpy(ene->ene_name, name, sizeof(ene->ene_name));
  262         LIST_INSERT_HEAD(&enl->enl_head, ene, ene_entry);
  263         EVNAMEMAP_WUNLOCK();
  264 }
  265 
  266 /*
  267  * If /etc/security/audit_event has been preloaded by the boot loader, parse
  268  * it to build an initial set of event number<->name mappings.
  269  */
  270 static void
  271 au_evnamemap_init_preload(void)
  272 {
  273         caddr_t kmdp;
  274         char *endptr, *line, *nextline, *ptr;
  275         const char *evnum_str, *evname;
  276         size_t size;
  277         long evnum;
  278         u_int lineno;
  279 
  280         kmdp = preload_search_by_type(EVNAMEMAP_HASH_TABLE_MODULE);
  281         if (kmdp == NULL)
  282                 return;
  283         ptr = preload_fetch_addr(kmdp);
  284         size = preload_fetch_size(kmdp);
  285 
  286         /*
  287          * Parse preloaded configuration file "in place".  Assume that the
  288          * last character is a new line, meaning that we can replace it with a
  289          * nul byte safely.  We can then use strsep(3) to process the full
  290          * buffer.
  291          */
  292         ptr[size - 1] = '\0';
  293 
  294         /*
  295          * Process line by line.
  296          */
  297         nextline = ptr;
  298         lineno = 0;
  299         while ((line = strsep(&nextline, "\n")) != NULL) {
  300                 /*
  301                  * Skip any leading white space.
  302                  */
  303                 while (line[0] == ' ' || line[0] == '\t')
  304                         line++;
  305 
  306                 /*
  307                  * Skip blank lines and comment lines.
  308                  */
  309                 if (line[0] == '\0' || line[0] == '#') {
  310                         lineno++;
  311                         continue;
  312                 }
  313 
  314                 /*
  315                  * Parse each line -- ":"-separated tuple of event number,
  316                  * event name, and other material we are less interested in.
  317                  */
  318                 evnum_str = strsep(&line, ":");
  319                 if (evnum_str == NULL || *evnum_str == '\0') {
  320                         printf("%s: Invalid line %u - evnum strsep\n",
  321                             __func__, lineno);
  322                         lineno++;
  323                         continue;
  324                 }
  325                 evnum = strtol(evnum_str, &endptr, 10);
  326                 if (*evnum_str == '\0' || *endptr != '\0' ||
  327                     evnum <= 0 || evnum > UINT16_MAX) {
  328                         printf("%s: Invalid line %u - evnum strtol\n",
  329                             __func__, lineno);
  330                         lineno++;
  331                         continue;
  332                 }
  333                 evname = strsep(&line, ":");
  334                 if (evname == NULL || *evname == '\0') {
  335                         printf("%s: Invalid line %u - evname strsp\n",
  336                             __func__, lineno);
  337                         lineno++;
  338                         continue;
  339                 }
  340                 au_evnamemap_insert(evnum, evname);
  341                 lineno++;
  342         }
  343 }
  344 
  345 void
  346 au_evnamemap_init(void)
  347 {
  348         int i;
  349 
  350         EVNAMEMAP_LOCK_INIT();
  351         for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++)
  352                 LIST_INIT(&evnamemap_hash[i].enl_head);
  353         au_evnamemap_init_preload();
  354 }
  355 
  356 /*
  357  * The DTrace audit provider occasionally needs to walk the entries in the
  358  * event-to-name mapping table, and uses this public interface to do so.  A
  359  * write lock is acquired so that the provider can safely update its fields in
  360  * table entries.
  361  */
  362 void
  363 au_evnamemap_foreach(au_evnamemap_callback_t callback)
  364 {
  365         struct evname_list *enl;
  366         struct evname_elem *ene;
  367         int i;
  368 
  369         EVNAMEMAP_WLOCK();
  370         for (i = 0; i < EVNAMEMAP_HASH_TABLE_SIZE; i++) {
  371                 enl = &evnamemap_hash[i];
  372                 LIST_FOREACH(ene, &enl->enl_head, ene_entry)
  373                         callback(ene);
  374         }
  375         EVNAMEMAP_WUNLOCK();
  376 }
  377 
  378 #ifdef KDTRACE_HOOKS
  379 /*
  380  * Look up an event-to-name mapping table entry by event number.  As evname
  381  * elements are stable in memory, we can return the pointer without the table
  382  * lock held -- but the caller will need to lock the element mutex before
  383  * accessing element fields.
  384  *
  385  * NB: the event identifier in elements is stable and can be read without
  386  * holding the evname_elem lock.
  387  */
  388 struct evname_elem *
  389 au_evnamemap_lookup(au_event_t event)
  390 {
  391         struct evname_list *enl;
  392         struct evname_elem *ene;
  393 
  394         EVNAMEMAP_RLOCK();
  395         enl = &evnamemap_hash[event % EVNAMEMAP_HASH_TABLE_SIZE];
  396         LIST_FOREACH(ene, &enl->enl_head, ene_entry) {
  397                 if (ene->ene_event == event)
  398                         goto out;
  399         }
  400         ene = NULL;
  401 out:
  402         EVNAMEMAP_RUNLOCK();
  403         return (ene);
  404 }
  405 #endif /* !KDTRACE_HOOKS */

Cache object: c7a6817eee3d01dd76d418e5c7709561


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