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_dtrace.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) 2016, 2018 Robert N. M. Watson
    3  * All rights reserved.
    4  *
    5  * This software was developed by BAE Systems, the University of Cambridge
    6  * Computer Laboratory, and Memorial University under DARPA/AFRL contract
    7  * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
    8  * (TC) research program.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <sys/param.h>
   36 #include <sys/conf.h>
   37 #include <sys/ctype.h>
   38 #include <sys/kernel.h>
   39 #include <sys/malloc.h>
   40 #include <sys/module.h>
   41 #include <sys/queue.h>
   42 #include <sys/refcount.h>
   43 
   44 #include <sys/dtrace.h>
   45 #include <sys/dtrace_bsd.h>
   46 
   47 #include <bsm/audit.h>
   48 #include <bsm/audit_internal.h>
   49 #include <bsm/audit_kevents.h>
   50 
   51 #include <security/audit/audit.h>
   52 #include <security/audit/audit_private.h>
   53 
   54 /*-
   55  * Audit DTrace provider: allow DTrace to request that audit records be
   56  * generated for various audit events, and then expose those records (in
   57  * various forms) to probes.  The model is that each event type has two
   58  * probes, which use the event's name to create the probe:
   59  *
   60  * - "commit" passes the kernel-internal (unserialised) kaudit_record
   61  *   synchronously (from the originating thread) of the record as we prepare
   62  *   to "commit" the record to the audit queue.
   63  *
   64  * - "bsm" also passes generated BSM, and executes asynchronously in the audit
   65  *   worker thread, once it has been extracted from the audit queue.  This is
   66  *   the point at which an audit record would be enqueued to the trail on
   67  *   disk, or to pipes.
   68  *
   69  * These probes support very different goals.  The former executes in the
   70  * thread originating the record, making it easier to correlate other DTrace
   71  * probe activity with the event described in the record.  The latter gives
   72  * access to BSM-formatted events (at a cost) allowing DTrace to extract BSM
   73  * directly an alternative mechanism to the formal audit trail and audit
   74  * pipes.
   75  *
   76  * To generate names for numeric event IDs, userspace will push the contents
   77  * of /etc/security/audit_event into the kernel during audit setup, much as it
   78  * does /etc/security/audit_class.  We then create the probes for each of
   79  * those mappings.  If one (or both) of the probes are enabled, then we cause
   80  * a record to be generated (as both normal audit preselection and audit pipes
   81  * do), and catch it on the way out during commit.  There are suitable hook
   82  * functions in the audit code that this provider can register to catch
   83  * various events in the audit-record life cycle.
   84  *
   85  * Further ponderings:
   86  *
   87  * - How do we want to handle events for which there are not names -- perhaps
   88  *   a catch-all probe for those events without mappings?
   89  *
   90  * - Should the evname code really be present even if DTrace isn't loaded...?
   91  *   Right now, we arrange that it is so that userspace can usefully maintain
   92  *   the list in case DTrace is later loaded (and to prevent userspace
   93  *   confusion).
   94  *
   95  * - Should we add an additional set of audit:class::commit probes that use
   96  *   event class names to match broader categories of events as specified in
   97  *   /etc/security/event_class?
   98  *
   99  * - If we pursue that last point, we will want to pass the name of the event
  100  *   into the probe explicitly (e.g., as arg0), since it would no longer be
  101  *   available as the probe function name.
  102  */
  103 
  104 static int      dtaudit_unload(void);
  105 static void     dtaudit_getargdesc(void *, dtrace_id_t, void *,
  106                     dtrace_argdesc_t *);
  107 static void     dtaudit_provide(void *, dtrace_probedesc_t *);
  108 static void     dtaudit_destroy(void *, dtrace_id_t, void *);
  109 static void     dtaudit_enable(void *, dtrace_id_t, void *);
  110 static void     dtaudit_disable(void *, dtrace_id_t, void *);
  111 static void     dtaudit_load(void *);
  112 
  113 static dtrace_pattr_t dtaudit_attr = {
  114 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
  115 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
  116 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
  117 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
  118 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
  119 };
  120 
  121 /*
  122  * Strings for the "module" and "name" portions of the probe.  The name of the
  123  * audit event will be the "function" portion of the probe.  All dtaudit
  124  * probes therefore take the form audit:event:<event name>:commit.
  125  */
  126 static char     *dtaudit_module_str = "event";
  127 static char     *dtaudit_name_commit_str = "commit";
  128 static char     *dtaudit_name_bsm_str = "bsm";
  129 
  130 static dtrace_pops_t dtaudit_pops = {
  131         .dtps_provide =         dtaudit_provide,
  132         .dtps_provide_module =  NULL,
  133         .dtps_enable =          dtaudit_enable,
  134         .dtps_disable =         dtaudit_disable,
  135         .dtps_suspend =         NULL,
  136         .dtps_resume =          NULL,
  137         .dtps_getargdesc =      dtaudit_getargdesc,
  138         .dtps_getargval =       NULL,
  139         .dtps_usermode =        NULL,
  140         .dtps_destroy =         dtaudit_destroy
  141 };
  142 
  143 static dtrace_provider_id_t     dtaudit_id;
  144 
  145 /*
  146  * Because looking up entries in the event-to-name mapping is quite expensive,
  147  * maintain a global flag tracking whether any dtaudit probes are enabled.  If
  148  * not, don't bother doing all that work whenever potential queries about
  149  * events turn up during preselection or commit.
  150  *
  151  * NB: We used to maintain our own variable in dtaudit, but now use the
  152  * centralized audit_dtrace_enabled variable imported from the audit code.
  153  *
  154  * static uint_t                dtaudit_probes_enabled;
  155  */
  156 
  157 /*
  158  * Check dtaudit policy for the event to see whether this is an event we would
  159  * like to preselect (i.e., cause an audit record to be generated for).  To
  160  * minimise probe effect when not used at all, we not only check for the probe
  161  * on the individual event, but also a global flag indicating that at least
  162  * one probe is enabled, before acquiring locks, searching lists, etc.
  163  *
  164  * If the event is selected, return an evname_elem reference to be stored in
  165  * the audit record, which we can use later to avoid further lookups.  The
  166  * contents of the evname_elem must be sufficiently stable so as to not risk
  167  * race conditions here.
  168  *
  169  * Currently, we take an interest only in the 'event' argument, but in the
  170  * future might want to support other types of record selection tied to
  171  * additional probe types (e.g., event clases).
  172  *
  173  * XXXRW: Should we have a catch-all probe here for events without registered
  174  * names?
  175  */
  176 static void *
  177 dtaudit_preselect(au_id_t auid, au_event_t event, au_class_t class)
  178 {
  179         struct evname_elem *ene;
  180         int probe_enabled;
  181 
  182         /*
  183          * NB: Lockless reads here may return a slightly stale value; this is
  184          * considered better than acquiring a lock, however.
  185          */
  186         if (!audit_dtrace_enabled)
  187                 return (NULL);
  188         ene = au_evnamemap_lookup(event);
  189         if (ene == NULL)
  190                 return (NULL);
  191 
  192         /*
  193          * See if either of the two probes for the audit event are enabled.
  194          *
  195          * NB: Lock also not acquired here -- but perhaps it wouldn't matter
  196          * given that we've already used the list lock above?
  197          *
  198          * XXXRW: Alternatively, au_evnamemap_lookup() could return these
  199          * values while holding the list lock...?
  200          */
  201         probe_enabled = ene->ene_commit_probe_enabled ||
  202             ene->ene_bsm_probe_enabled;
  203         if (!probe_enabled)
  204                 return (NULL);
  205         return ((void *)ene);
  206 }
  207 
  208 /*
  209  * Commit probe pre-BSM.  Fires the probe but also checks to see if we should
  210  * ask the audit framework to call us again with BSM arguments in the audit
  211  * worker thread.
  212  *
  213  * XXXRW: Should we have a catch-all probe here for events without registered
  214  * names?
  215  */
  216 static int
  217 dtaudit_commit(struct kaudit_record *kar, au_id_t auid, au_event_t event,
  218     au_class_t class, int sorf)
  219 {
  220         char ene_name_lower[EVNAMEMAP_NAME_SIZE];
  221         struct evname_elem *ene;
  222         int i;
  223 
  224         ene = (struct evname_elem *)kar->k_dtaudit_state;
  225         if (ene == NULL)
  226                 return (0);
  227 
  228         /*
  229          * Process a possibly registered commit probe.
  230          */
  231         if (ene->ene_commit_probe_enabled) {
  232                 /*
  233                  * XXXRW: Lock ene to provide stability to the name string.  A
  234                  * bit undesirable!  We may want another locking strategy
  235                  * here.  At least we don't run the DTrace probe under the
  236                  * lock.
  237                  *
  238                  * XXXRW: We provide the struct audit_record pointer -- but
  239                  * perhaps should provide the kaudit_record pointer?
  240                  */
  241                 EVNAME_LOCK(ene);
  242                 for (i = 0; i < sizeof(ene_name_lower); i++)
  243                         ene_name_lower[i] = tolower(ene->ene_name[i]);
  244                 EVNAME_UNLOCK(ene);
  245                 dtrace_probe(ene->ene_commit_probe_id,
  246                     (uintptr_t)ene_name_lower, (uintptr_t)&kar->k_ar, 0, 0, 0);
  247         }
  248 
  249         /*
  250          * Return the state of the BSM probe to the caller.
  251          */
  252         return (ene->ene_bsm_probe_enabled);
  253 }
  254 
  255 /*
  256  * Commit probe post-BSM.
  257  *
  258  * XXXRW: Should we have a catch-all probe here for events without registered
  259  * names?
  260  */
  261 static void
  262 dtaudit_bsm(struct kaudit_record *kar, au_id_t auid, au_event_t event,
  263     au_class_t class, int sorf, void *bsm_data, size_t bsm_len)
  264 {
  265         char ene_name_lower[EVNAMEMAP_NAME_SIZE];
  266         struct evname_elem *ene;
  267         int i;
  268 
  269         ene = (struct evname_elem *)kar->k_dtaudit_state;
  270         if (ene == NULL)
  271                 return;
  272         if (!(ene->ene_bsm_probe_enabled))
  273                 return;
  274 
  275         /*
  276          * XXXRW: Lock ene to provide stability to the name string.  A bit
  277          * undesirable!  We may want another locking strategy here.  At least
  278          * we don't run the DTrace probe under the lock.
  279          *
  280          * XXXRW: We provide the struct audit_record pointer -- but perhaps
  281          * should provide the kaudit_record pointer?
  282          */
  283         EVNAME_LOCK(ene);
  284         for (i = 0; i < sizeof(ene_name_lower); i++)
  285                 ene_name_lower[i] = tolower(ene->ene_name[i]);
  286         EVNAME_UNLOCK(ene);
  287         dtrace_probe(ene->ene_bsm_probe_id, (uintptr_t)ene_name_lower,
  288             (uintptr_t)&kar->k_ar, (uintptr_t)bsm_data, (uintptr_t)bsm_len,
  289             0);
  290 }
  291 
  292 /*
  293  * A very simple provider: argument types are identical across all probes: the
  294  * kaudit_record, plus a BSM pointer and length.
  295  */
  296 static void
  297 dtaudit_getargdesc(void *arg, dtrace_id_t id, void *parg,
  298     dtrace_argdesc_t *desc)
  299 {
  300         struct evname_elem *ene;
  301         const char *p;
  302 
  303         ene = (struct evname_elem *)parg;
  304         p = NULL;
  305         switch (desc->dtargd_ndx) {
  306         case 0:
  307                 /* Audit event name. */
  308                 p = "char *";
  309                 break;
  310 
  311         case 1:
  312                 /* In-kernel audit record. */
  313                 p = "struct audit_record *";
  314                 break;
  315 
  316         case 2:
  317                 /* BSM data, if present. */
  318                 if (id == ene->ene_bsm_probe_id)
  319                         p = "const void *";
  320                 else
  321                         desc->dtargd_ndx = DTRACE_ARGNONE;
  322                 break;
  323 
  324         case 3:
  325                 /* BSM length, if present. */
  326                 if (id == ene->ene_bsm_probe_id)
  327                         p = "size_t";
  328                 else
  329                         desc->dtargd_ndx = DTRACE_ARGNONE;
  330                 break;
  331 
  332         default:
  333                 desc->dtargd_ndx = DTRACE_ARGNONE;
  334                 break;
  335         }
  336         if (p != NULL)
  337                 strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
  338 }
  339 
  340 /*
  341  * Callback from the event-to-name mapping code when performing
  342  * evname_foreach().  Note that we may update the entry, so the foreach code
  343  * must have a write lock.  However, as the synchronisation model is private
  344  * to the evname code, we cannot easily assert it here.
  345  *
  346  * XXXRW: How do we want to handle event rename / collision issues here --
  347  * e.g., if userspace was using a name to point to one event number, and then
  348  * changes it so that the name points at another?  For now, paper over this by
  349  * skipping event numbers that are already registered, and likewise skipping
  350  * names that are already registered.  However, this could lead to confusing
  351  * behaviour so possibly needs to be resolved in the longer term.
  352  */
  353 static void
  354 dtaudit_au_evnamemap_callback(struct evname_elem *ene)
  355 {
  356         char ene_name_lower[EVNAMEMAP_NAME_SIZE];
  357         int i;
  358 
  359         /*
  360          * DTrace, by convention, has lower-case probe names.  However, the
  361          * in-kernel event-to-name mapping table must maintain event-name case
  362          * as submitted by userspace.  Create a temporary lower-case version
  363          * here, away from the fast path, to use when exposing the event name
  364          * to DTrace as part of the name of a probe.
  365          *
  366          * NB: Convert the entire array, including the terminating nul,
  367          * because these strings are short and it's more work not to.  If they
  368          * become long, we might feel more guilty about this sloppiness!
  369          */
  370         for (i = 0; i < sizeof(ene_name_lower); i++)
  371                 ene_name_lower[i] = tolower(ene->ene_name[i]);
  372 
  373         /*
  374          * Don't register a new probe if this event number already has an
  375          * associated commit probe -- or if another event has already
  376          * registered this name.
  377          *
  378          * XXXRW: There is an argument that if multiple numeric events match
  379          * a single name, they should all be exposed to the same named probe.
  380          * In particular, we should perhaps use a probe ID returned by this
  381          * lookup and just stick that in the saved probe ID?
  382          */
  383         if ((ene->ene_commit_probe_id == 0) &&
  384             (dtrace_probe_lookup(dtaudit_id, dtaudit_module_str,
  385             ene_name_lower, dtaudit_name_commit_str) == 0)) {
  386                 /*
  387                  * Create the commit probe.
  388                  *
  389                  * NB: We don't declare any extra stack frames because stack()
  390                  * will just return the path to the audit commit code, which
  391                  * is not really interesting anyway.
  392                  *
  393                  * We pass in the pointer to the evnam_elem entry so that we
  394                  * can easily change its enabled flag in the probe
  395                  * enable/disable interface.
  396                  */
  397                 ene->ene_commit_probe_id = dtrace_probe_create(dtaudit_id,
  398                     dtaudit_module_str, ene_name_lower,
  399                     dtaudit_name_commit_str, 0, ene);
  400         }
  401 
  402         /*
  403          * Don't register a new probe if this event number already has an
  404          * associated bsm probe -- or if another event has already
  405          * registered this name.
  406          *
  407          * XXXRW: There is an argument that if multiple numeric events match
  408          * a single name, they should all be exposed to the same named probe.
  409          * In particular, we should perhaps use a probe ID returned by this
  410          * lookup and just stick that in the saved probe ID?
  411          */
  412         if ((ene->ene_bsm_probe_id == 0) &&
  413             (dtrace_probe_lookup(dtaudit_id, dtaudit_module_str,
  414             ene_name_lower, dtaudit_name_bsm_str) == 0)) {
  415                 /*
  416                  * Create the bsm probe.
  417                  *
  418                  * NB: We don't declare any extra stack frames because stack()
  419                  * will just return the path to the audit commit code, which
  420                  * is not really interesting anyway.
  421                  *
  422                  * We pass in the pointer to the evnam_elem entry so that we
  423                  * can easily change its enabled flag in the probe
  424                  * enable/disable interface.
  425                  */
  426                 ene->ene_bsm_probe_id = dtrace_probe_create(dtaudit_id,
  427                     dtaudit_module_str, ene_name_lower, dtaudit_name_bsm_str,
  428                     0, ene);
  429         }
  430 }
  431 
  432 static void
  433 dtaudit_provide(void *arg, dtrace_probedesc_t *desc)
  434 {
  435 
  436         /*
  437          * Walk all registered number-to-name mapping entries, and ensure each
  438          * is properly registered.
  439          */
  440         au_evnamemap_foreach(dtaudit_au_evnamemap_callback);
  441 }
  442 
  443 static void
  444 dtaudit_destroy(void *arg, dtrace_id_t id, void *parg)
  445 {
  446 }
  447 
  448 static void
  449 dtaudit_enable(void *arg, dtrace_id_t id, void *parg)
  450 {
  451         struct evname_elem *ene;
  452 
  453         ene = parg;
  454         KASSERT(ene->ene_commit_probe_id == id || ene->ene_bsm_probe_id == id,
  455             ("%s: probe ID mismatch (%u, %u != %u)", __func__,
  456             ene->ene_commit_probe_id, ene->ene_bsm_probe_id, id));
  457 
  458         if (id == ene->ene_commit_probe_id)
  459                 ene->ene_commit_probe_enabled = 1;
  460         else
  461                 ene->ene_bsm_probe_enabled = 1;
  462         refcount_acquire(&audit_dtrace_enabled);
  463         audit_syscalls_enabled_update();
  464 }
  465 
  466 static void
  467 dtaudit_disable(void *arg, dtrace_id_t id, void *parg)
  468 {
  469         struct evname_elem *ene;
  470 
  471         ene = parg;
  472         KASSERT(ene->ene_commit_probe_id == id || ene->ene_bsm_probe_id == id,
  473             ("%s: probe ID mismatch (%u, %u != %u)", __func__,
  474             ene->ene_commit_probe_id, ene->ene_bsm_probe_id, id));
  475 
  476         if (id == ene->ene_commit_probe_id)
  477                 ene->ene_commit_probe_enabled = 0;
  478         else
  479                 ene->ene_bsm_probe_enabled = 0;
  480         (void)refcount_release(&audit_dtrace_enabled);
  481         audit_syscalls_enabled_update();
  482 }
  483 
  484 static void
  485 dtaudit_load(void *dummy)
  486 {
  487 
  488         if (dtrace_register("audit", &dtaudit_attr, DTRACE_PRIV_USER, NULL,
  489             &dtaudit_pops, NULL, &dtaudit_id) != 0)
  490                 return;
  491         dtaudit_hook_preselect = dtaudit_preselect;
  492         dtaudit_hook_commit = dtaudit_commit;
  493         dtaudit_hook_bsm = dtaudit_bsm;
  494 }
  495 
  496 static int
  497 dtaudit_unload(void)
  498 {
  499         int error;
  500 
  501         dtaudit_hook_preselect = NULL;
  502         dtaudit_hook_commit = NULL;
  503         dtaudit_hook_bsm = NULL;
  504         if ((error = dtrace_unregister(dtaudit_id)) != 0)
  505                 return (error);
  506         return (0);
  507 }
  508 
  509 static int
  510 dtaudit_modevent(module_t mod __unused, int type, void *data __unused)
  511 {
  512         int error = 0;
  513 
  514         switch (type) {
  515         case MOD_LOAD:
  516         case MOD_UNLOAD:
  517         case MOD_SHUTDOWN:
  518                 break;
  519 
  520         default:
  521                 error = EOPNOTSUPP;
  522                 break;
  523         }
  524 
  525         return (error);
  526 }
  527 
  528 SYSINIT(dtaudit_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtaudit_load,
  529     NULL);
  530 SYSUNINIT(dtaudit_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
  531     dtaudit_unload, NULL);
  532 
  533 DEV_MODULE(dtaudit, dtaudit_modevent, NULL);
  534 MODULE_VERSION(dtaudit, 1);
  535 MODULE_DEPEND(dtaudit, dtrace, 1, 1, 1);
  536 MODULE_DEPEND(dtaudit, opensolaris, 1, 1, 1);

Cache object: 80175fcf3cc0538ca6ab0af67703fa85


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