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