audit.c revision 2a8d6eba033e4713ab12b61178f0513f1f075482
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Audit interfaces. Auditing can be enabled in two ways:
*
* o Using the LD_AUDIT environment variable
*
* o From individual objects containing a DT_DEPAUDIT entry
* (see ld(1) -P/-p options).
*
* The former establishes a global set of audit libraries which can inspect all
* objects from a given process. The latter establishes a local set of audit
* libraries which can inspect the immediate dependencies of the caller.
*
* Audit library capabilities are indicated by flags within the link-map list
* header (for global auditing), see LML_TFLG_AUD_* flags, or by the same flags
* within the individual link-map (for local auditing). Although both sets of
* flags can occur in different data items they are defined as one to simplify
* audit interface requirements. The basic test for all audit interfaces is:
*
* if (((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK) &&
* (lml == LIST(lmp)))
*
* The latter link-map list equivalence test insures that auditors themselves
* (invoked through DT_DEPAUDIT) are not audited.
*/
#include <stdio.h>
#include <stdio.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <string.h>
#include <debug.h>
#include "_rtld.h"
#include "_audit.h"
#include "_elf.h"
#include "msg.h"
/* simplify boot_elf.s access. */
static Audit_client *
{
int ndx;
return (NULL);
}
return (NULL);
}
/*
* la_filter() caller. Traverse through all audit libraries and call any
* la_filter() entry points found. A zero return from an auditor indicates
* that the filtee should be ignored.
*/
static int
{
continue;
continue;
continue;
return (0);
(void) enter(thr_flg_reenter);
}
return (1);
}
int
{
if (rt_critical())
return (respond);
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (appl)
rtld_flags &= ~RT_FL_APPLIC;
return (respond);
}
/*
* la_objsearch() caller. Traverse through all audit libraries and call any
* la_objsearch() entry points found.
*
* Effectively any audit library can change the name we're working with, so we
* continue to propagate the new name to each audit library. Any 0 return
* terminates the search.
*/
static char *
{
continue;
continue;
(void) enter(thr_flg_reenter);
break;
}
return (nname);
}
char *
{
int appl = 0;
if (rt_critical())
return (nname);
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (appl)
rtld_flags &= ~RT_FL_APPLIC;
return (nname);
}
/*
* la_activity() caller. Traverse through all audit libraries and call any
* la_activity() entry points found.
*/
static void
{
if (alp->al_activity == 0)
continue;
continue;
/*
* at a time. This ensures the library doesn't see numerous
* events from lazy loading a series of libraries. Keep track
* of this caller having called an auditor, so that the
* appropriate "consistent" event can be supplied on leaving
* ld.so.1.
*/
continue;
AL_CNT_ACTAUDIT) == NULL)
return;
} else {
continue;
}
(void) enter(thr_flg_reenter);
}
}
void
{
int appl = 0;
if (rt_critical())
return;
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (appl)
rtld_flags &= ~RT_FL_APPLIC;
}
/*
* la_objopen() caller. Create an audit information structure for the indicated
* link-map, regardless of an la_objopen() entry point. This structure is used
* to supply information to various audit interfaces (see LML_MSK_AUDINFO).
* Traverse through all audit library and call any la_objopen() entry points
* found.
*/
static int
int *ndx)
{
/*
* Associate a cookie with the audit library, and assign the
* initial cookie as the present link-map.
*/
continue;
(void) enter(thr_flg_reenter);
if (flags & LA_FLG_BINDTO)
if (flags & LA_FLG_BINDFROM) {
/*
* pltexit() entry point exist in one of our auditing
* libraries.
*/
continue;
/*
* Create one dynplt for every 'PLT' that exists in the
* object.
*/
dyn_plt_ent_size)) == NULL)
return (0);
}
}
return (1);
}
int
{
if (rt_critical())
return (respond);
/*
* Determine the total number of audit libraries in use. This provides
* the number of client structures required for this object.
*/
if (auditors)
/*
* The initial allocation of the audit information structure includes
* an array of audit clients, 1 per audit library presently available.
*
* ---------------
* | ai_cnt |
* Audit_info | ai_clients |-------
* | ai_dynplts | |
* |---------------| |
* Audit_client | 1 |<------
* |---------------|
* | 2 |
* .........
*/
return (0);
sizeof (Audit_info));
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (auditors)
if (appl)
rtld_flags &= ~RT_FL_APPLIC;
return (respond);
}
/*
* la_objclose() caller. Traverse through all audit library and call any
* la_objclose() entry points found.
*/
void
{
continue;
continue;
(void) enter(thr_flg_reenter);
}
}
void
{
int appl = 0;
if (rt_critical())
return;
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (appl)
rtld_flags &= ~RT_FL_APPLIC;
}
/*
* la_pltenter() caller. Traverse through all audit library and call any
* la_pltenter() entry points found. NOTE: this routine is called via the
* glue code established in elf_plt_trace_write(), the symbol descriptor is
* created as part of the glue and for 32bit environments the st_name is a
* pointer to the real symbol name (ie. it's already been adjusted with the
* objects base offset). For 64bit environments the st_name remains the
* original symbol offset and in this case it is used to compute the real name
* pointer and pass as a separate argument to the auditor.
*/
static void
{
#if defined(_ELF64)
#else
#endif
if (alp->al_pltenter == 0)
continue;
continue;
continue;
continue;
/* BEGIN CSTYLED */
#if defined(_ELF64)
#else
flags);
#endif
/* END CSTYLED */
(void) enter(thr_flg_reenter);
}
}
{
int _appl = 0;
if (rt_critical())
/*
* We're effectively entering ld.so.1 from user (glue) code.
*/
(void) enter(0);
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (_appl)
rtld_flags &= ~RT_FL_APPLIC;
}
/*
* la_pltexit() caller. Traverse through all audit library and call any
* la_pltexit() entry points found. See notes above (_audit_pltenter) for
* discussion on st_name.
*/
static Addr
{
#if defined(_ELF64)
#endif
if (alp->al_pltexit == 0)
continue;
continue;
continue;
continue;
/* BEGIN CSTYLED */
#if defined(_ELF64)
#else
retval);
#endif
/* END CSTYLED */
(void) enter(thr_flg_reenter);
}
return (retval);
}
{
int _appl = 0;
if (rt_critical())
return (_retval);
/*
* We're effectively entering ld.so.1 from user (glue) code.
*/
(void) enter(0);
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (_appl)
rtld_flags &= ~RT_FL_APPLIC;
return (_retval);
}
/*
* la_symbind() caller. Traverse through all audit library and call any
* la_symbind() entry points found.
*/
static Addr
{
#if defined(_ELF64)
#else
#endif
if (alp->al_symbind == 0)
continue;
continue;
continue;
continue;
/*
* The la_symbind interface is only called when the calling
* object has been identified as BINDFROM, and the destination
* object has been identified as BINDTO. Use a local version of
* the flags, so that any user update can be collected.
*/
called++;
/* BEGIN CSTYLED */
#if defined(_ELF64)
#else
&lflags);
#endif
/* END CSTYLED */
(void) enter(thr_flg_reenter);
/*
* If the auditor indicated that they did not want to process
* pltenter, or pltexit audits for this symbol, retain this
* information. Also retain whether an alternative symbol value
* has been supplied.
*/
*flags |= LA_SYMB_ALTVALUE;
}
}
{
/*
* Construct a new symbol from that supplied but with the real address.
* In the 64-bit world the st_name field is only 32-bits which isn't
* big enough to hold a character pointer. We pass this pointer as a
* separate parameter for 64-bit audit libraries.
*/
if (rt_critical())
#if !defined(_ELF64)
#endif
if ((rtld_flags & RT_FL_APPLIC) == 0)
/*
* If no la_symbind() was called for this interface, fabricate that no
* la_pltenter, or la_pltexit is required. This helps reduce the glue
* code created for further auditing.
*/
if (caller == 0)
if (_appl)
rtld_flags &= ~RT_FL_APPLIC;
}
/*
* la_preinit() caller. Traverse through all audit libraries and call any
* la_preinit() entry points found.
*/
static void
{
if (alp->al_preinit == 0)
continue;
continue;
(void) enter(thr_flg_reenter);
}
}
void
{
int appl = 0;
if (rt_critical())
return;
if ((rtld_flags & RT_FL_APPLIC) == 0)
if (appl)
rtld_flags &= ~RT_FL_APPLIC;
}
/*
* Clean up (free) an audit descriptor. First, gather a list of all handles,
* and then close each one down. This is done rather than using the handles
* directly from the auditors, as the audit list can be torn down as a result
* of the dlclose. In other words, what you're pointing at can be removed
* while your still pointing at it.
*/
void
{
return;
if (ghalp) {
}
}
}
/*
* Clean up (free) an audit information structure.
*/
void
{
return;
if (aip->ai_dynplts)
}
/*
* Create a data structure of symbol lookup names and associated flags to help
* simplify audit_symget() use.
*/
typedef struct {
} Aud_info;
{ MSG_SYM_LAVERSION, 0 }, /* MSG_ORIG(MSG_SYM_LAVERSION) */
{ MSG_SYM_LAPREINIT, /* MSG_ORIG(MSG_SYM_LAPREINIT) */
LML_TFLG_AUD_PREINIT, 0 },
{ MSG_SYM_LAOBJSEARCH, /* MSG_ORIG(MSG_SYM_LAOBJSEARCH) */
LML_TFLG_AUD_OBJSEARCH, 0 },
{ MSG_SYM_LAOBJOPEN, /* MSG_ORIG(MSG_SYM_LAOBJOPEN) */
LML_TFLG_AUD_OBJOPEN, 0 },
{ MSG_SYM_LAOBJFILTER, /* MSG_ORIG(MSG_SYM_LAOBJFILTER */
LML_TFLG_AUD_OBJFILTER, 0 },
{ MSG_SYM_LAOBJCLOSE, /* MSG_ORIG(MSG_SYM_LAOBJCLOSE) */
LML_TFLG_AUD_OBJCLOSE, 0 },
{ MSG_SYM_LAACTIVITY, /* MSG_ORIG(MSG_SYM_LAACTIVITY) */
LML_TFLG_AUD_ACTIVITY, 0 },
#if defined(_ELF64)
{ MSG_SYM_LASYMBIND_64, /* MSG_ORIG(MSG_SYM_LASYMBIND_64) */
#else
{ MSG_SYM_LASYMBIND, /* MSG_ORIG(MSG_SYM_LASYMBIND) */
#endif
LML_TFLG_AUD_SYMBIND, 0 },
#if defined(__sparcv9)
{ MSG_SYM_LAV9PLTENTER, /* MSG_ORIG(MSG_SYM_LAV9PLTENTER) */
{ MSG_SYM_LAV8PLTENTER, /* MSG_ORIG(MSG_SYM_LAV8PLTENTER) */
{ MSG_SYM_LAAMD64PLTENTER, /* MSG_ORIG(MSG_SYM_LAAMD64PLTENTER) */
{ MSG_SYM_LAX86PLTENTER, /* MSG_ORIG(MSG_SYM_LAX86PLTENTER) */
#else
#endif
#if defined(_ELF64)
{ MSG_SYM_LAPLTEXIT_64, /* MSG_ORIG(MSG_SYM_LAPLTEXIT_64) */
#else
{ MSG_SYM_LAPLTEXIT, /* MSG_ORIG(MSG_SYM_LAPLTEXIT) */
#endif
};
#define AI_LAVERSION 0
#define AI_LAPREINIT 1
#define AI_LAOBJSEARCH 2
#define AI_LAOBJOPEN 3
#define AI_LAOBJFILTER 4
#define AI_LAOBJCLOSE 5
#define AI_LAACTIVITY 6
#define AI_LASYMBIND 7
#define AI_LAPLTENTER 8
#define AI_LAPLTEXIT 9
static Addr
{
/*
* Initialize the symbol lookup data structure.
*/
0, 0, 0, 0, LKUP_FIRST);
if (alflag)
if (auflag)
audit_flags |= auflag;
return (addr);
} else
return (0);
}
/*
* Centralize cleanup routines.
*/
static int
{
if (ghp)
if (alp)
return (0);
}
/*
* Given a list of one or more audit libraries, open each one and establish a
* a descriptor representing the entry points it provides.
*/
int
{
int error = 1;
/*
* Mark that we have at least one auditing link map
*/
/*
* The audit definitions may be a list (which will already have been
* dupped) so split it into individual tokens.
*/
/*
* Open the audit library on its own link-map.
*/
continue;
}
/*
* If this auditor has already been loaded, reuse it.
*/
AL_CNT_AUDITORS) == NULL)
continue;
}
/*
* Prior to the Unified Process Model (UPM) environment, an
* rtld lock had to be held upon leave(). However, even within
* a UPM environment, an old auditor, that has a lazy dependency
* on libc, is still a possibility. As libc isn't loaded, we
* don't know the process model, and will determine this later.
* Refer to external.c:get_lcinterface().
*/
if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0)
/*
* Allocate an audit list descriptor for this object and
* search for all known entry points.
*/
/*
* All audit libraries must handshake through la_version().
* Determine that the symbol exists, finish initializing the
* object, and then call the function.
*/
AI_LAVERSION, in_nfavl)) == 0) {
continue;
}
rtld_flags &= ~RT_FL_APPLIC;
continue;
}
AL_CNT_AUDITORS) == NULL)
/*
* Collect any remaining entry points.
*/
/*
* Collect the individual object flags, and assign this audit
* list descriptor to its associated link-map list.
*/
}
/*
* Free the original audit string, as this descriptor may be used again
* to add additional auditing.
*/
return (error);
}