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