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