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