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