audit.c revision 12449:a87750d92895
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
62uint_t	audit_flags = 0;		/* Copy of specific audit flags to */
63					/* simplify boot_elf.s access. */
64
65static 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 */
85static 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
115int
116audit_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 */
148static 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
172char *
173audit_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 */
203static 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
252void
253audit_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 */
280static 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
340int
341audit_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 */
407void
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
427void
428audit_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 */
458static 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
501Addr
502audit_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 */
538static 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
576Addr
577audit_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 */
612static 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
676Addr
677audit_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 */
726static 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
746void
747audit_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 */
773void
774audit_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 */
809void
810audit_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 */
826typedef struct {
827	Msg	sname;
828	uint_t	alflag;
829	uint_t	auflag;
830} Aud_info;
831
832static 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
886static Addr
887audit_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 */
925static int
926audit_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 */
941int
942audit_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