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