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