Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  *
     26  * Audit interfaces.  Auditing can be enabled in two ways:
     27  *
     28  *	o	Using the LD_AUDIT environment variable
     29  *
     30  *	o	From individual objects containing a DT_DEPAUDIT entry
     31  *		(see ld(1) -P/-p options).
     32  *
     33  * The former establishes a global set of audit libraries which can inspect all
     34  * objects from a given process.  The latter establishes a local set of audit
     35  * libraries which can inspect the immediate dependencies of the caller.
     36  *
     37  * Audit library capabilities are indicated by flags within the link-map list
     38  * header (for global auditing), see LML_TFLG_AUD_* flags, or by the same flags
     39  * within the individual link-map (for local auditing).  Although both sets of
     40  * flags can occur in different data items they are defined as one to simplify
     41  * audit interface requirements.  The basic test for all audit interfaces is:
     42  *
     43  *    if (((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK) &&
     44  *	(lml == LIST(lmp)))
     45  *
     46  * The latter link-map list equivalence test insures that auditors themselves
     47  * (invoked through DT_DEPAUDIT) are not audited.
     48  */
     49 
     50 #include	<stdio.h>
     51 #include	<sys/types.h>
     52 #include	<sys/lwp.h>
     53 #include	<stdio.h>
     54 #include	<stdarg.h>
     55 #include	<dlfcn.h>
     56 #include	<string.h>
     57 #include	<debug.h>
     58 #include	"_rtld.h"
     59 #include	"_audit.h"
     60 #include	"_elf.h"
     61 #include	"msg.h"
     62 
     63 uint_t	audit_flags = 0;		/* Copy of specific audit flags to */
     64 					/* simplify boot_elf.s access. */
     65 
     66 static Audit_client *
     67 _audit_client(Audit_info *aip, Rt_map *almp)
     68 {
     69 	int	ndx;
     70 
     71 	if (aip == NULL)
     72 		return (NULL);
     73 
     74 	for (ndx = 0; ndx < aip->ai_cnt; ndx++) {
     75 		if (aip->ai_clients[ndx].ac_lmp == almp)
     76 			return (&(aip->ai_clients[ndx]));
     77 	}
     78 	return (NULL);
     79 }
     80 
     81 /*
     82  * la_filter() caller.  Traverse through all audit libraries and call any
     83  * la_filter() entry points found.  A zero return from an auditor indicates
     84  * that the filtee should be ignored.
     85  */
     86 static int
     87 _audit_objfilter(APlist *list, Rt_map *frlmp, const char *ref, Rt_map *felmp,
     88     uint_t flags)
     89 {
     90 	Audit_list	*alp;
     91 	Aliste		idx;
     92 
     93 	for (APLIST_TRAVERSE(list, idx, alp)) {
     94 		Audit_client	*fracp, *feacp;
     95 
     96 		if (alp->al_objfilter == NULL)
     97 			continue;
     98 		if ((fracp = _audit_client(AUDINFO(frlmp),
     99 		    alp->al_lmp)) == NULL)
    100 			continue;
    101 		if ((feacp = _audit_client(AUDINFO(felmp),
    102 		    alp->al_lmp)) == NULL)
    103 			continue;
    104 
    105 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    106 		if ((*alp->al_objfilter)(&(fracp->ac_cookie), ref,
    107 		    &(feacp->ac_cookie), flags) == 0)
    108 			return (0);
    109 		(void) enter(thr_flg_reenter);
    110 	}
    111 	return (1);
    112 }
    113 
    114 int
    115 audit_objfilter(Rt_map *frlmp, const char *ref, Rt_map *felmp, uint_t flags)
    116 {
    117 	int	appl = 0, respond = 1;
    118 
    119 	if (rt_critical())
    120 		return (respond);
    121 
    122 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    123 		appl = rtld_flags |= RT_FL_APPLIC;
    124 
    125 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJFILTER))
    126 		respond = _audit_objfilter(auditors->ad_list, frlmp,
    127 		    ref, felmp, flags);
    128 	if (respond && AUDITORS(frlmp) &&
    129 	    (AUDITORS(frlmp)->ad_flags & LML_TFLG_AUD_OBJFILTER))
    130 		respond = _audit_objfilter(AUDITORS(frlmp)->ad_list, frlmp,
    131 		    ref, felmp, flags);
    132 
    133 	if (appl)
    134 		rtld_flags &= ~RT_FL_APPLIC;
    135 
    136 	return (respond);
    137 }
    138 
    139 /*
    140  * la_objsearch() caller.  Traverse through all audit libraries and call any
    141  * la_objsearch() entry points found.
    142  *
    143  * Effectively any audit library can change the name we're working with, so we
    144  * continue to propagate the new name to each audit library.  Any 0 return
    145  * terminates the search.
    146  */
    147 static char *
    148 _audit_objsearch(APlist *list, char *name, Rt_map *clmp, uint_t flags)
    149 {
    150 	Audit_list	*alp;
    151 	Aliste		idx;
    152 	char		*nname = (char *)name;
    153 
    154 	for (APLIST_TRAVERSE(list, idx, alp)) {
    155 		Audit_client	*acp;
    156 
    157 		if (alp->al_objsearch == NULL)
    158 			continue;
    159 		if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == NULL)
    160 			continue;
    161 
    162 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    163 		nname = (*alp->al_objsearch)(nname, &(acp->ac_cookie), flags);
    164 		(void) enter(thr_flg_reenter);
    165 		if (nname == NULL)
    166 			break;
    167 	}
    168 	return (nname);
    169 }
    170 
    171 char *
    172 audit_objsearch(Rt_map *clmp, const char *name, uint_t flags)
    173 {
    174 	char	*nname = (char *)name;
    175 	int	appl = 0;
    176 
    177 	if (rt_critical())
    178 		return (nname);
    179 
    180 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    181 		appl = rtld_flags |= RT_FL_APPLIC;
    182 
    183 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJSEARCH))
    184 		nname = _audit_objsearch(auditors->ad_list, nname,
    185 		    clmp, flags);
    186 	if (nname && AUDITORS(clmp) &&
    187 	    (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_OBJSEARCH))
    188 		nname = _audit_objsearch(AUDITORS(clmp)->ad_list, nname,
    189 		    clmp, flags);
    190 
    191 	if (appl)
    192 		rtld_flags &= ~RT_FL_APPLIC;
    193 
    194 	DBG_CALL(Dbg_libs_audit(LIST(clmp), name, nname));
    195 	return (nname);
    196 }
    197 
    198 /*
    199  * la_activity() caller.  Traverse through all audit libraries and call any
    200  * la_activity() entry points found.
    201  */
    202 static void
    203 _audit_activity(APlist *list, Rt_map *clmp, uint_t flags)
    204 {
    205 	Audit_list	*alp;
    206 	Aliste		idx;
    207 	Lm_list		*clml = LIST(clmp);
    208 
    209 	for (APLIST_TRAVERSE(list, idx, alp)) {
    210 		Audit_client	*acp;
    211 		Rt_map		*almp = alp->al_lmp;
    212 		Lm_list		*alml = LIST(almp);
    213 
    214 		if (alp->al_activity == 0)
    215 			continue;
    216 		if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == NULL)
    217 			continue;
    218 
    219 		/*
    220 		 * Make sure the audit library only sees one addition/deletion
    221 		 * at a time.  This ensures the library doesn't see numerous
    222 		 * events from lazy loading a series of libraries.  Keep track
    223 		 * of this caller having called an auditor, so that the
    224 		 * appropriate "consistent" event can be supplied on leaving
    225 		 * ld.so.1.
    226 		 */
    227 		if ((flags == LA_ACT_ADD) || (flags == LA_ACT_DELETE)) {
    228 
    229 			if (alml->lm_flags & LML_FLG_AUDITNOTIFY)
    230 				continue;
    231 
    232 			if (aplist_append(&clml->lm_actaudit, clmp,
    233 			    AL_CNT_ACTAUDIT) == NULL)
    234 				return;
    235 
    236 			alml->lm_flags |= LML_FLG_AUDITNOTIFY;
    237 
    238 		} else {
    239 			if ((alml->lm_flags & LML_FLG_AUDITNOTIFY) == 0)
    240 				continue;
    241 
    242 			alml->lm_flags &= ~LML_FLG_AUDITNOTIFY;
    243 		}
    244 
    245 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    246 		(*alp->al_activity)(&(acp->ac_cookie), flags);
    247 		(void) enter(thr_flg_reenter);
    248 	}
    249 }
    250 
    251 void
    252 audit_activity(Rt_map *clmp, uint_t flags)
    253 {
    254 	int	appl = 0;
    255 
    256 	if (rt_critical())
    257 		return;
    258 
    259 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    260 		appl = rtld_flags |= RT_FL_APPLIC;
    261 
    262 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_ACTIVITY))
    263 		_audit_activity(auditors->ad_list, clmp, flags);
    264 	if (AUDITORS(clmp) &&
    265 	    (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_ACTIVITY))
    266 		_audit_activity(AUDITORS(clmp)->ad_list, clmp, flags);
    267 
    268 	if (appl)
    269 		rtld_flags &= ~RT_FL_APPLIC;
    270 }
    271 
    272 /*
    273  * la_objopen() caller.  Create an audit information structure for the indicated
    274  * link-map, regardless of an la_objopen() entry point.  This structure is used
    275  * to supply information to various audit interfaces (see LML_MSK_AUDINFO).
    276  * Traverse through all audit library and call any la_objopen() entry points
    277  * found.
    278  */
    279 static int
    280 _audit_objopen(APlist *list, Rt_map *nlmp, Lmid_t lmid, Audit_info *aip,
    281     int *ndx)
    282 {
    283 	Audit_list	*alp;
    284 	Aliste		idx;
    285 
    286 	for (APLIST_TRAVERSE(list, idx, alp)) {
    287 		uint_t		flags;
    288 		Audit_client	*acp;
    289 
    290 		/*
    291 		 * Associate a cookie with the audit library, and assign the
    292 		 * initial cookie as the present link-map.
    293 		 */
    294 		acp = &aip->ai_clients[(*ndx)++];
    295 		acp->ac_lmp = alp->al_lmp;
    296 		acp->ac_cookie = (uintptr_t)nlmp;
    297 
    298 		if (alp->al_objopen == NULL)
    299 			continue;
    300 
    301 		DBG_CALL(Dbg_audit_object(LIST(alp->al_lmp), alp->al_libname,
    302 		    NAME(nlmp)));
    303 
    304 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    305 		flags = (*alp->al_objopen)((Link_map *)nlmp, lmid,
    306 		    &(acp->ac_cookie));
    307 		(void) enter(thr_flg_reenter);
    308 
    309 		if (flags & LA_FLG_BINDTO)
    310 			acp->ac_flags |= FLG_AC_BINDTO;
    311 
    312 		if (flags & LA_FLG_BINDFROM) {
    313 			ulong_t		pltcnt;
    314 
    315 			acp->ac_flags |= FLG_AC_BINDFROM;
    316 
    317 			/*
    318 			 * We only need dynamic plt's if a pltenter and/or a
    319 			 * pltexit() entry point exist in one of our auditing
    320 			 * libraries.
    321 			 */
    322 			if (aip->ai_dynplts || (JMPREL(nlmp) == 0) ||
    323 			    ((audit_flags & (AF_PLTENTER | AF_PLTEXIT)) == 0))
    324 				continue;
    325 
    326 			/*
    327 			 * Create one dynplt for every 'PLT' that exists in the
    328 			 * object.
    329 			 */
    330 			pltcnt = PLTRELSZ(nlmp) / RELENT(nlmp);
    331 			if ((aip->ai_dynplts = calloc(pltcnt,
    332 			    dyn_plt_ent_size)) == NULL)
    333 				return (0);
    334 		}
    335 	}
    336 	return (1);
    337 }
    338 
    339 int
    340 audit_objopen(Rt_map *clmp, Rt_map *nlmp)
    341 {
    342 	Lmid_t		lmid = get_linkmap_id(LIST(nlmp));
    343 	int		appl = 0, respond = 1, ndx = 0;
    344 	uint_t		clients = 0;
    345 	Audit_info	*aip;
    346 
    347 	if (rt_critical())
    348 		return (respond);
    349 
    350 	/*
    351 	 * Determine the total number of audit libraries in use.  This provides
    352 	 * the number of client structures required for this object.
    353 	 */
    354 	if (auditors)
    355 		clients = auditors->ad_cnt;
    356 	if (AUDITORS(clmp))
    357 		clients += AUDITORS(clmp)->ad_cnt;
    358 	if ((nlmp != clmp) && AUDITORS(nlmp))
    359 		clients += AUDITORS(nlmp)->ad_cnt;
    360 
    361 	/*
    362 	 * The initial allocation of the audit information structure includes
    363 	 * an array of audit clients, 1 per audit library presently available.
    364 	 *
    365 	 *			 ---------------
    366 	 *			| ai_cnt	|
    367 	 * 	Audit_info	| ai_clients	|-------
    368 	 *			| ai_dynplts	|	|
    369 	 *			|---------------|	|
    370 	 * 	Audit_client    |	1	|<------
    371 	 *			|---------------|
    372 	 *			|	2	|
    373 	 *			    .........
    374 	 */
    375 	if ((AUDINFO(nlmp) = aip = calloc(1, sizeof (Audit_info) +
    376 	    (sizeof (Audit_client) * clients))) == NULL)
    377 		return (0);
    378 
    379 	aip->ai_cnt = clients;
    380 	aip->ai_clients = (Audit_client *)((uintptr_t)aip +
    381 	    sizeof (Audit_info));
    382 
    383 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    384 		appl = rtld_flags |= RT_FL_APPLIC;
    385 
    386 	if (auditors)
    387 		respond = _audit_objopen(auditors->ad_list, nlmp,
    388 		    lmid, aip, &ndx);
    389 	if (respond && AUDITORS(clmp))
    390 		respond = _audit_objopen(AUDITORS(clmp)->ad_list, nlmp,
    391 		    lmid, aip, &ndx);
    392 	if (respond && (nlmp != clmp) && AUDITORS(nlmp))
    393 		respond = _audit_objopen(AUDITORS(nlmp)->ad_list, nlmp,
    394 		    lmid, aip, &ndx);
    395 
    396 	if (appl)
    397 		rtld_flags &= ~RT_FL_APPLIC;
    398 
    399 	return (respond);
    400 }
    401 
    402 /*
    403  * la_objclose() caller.  Traverse through all audit library and call any
    404  * la_objclose() entry points found.
    405  */
    406 void
    407 _audit_objclose(APlist *list, Rt_map *lmp)
    408 {
    409 	Audit_list	*alp;
    410 	Aliste		idx;
    411 
    412 	for (APLIST_TRAVERSE(list, idx, alp)) {
    413 		Audit_client	*acp;
    414 
    415 		if (alp->al_objclose == NULL)
    416 			continue;
    417 		if ((acp = _audit_client(AUDINFO(lmp), alp->al_lmp)) == NULL)
    418 			continue;
    419 
    420 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    421 		(*alp->al_objclose)(&(acp->ac_cookie));
    422 		(void) enter(thr_flg_reenter);
    423 	}
    424 }
    425 
    426 void
    427 audit_objclose(Rt_map *clmp, Rt_map *lmp)
    428 {
    429 	int	appl = 0;
    430 
    431 	if (rt_critical())
    432 		return;
    433 
    434 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    435 		appl = rtld_flags |= RT_FL_APPLIC;
    436 
    437 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJCLOSE))
    438 		_audit_objclose(auditors->ad_list, lmp);
    439 	if (AUDITORS(clmp) &&
    440 	    (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_OBJCLOSE))
    441 		_audit_objclose(AUDITORS(clmp)->ad_list, lmp);
    442 
    443 	if (appl)
    444 		rtld_flags &= ~RT_FL_APPLIC;
    445 }
    446 
    447 /*
    448  * la_pltenter() caller.  Traverse through all audit library and call any
    449  * la_pltenter() entry points found.  NOTE: this routine is called via the
    450  * glue code established in elf_plt_trace_write(), the symbol descriptor is
    451  * created as part of the glue and for 32bit environments the st_name is a
    452  * pointer to the real symbol name (ie. it's already been adjusted with the
    453  * objects base offset).  For 64bit environments the st_name remains the
    454  * original symbol offset and in this case it is used to compute the real name
    455  * pointer and pass as a separate argument to the auditor.
    456  */
    457 static void
    458 _audit_pltenter(APlist *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym,
    459     uint_t ndx, void *regs, uint_t *flags)
    460 {
    461 	Audit_list	*alp;
    462 	Aliste		idx;
    463 #if	defined(_ELF64)
    464 	const char	*name = (const char *)(sym->st_name + STRTAB(dlmp));
    465 #else
    466 	const char	*name = (const char *)(sym->st_name);
    467 #endif
    468 
    469 	for (APLIST_TRAVERSE(list, idx, alp)) {
    470 		Audit_client	*racp, *dacp;
    471 		Addr		prev = sym->st_value;
    472 
    473 		if (alp->al_pltenter == 0)
    474 			continue;
    475 		if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == NULL)
    476 			continue;
    477 		if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == NULL)
    478 			continue;
    479 		if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
    480 		    ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
    481 			continue;
    482 
    483 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    484 		sym->st_value = (Addr)(*alp->al_pltenter)(sym, ndx,
    485 		    &(racp->ac_cookie), &(dacp->ac_cookie), regs,
    486 		/* BEGIN CSTYLED */
    487 #if	defined(_ELF64)
    488 		    flags, name);
    489 #else
    490 		    flags);
    491 #endif
    492 		/* END CSTYLED */
    493 		(void) enter(thr_flg_reenter);
    494 
    495 		DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname,
    496 		    MSG_ORIG(MSG_AUD_PLTENTER), name, prev, sym->st_name));
    497 	}
    498 }
    499 
    500 Addr
    501 audit_pltenter(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx,
    502     void *regs, uint_t *flags)
    503 {
    504 	Sym	_sym = *sym;
    505 	int	_appl = 0;
    506 
    507 	if (rt_critical())
    508 		return (_sym.st_value);
    509 
    510 	/*
    511 	 * We're effectively entering ld.so.1 from user (glue) code.
    512 	 */
    513 	(void) enter(0);
    514 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    515 		_appl = rtld_flags |= RT_FL_APPLIC;
    516 
    517 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTENTER))
    518 		_audit_pltenter(auditors->ad_list, rlmp, dlmp, &_sym,
    519 		    ndx, regs, flags);
    520 	if (AUDITORS(rlmp) &&
    521 	    (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTENTER))
    522 		_audit_pltenter(AUDITORS(rlmp)->ad_list, rlmp, dlmp, &_sym,
    523 		    ndx, regs, flags);
    524 
    525 	if (_appl)
    526 		rtld_flags &= ~RT_FL_APPLIC;
    527 	leave(LIST(rlmp), 0);
    528 
    529 	return (_sym.st_value);
    530 }
    531 
    532 /*
    533  * la_pltexit() caller.  Traverse through all audit library and call any
    534  * la_pltexit() entry points found.  See notes above (_audit_pltenter) for
    535  * discussion on st_name.
    536  */
    537 static Addr
    538 _audit_pltexit(APlist *list, uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp,
    539     Sym *sym, uint_t ndx)
    540 {
    541 	Audit_list	*alp;
    542 	Aliste		idx;
    543 #if	defined(_ELF64)
    544 	const char	*name = (const char *)(sym->st_name + STRTAB(dlmp));
    545 #endif
    546 
    547 	for (APLIST_TRAVERSE(list, idx, alp)) {
    548 		Audit_client	*racp, *dacp;
    549 
    550 		if (alp->al_pltexit == 0)
    551 			continue;
    552 		if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == NULL)
    553 			continue;
    554 		if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == NULL)
    555 			continue;
    556 		if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
    557 		    ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
    558 			continue;
    559 
    560 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    561 		retval = (*alp->al_pltexit)(sym, ndx,
    562 		    &(racp->ac_cookie), &(dacp->ac_cookie),
    563 		/* BEGIN CSTYLED */
    564 #if	defined(_ELF64)
    565 		    retval, name);
    566 #else
    567 		    retval);
    568 #endif
    569 		/* END CSTYLED */
    570 		(void) enter(thr_flg_reenter);
    571 	}
    572 	return (retval);
    573 }
    574 
    575 Addr
    576 audit_pltexit(uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp, Sym *sym,
    577     uint_t ndx)
    578 {
    579 	uintptr_t	_retval = retval;
    580 	int		_appl = 0;
    581 
    582 	if (rt_critical())
    583 		return (_retval);
    584 
    585 	/*
    586 	 * We're effectively entering ld.so.1 from user (glue) code.
    587 	 */
    588 	(void) enter(0);
    589 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    590 		_appl = rtld_flags |= RT_FL_APPLIC;
    591 
    592 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTEXIT))
    593 		_retval = _audit_pltexit(auditors->ad_list, _retval,
    594 		    rlmp, dlmp, sym, ndx);
    595 	if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTEXIT))
    596 		_retval = _audit_pltexit(AUDITORS(rlmp)->ad_list, _retval,
    597 		    rlmp, dlmp, sym, ndx);
    598 
    599 	if (_appl)
    600 		rtld_flags &= ~RT_FL_APPLIC;
    601 	leave(LIST(rlmp), 0);
    602 
    603 	return (_retval);
    604 }
    605 
    606 
    607 /*
    608  * la_symbind() caller.  Traverse through all audit library and call any
    609  * la_symbind() entry points found.
    610  */
    611 static Addr
    612 _audit_symbind(APlist *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx,
    613     uint_t *flags, int *called)
    614 {
    615 	Audit_list	*alp;
    616 	Aliste		idx;
    617 #if	defined(_ELF64)
    618 	const char	*name = (const char *)(sym->st_name + STRTAB(dlmp));
    619 #else
    620 	const char	*name = (const char *)(sym->st_name);
    621 #endif
    622 
    623 	for (APLIST_TRAVERSE(list, idx, alp)) {
    624 		Audit_client	*racp, *dacp;
    625 		Addr		prev = sym->st_value;
    626 		uint_t		lflags;
    627 
    628 		if (alp->al_symbind == 0)
    629 			continue;
    630 		if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == NULL)
    631 			continue;
    632 		if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == NULL)
    633 			continue;
    634 		if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
    635 		    ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
    636 			continue;
    637 
    638 		/*
    639 		 * The la_symbind interface is only called when the calling
    640 		 * object has been identified as BINDFROM, and the destination
    641 		 * object has been identified as BINDTO.  Use a local version of
    642 		 * the flags, so that any user update can be collected.
    643 		 */
    644 		called++;
    645 		lflags = (*flags & ~(LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
    646 
    647 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    648 		sym->st_value = (*alp->al_symbind)(sym, ndx,
    649 		    &(racp->ac_cookie), &(dacp->ac_cookie),
    650 		/* BEGIN CSTYLED */
    651 #if	defined(_ELF64)
    652 		    &lflags, name);
    653 #else
    654 		    &lflags);
    655 #endif
    656 		/* END CSTYLED */
    657 		(void) enter(thr_flg_reenter);
    658 
    659 		/*
    660 		 * If the auditor indicated that they did not want to process
    661 		 * pltenter, or pltexit audits for this symbol, retain this
    662 		 * information.  Also retain whether an alternative symbol value
    663 		 * has been supplied.
    664 		 */
    665 		*flags |= (lflags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
    666 		if ((prev != sym->st_value) && (alp->al_vernum >= LAV_VERSION2))
    667 			*flags |= LA_SYMB_ALTVALUE;
    668 
    669 		DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname,
    670 		    MSG_ORIG(MSG_AUD_SYMBIND), name, prev, sym->st_value));
    671 	}
    672 	return (sym->st_value);
    673 }
    674 
    675 Addr
    676 audit_symbind(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, Addr value,
    677     uint_t *flags)
    678 {
    679 	Sym	_sym;
    680 	int	_appl = 0, called = 0;
    681 
    682 	/*
    683 	 * Construct a new symbol from that supplied but with the real address.
    684 	 * In the 64-bit world the st_name field is only 32-bits which isn't
    685 	 * big enough to hold a character pointer. We pass this pointer as a
    686 	 * separate parameter for 64-bit audit libraries.
    687 	 */
    688 	_sym = *sym;
    689 	_sym.st_value = value;
    690 
    691 	if (rt_critical())
    692 		return (_sym.st_value);
    693 
    694 #if	!defined(_ELF64)
    695 	_sym.st_name += (Word)STRTAB(dlmp);
    696 #endif
    697 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    698 		_appl = rtld_flags |= RT_FL_APPLIC;
    699 
    700 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_SYMBIND))
    701 		_sym.st_value = _audit_symbind(auditors->ad_list,
    702 		    rlmp, dlmp, &_sym, ndx, flags, &called);
    703 	if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_SYMBIND))
    704 		_sym.st_value = _audit_symbind(AUDITORS(rlmp)->ad_list,
    705 		    rlmp, dlmp, &_sym, ndx, flags, &called);
    706 
    707 	/*
    708 	 * If no la_symbind() was called for this interface, fabricate that no
    709 	 * la_pltenter, or la_pltexit is required.  This helps reduce the glue
    710 	 * code created for further auditing.
    711 	 */
    712 	if (caller == 0)
    713 		*flags |= (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
    714 
    715 	if (_appl)
    716 		rtld_flags &= ~RT_FL_APPLIC;
    717 
    718 	return (_sym.st_value);
    719 }
    720 
    721 /*
    722  * la_preinit() caller.  Traverse through all audit libraries and call any
    723  * la_preinit() entry points found.
    724  */
    725 static void
    726 _audit_preinit(APlist *list, Rt_map *clmp)
    727 {
    728 	Audit_list	*alp;
    729 	Aliste		idx;
    730 
    731 	for (APLIST_TRAVERSE(list, idx, alp)) {
    732 		Audit_client	*acp;
    733 
    734 		if (alp->al_preinit == 0)
    735 			continue;
    736 		if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == NULL)
    737 			continue;
    738 
    739 		leave(LIST(alp->al_lmp), thr_flg_reenter);
    740 		(*alp->al_preinit)(&(acp->ac_cookie));
    741 		(void) enter(thr_flg_reenter);
    742 	}
    743 }
    744 
    745 void
    746 audit_preinit(Rt_map *clmp)
    747 {
    748 	int	appl = 0;
    749 
    750 	if (rt_critical())
    751 		return;
    752 
    753 	if ((rtld_flags & RT_FL_APPLIC) == 0)
    754 		appl = rtld_flags |= RT_FL_APPLIC;
    755 
    756 	if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PREINIT))
    757 		_audit_preinit(auditors->ad_list, clmp);
    758 	if (AUDITORS(clmp) && (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_PREINIT))
    759 		_audit_preinit(AUDITORS(clmp)->ad_list, clmp);
    760 
    761 	if (appl)
    762 		rtld_flags &= ~RT_FL_APPLIC;
    763 }
    764 
    765 /*
    766  * Clean up (free) an audit descriptor.  First, gather a list of all handles,
    767  * and then close each one down.  This is done rather than using the handles
    768  * directly from the auditors, as the audit list can be torn down as a result
    769  * of the dlclose.  In other words, what you're pointing at can be removed
    770  * while your still pointing at it.
    771  */
    772 void
    773 audit_desc_cleanup(Rt_map *clmp)
    774 {
    775 	Audit_desc	*adp = AUDITORS(clmp);
    776 	Audit_list	*alp;
    777 	Aliste		idx;
    778 	APlist		*ghalp = NULL;
    779 
    780 	if (adp == NULL)
    781 		return;
    782 	if (adp->ad_name)
    783 		free(adp->ad_name);
    784 
    785 	for (APLIST_TRAVERSE(adp->ad_list, idx, alp))
    786 		(void) aplist_append(&ghalp, alp->al_ghp, AL_CNT_GROUPS);
    787 
    788 	free(adp->ad_list);
    789 	adp->ad_list = NULL;
    790 
    791 	free(adp);
    792 	AUDITORS(clmp) = NULL;
    793 
    794 	if (ghalp) {
    795 		Grp_hdl		*ghp;
    796 		Aliste		idx;
    797 
    798 		for (APLIST_TRAVERSE(ghalp, idx, ghp)) {
    799 			(void) dlclose_intn(ghp, clmp);
    800 		}
    801 		free(ghalp);
    802 	}
    803 }
    804 
    805 /*
    806  * Clean up (free) an audit information structure.
    807  */
    808 void
    809 audit_info_cleanup(Rt_map *clmp)
    810 {
    811 	Audit_info	*aip = AUDINFO(clmp);
    812 
    813 	if (aip == NULL)
    814 		return;
    815 
    816 	if (aip->ai_dynplts)
    817 		free(aip->ai_dynplts);
    818 	free(aip);
    819 }
    820 
    821 /*
    822  * Create a data structure of symbol lookup names and associated flags to help
    823  * simplify audit_symget() use.
    824  */
    825 typedef struct {
    826 	Msg	sname;
    827 	uint_t	alflag;
    828 	uint_t	auflag;
    829 } Aud_info;
    830 
    831 static const Aud_info aud_info[] = {
    832 	{ MSG_SYM_LAVERSION,	0 },	/* MSG_ORIG(MSG_SYM_LAVERSION) */
    833 	{ MSG_SYM_LAPREINIT,		/* MSG_ORIG(MSG_SYM_LAPREINIT) */
    834 	    LML_TFLG_AUD_PREINIT, 0 },
    835 	{ MSG_SYM_LAOBJSEARCH,		/* MSG_ORIG(MSG_SYM_LAOBJSEARCH) */
    836 	    LML_TFLG_AUD_OBJSEARCH, 0 },
    837 	{ MSG_SYM_LAOBJOPEN,		/* MSG_ORIG(MSG_SYM_LAOBJOPEN) */
    838 	    LML_TFLG_AUD_OBJOPEN, 0 },
    839 	{ MSG_SYM_LAOBJFILTER,		/* MSG_ORIG(MSG_SYM_LAOBJFILTER */
    840 	    LML_TFLG_AUD_OBJFILTER, 0 },
    841 	{ MSG_SYM_LAOBJCLOSE,		/* MSG_ORIG(MSG_SYM_LAOBJCLOSE) */
    842 	    LML_TFLG_AUD_OBJCLOSE, 0 },
    843 	{ MSG_SYM_LAACTIVITY,		/* MSG_ORIG(MSG_SYM_LAACTIVITY) */
    844 	    LML_TFLG_AUD_ACTIVITY, 0 },
    845 
    846 #if	defined(_ELF64)
    847 	{ MSG_SYM_LASYMBIND_64,		/* MSG_ORIG(MSG_SYM_LASYMBIND_64) */
    848 #else
    849 	{ MSG_SYM_LASYMBIND,		/* MSG_ORIG(MSG_SYM_LASYMBIND) */
    850 #endif
    851 	    LML_TFLG_AUD_SYMBIND, 0 },
    852 
    853 #if	defined(__sparcv9)
    854 	{ MSG_SYM_LAV9PLTENTER,		/* MSG_ORIG(MSG_SYM_LAV9PLTENTER) */
    855 #elif   defined(__sparc)
    856 	{ MSG_SYM_LAV8PLTENTER,		/* MSG_ORIG(MSG_SYM_LAV8PLTENTER) */
    857 #elif	defined(__amd64)
    858 	{ MSG_SYM_LAAMD64PLTENTER, /* MSG_ORIG(MSG_SYM_LAAMD64PLTENTER) */
    859 #elif	defined(__i386)
    860 	{ MSG_SYM_LAX86PLTENTER,	/* MSG_ORIG(MSG_SYM_LAX86PLTENTER) */
    861 #else
    862 #error platform not defined!
    863 #endif
    864 	    LML_TFLG_AUD_PLTENTER, AF_PLTENTER },
    865 
    866 #if	defined(_ELF64)
    867 	{ MSG_SYM_LAPLTEXIT_64,		/* MSG_ORIG(MSG_SYM_LAPLTEXIT_64) */
    868 #else
    869 	{ MSG_SYM_LAPLTEXIT,		/* MSG_ORIG(MSG_SYM_LAPLTEXIT) */
    870 #endif
    871 	    LML_TFLG_AUD_PLTEXIT, AF_PLTEXIT }
    872 };
    873 
    874 #define	AI_LAVERSION	0
    875 #define	AI_LAPREINIT	1
    876 #define	AI_LAOBJSEARCH	2
    877 #define	AI_LAOBJOPEN	3
    878 #define	AI_LAOBJFILTER	4
    879 #define	AI_LAOBJCLOSE	5
    880 #define	AI_LAACTIVITY	6
    881 #define	AI_LASYMBIND	7
    882 #define	AI_LAPLTENTER	8
    883 #define	AI_LAPLTEXIT	9
    884 
    885 static Addr
    886 audit_symget(Audit_list *alp, int info, int *in_nfavl)
    887 {
    888 	Rt_map		*_lmp, *lmp = alp->al_lmp;
    889 	const char	*sname = MSG_ORIG(aud_info[info].sname);
    890 	uint_t		alflag = aud_info[info].alflag;
    891 	uint_t		auflag = aud_info[info].auflag;
    892 	uint_t		binfo;
    893 	Sym		*sym;
    894 	Slookup		sl;
    895 
    896 	/*
    897 	 * Initialize the symbol lookup data structure.
    898 	 */
    899 	SLOOKUP_INIT(sl, sname, lml_rtld.lm_head, lmp, ld_entry_cnt,
    900 	    0, 0, 0, 0, LKUP_FIRST);
    901 
    902 	if (sym = LM_LOOKUP_SYM(lmp)(&sl, &_lmp, &binfo, in_nfavl)) {
    903 		Addr	addr = sym->st_value;
    904 
    905 		if (!(FLAGS(lmp) & FLG_RT_FIXED))
    906 			addr += ADDR(lmp);
    907 
    908 		if (alflag)
    909 			alp->al_flags |= alflag;
    910 		if (auflag)
    911 			audit_flags |= auflag;
    912 
    913 		DBG_CALL(Dbg_audit_interface(LIST(alp->al_lmp),
    914 		    alp->al_libname, sname));
    915 		return (addr);
    916 	} else
    917 		return (0);
    918 }
    919 
    920 /*
    921  * Centralize cleanup routines.
    922  */
    923 static int
    924 audit_disable(char *name, Rt_map *clmp, Grp_hdl *ghp, Audit_list *alp)
    925 {
    926 	eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_AUD_DISABLED), name);
    927 	if (ghp)
    928 		(void) dlclose_intn(ghp, clmp);
    929 	if (alp)
    930 		free(alp);
    931 
    932 	return (0);
    933 }
    934 
    935 /*
    936  * Given a list of one or more audit libraries, open each one and establish a
    937  * a descriptor representing the entry points it provides.
    938  */
    939 int
    940 audit_setup(Rt_map *clmp, Audit_desc *adp, uint_t orig, int *in_nfavl)
    941 {
    942 	char	*ptr, *next;
    943 	Lm_list	*clml = LIST(clmp);
    944 	int	error = 1;
    945 
    946 	DBG_CALL(Dbg_audit_lib(clml, adp->ad_name));
    947 
    948 	/*
    949 	 * Mark that we have at least one auditing link map
    950 	 */
    951 	rtld_flags2 |= RT_FL2_HASAUDIT;
    952 
    953 	/*
    954 	 * The audit definitions may be a list (which will already have been
    955 	 * dupped) so split it into individual tokens.
    956 	 */
    957 	for (ptr = strtok_r(adp->ad_name, MSG_ORIG(MSG_STR_DELIMIT), &next);
    958 	    ptr; ptr = strtok_r(NULL,  MSG_ORIG(MSG_STR_DELIMIT), &next)) {
    959 		Grp_hdl		*ghp;
    960 		Rt_map		*lmp;
    961 		Rt_map		**tobj;
    962 		Audit_list	*alp;
    963 
    964 		/*
    965 		 * Open the audit library on its own link-map.
    966 		 */
    967 		if ((ghp = dlmopen_intn((Lm_list *)LM_ID_NEWLM, ptr,
    968 		    (RTLD_FIRST | RTLD_GLOBAL | RTLD_WORLD), clmp,
    969 		    FLG_RT_AUDIT, orig)) == NULL) {
    970 			error = audit_disable(ptr, clmp, 0, 0);
    971 			continue;
    972 		}
    973 		lmp = ghp->gh_ownlmp;
    974 
    975 		/*
    976 		 * If this auditor has already been loaded, reuse it.
    977 		 */
    978 		if ((alp = LIST(lmp)->lm_alp) != NULL) {
    979 			if (aplist_append(&(adp->ad_list), alp,
    980 			    AL_CNT_AUDITORS) == NULL)
    981 				return (audit_disable(ptr, clmp, ghp, alp));
    982 
    983 			adp->ad_cnt++;
    984 			DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
    985 			    alp->al_vernum));
    986 			adp->ad_flags |= alp->al_flags;
    987 			continue;
    988 		}
    989 
    990 		/*
    991 		 * Prior to the Unified Process Model (UPM) environment, an
    992 		 * rtld lock had to be held upon leave().  However, even within
    993 		 * a UPM environment, an old auditor, that has a lazy dependency
    994 		 * on libc, is still a possibility.  As libc isn't loaded, we
    995 		 * don't know the process model, and will determine this later.
    996 		 * Refer to external.c:get_lcinterface().
    997 		 */
    998 		if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0)
    999 			LIST(lmp)->lm_flags |= LML_FLG_HOLDLOCK;
   1000 
   1001 		/*
   1002 		 * Allocate an audit list descriptor for this object and
   1003 		 * search for all known entry points.
   1004 		 */
   1005 		if ((alp = calloc(1, sizeof (Audit_list))) == NULL)
   1006 			return (audit_disable(ptr, clmp, ghp, 0));
   1007 
   1008 		alp->al_libname = NAME(lmp);
   1009 		alp->al_lmp = lmp;
   1010 		alp->al_ghp = ghp;
   1011 
   1012 		/*
   1013 		 * All audit libraries must handshake through la_version().
   1014 		 * Determine that the symbol exists, finish initializing the
   1015 		 * object, and then call the function.
   1016 		 */
   1017 		if ((alp->al_version = (uint_t(*)())audit_symget(alp,
   1018 		    AI_LAVERSION, in_nfavl)) == 0) {
   1019 			eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM),
   1020 			    MSG_ORIG(MSG_SYM_LAVERSION));
   1021 			error = audit_disable(ptr, clmp, ghp, alp);
   1022 			continue;
   1023 		}
   1024 
   1025 		if ((tobj = tsort(lmp, LIST(lmp)->lm_init, RT_SORT_REV)) ==
   1026 		    (Rt_map **)S_ERROR)
   1027 			return (audit_disable(ptr, clmp, ghp, alp));
   1028 
   1029 		rtld_flags |= RT_FL_APPLIC;
   1030 		if (tobj != (Rt_map **)NULL)
   1031 			call_init(tobj, DBG_INIT_SORT);
   1032 
   1033 		alp->al_vernum = alp->al_version(LAV_CURRENT);
   1034 		rtld_flags &= ~RT_FL_APPLIC;
   1035 
   1036 		if ((alp->al_vernum < LAV_VERSION1) ||
   1037 		    (alp->al_vernum > LAV_CURRENT)) {
   1038 			eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS),
   1039 			    LAV_CURRENT, alp->al_vernum);
   1040 			error = audit_disable(ptr, clmp, ghp, alp);
   1041 			continue;
   1042 		}
   1043 
   1044 		if (aplist_append(&(adp->ad_list), alp,
   1045 		    AL_CNT_AUDITORS) == NULL)
   1046 			return (audit_disable(ptr, clmp, ghp, alp));
   1047 
   1048 		adp->ad_cnt++;
   1049 		DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
   1050 		    alp->al_vernum));
   1051 
   1052 		/*
   1053 		 * Collect any remaining entry points.
   1054 		 */
   1055 		alp->al_preinit = (void(*)())audit_symget(alp,
   1056 		    AI_LAPREINIT, in_nfavl);
   1057 		alp->al_objsearch = (char *(*)())audit_symget(alp,
   1058 		    AI_LAOBJSEARCH, in_nfavl);
   1059 		alp->al_objopen = (uint_t(*)())audit_symget(alp,
   1060 		    AI_LAOBJOPEN, in_nfavl);
   1061 		alp->al_objfilter = (int(*)())audit_symget(alp,
   1062 		    AI_LAOBJFILTER, in_nfavl);
   1063 		alp->al_objclose = (uint_t(*)())audit_symget(alp,
   1064 		    AI_LAOBJCLOSE, in_nfavl);
   1065 		alp->al_activity = (void (*)())audit_symget(alp,
   1066 		    AI_LAACTIVITY, in_nfavl);
   1067 		alp->al_symbind = (uintptr_t(*)())audit_symget(alp,
   1068 		    AI_LASYMBIND, in_nfavl);
   1069 		alp->al_pltenter = (uintptr_t(*)())audit_symget(alp,
   1070 		    AI_LAPLTENTER, in_nfavl);
   1071 		alp->al_pltexit = (uintptr_t(*)())audit_symget(alp,
   1072 		    AI_LAPLTEXIT, in_nfavl);
   1073 
   1074 		/*
   1075 		 * Collect the individual object flags, and assign this audit
   1076 		 * list descriptor to its associated link-map list.
   1077 		 */
   1078 		adp->ad_flags |= alp->al_flags;
   1079 		LIST(lmp)->lm_alp = alp;
   1080 	}
   1081 
   1082 	/*
   1083 	 * Free the original audit string, as this descriptor may be used again
   1084 	 * to add additional auditing.
   1085 	 */
   1086 	free(adp->ad_name);
   1087 	adp->ad_name = NULL;
   1088 
   1089 	return (error);
   1090 }
   1091