17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
55aefb655Srie * Common Development and Distribution License (the "License").
65aefb655Srie * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
215aefb655Srie
227c478bd9Sstevel@tonic-gate /*
23f441771bSRod Evans * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
24*38f4bdddSBryan Cantrill * Copyright (c) 2012, Joyent, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate *
267c478bd9Sstevel@tonic-gate * Audit interfaces. Auditing can be enabled in two ways:
277c478bd9Sstevel@tonic-gate *
282020b2b6SRod Evans * - Using the LD_AUDIT environment variable
297c478bd9Sstevel@tonic-gate *
302020b2b6SRod Evans * - From individual objects containing a DT_DEPAUDIT entry
317c478bd9Sstevel@tonic-gate * (see ld(1) -P/-p options).
327c478bd9Sstevel@tonic-gate *
337c478bd9Sstevel@tonic-gate * The former establishes a global set of audit libraries which can inspect all
347c478bd9Sstevel@tonic-gate * objects from a given process. The latter establishes a local set of audit
357c478bd9Sstevel@tonic-gate * libraries which can inspect the immediate dependencies of the caller.
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * Audit library capabilities are indicated by flags within the link-map list
387c478bd9Sstevel@tonic-gate * header (for global auditing), see LML_TFLG_AUD_* flags, or by the same flags
397c478bd9Sstevel@tonic-gate * within the individual link-map (for local auditing). Although both sets of
407c478bd9Sstevel@tonic-gate * flags can occur in different data items they are defined as one to simplify
417c478bd9Sstevel@tonic-gate * audit interface requirements. The basic test for all audit interfaces is:
427c478bd9Sstevel@tonic-gate *
432020b2b6SRod Evans * if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_MASK)
442020b2b6SRod Evans *
452020b2b6SRod Evans * Note. Auditors themselves are identified with the LML_TFLG_NOAUDIT link-map
462020b2b6SRod Evans * list flag, and no LML_TFLG_AUD_MASK flags. These flags get propagated from
472020b2b6SRod Evans * a callers link-map list to any new link-map lists created. Thus, standard
482020b2b6SRod Evans * link-maps lists have the LML_TFLG_AUD_MASK flags propagated, and should a
492020b2b6SRod Evans * new link-map list be created by an auditor, that list gets tagged as
502020b2b6SRod Evans * LML_TFLG_NOAUDIT.
517c478bd9Sstevel@tonic-gate *
527c478bd9Sstevel@tonic-gate * The latter link-map list equivalence test insures that auditors themselves
537c478bd9Sstevel@tonic-gate * (invoked through DT_DEPAUDIT) are not audited.
542020b2b6SRod Evans *
552020b2b6SRod Evans * The history of version changes:
562020b2b6SRod Evans *
572020b2b6SRod Evans * LAV_VERSION1 (Solaris 2.6)
582020b2b6SRod Evans * Auditing implementation added.
592020b2b6SRod Evans *
602020b2b6SRod Evans * LAV_VERSION2 (Solaris 2.6)
612020b2b6SRod Evans * LA_SYMB_ALTVALUE support added.
622020b2b6SRod Evans *
632020b2b6SRod Evans * LAV_VERSION3 (Solaris 9 update 7)
642020b2b6SRod Evans * ld_objfilter() added.
652020b2b6SRod Evans *
662020b2b6SRod Evans * LAV_VERSION4 (Solaris 10 update 5)
672020b2b6SRod Evans * Correction of activity calls for local auditors, and introduction of
682020b2b6SRod Evans * -z globalaudit concept.
692020b2b6SRod Evans *
702020b2b6SRod Evans * LAV_VERSION5 (Solaris 11)
712020b2b6SRod Evans * Under this version, preinit and activity events are enabled from local
722020b2b6SRod Evans * auditors. The la_preinit and la_activity interfaces require a cookie
732020b2b6SRod Evans * that represents the head of the link-map list being audited. If a
742020b2b6SRod Evans * local preinit or activity interface is detected, the local auditors
752020b2b6SRod Evans * la_objopen() routine is called with a cookie that represents the object
762020b2b6SRod Evans * that heads the link-map list of the object being audited.
772020b2b6SRod Evans *
782020b2b6SRod Evans * A local auditor is loaded through adding a new dependency that requests
792020b2b6SRod Evans * auditing, and therefore an la_activity(ADD) event is already in effect.
802020b2b6SRod Evans * Regardless, the local auditors la_activity() routine is called with the
812020b2b6SRod Evans * cookie that represents the object that heads the link-map list of the
822020b2b6SRod Evans * object being audited.
832020b2b6SRod Evans *
842020b2b6SRod Evans * A local auditor can be loaded prior to the preinit event. In this case,
852020b2b6SRod Evans * the local auditors la_preinit() routine is called with the cookie that
862020b2b6SRod Evans * represents the object that heads the link-map list of the object being
872020b2b6SRod Evans * audited. After the preinit event, any la_preinit() routine within a
882020b2b6SRod Evans * local auditor will not be called.
892020b2b6SRod Evans *
902020b2b6SRod Evans * These events are intended to follow the expected sequence of events
912020b2b6SRod Evans * received by global auditors, ie:
922020b2b6SRod Evans *
932020b2b6SRod Evans * - la_objopen(main)
942020b2b6SRod Evans * - la_activity(ADD)
952020b2b6SRod Evans * - la_objopen(dependency)
962020b2b6SRod Evans * - la_activity(CONSISTENT)
972020b2b6SRod Evans * - la_preinit(main)
987c478bd9Sstevel@tonic-gate */
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate #include <stdio.h>
1017c478bd9Sstevel@tonic-gate #include <sys/types.h>
1027c478bd9Sstevel@tonic-gate #include <sys/lwp.h>
1037c478bd9Sstevel@tonic-gate #include <stdio.h>
1047c478bd9Sstevel@tonic-gate #include <stdarg.h>
1057c478bd9Sstevel@tonic-gate #include <dlfcn.h>
1067c478bd9Sstevel@tonic-gate #include <string.h>
1075aefb655Srie #include <debug.h>
1087c478bd9Sstevel@tonic-gate #include "_rtld.h"
1097c478bd9Sstevel@tonic-gate #include "_audit.h"
1107c478bd9Sstevel@tonic-gate #include "_elf.h"
1117c478bd9Sstevel@tonic-gate #include "msg.h"
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate uint_t audit_flags = 0; /* Copy of specific audit flags to */
1147c478bd9Sstevel@tonic-gate /* simplify boot_elf.s access. */
1157c478bd9Sstevel@tonic-gate
1162020b2b6SRod Evans /*
1172020b2b6SRod Evans * Obtain a head link-map cookie. Local auditors can provide la_preinit() and
1182020b2b6SRod Evans * la_activity() routines, and these routines require a cookie that represents
1192020b2b6SRod Evans * the object that heads the link-map of the object being audited. A list of
1202020b2b6SRod Evans * these cookies is maintained on the link-map list. This list allows multiple
1212020b2b6SRod Evans * local objects to specify the same auditor, and to obtain the same cookie
1222020b2b6SRod Evans * for the link-map that heads the link-map list.
1232020b2b6SRod Evans *
1242020b2b6SRod Evans * The initial cookie is created by _audit_create_head_client() which is called
1252020b2b6SRod Evans * from _audit_add_head(). This cookies address is then passed to the local
1262020b2b6SRod Evans * auditors ld_objopen() and la_activity() routines. Subsequent preinit and
1272020b2b6SRod Evans * activity events use _audit_get_head_client() to dynamically retrieve the
1282020b2b6SRod Evans * cookies address.
1292020b2b6SRod Evans */
1302020b2b6SRod Evans static Audit_client *
_audit_get_head_client(Rt_map * hlmp,Rt_map * almp)1312020b2b6SRod Evans _audit_get_head_client(Rt_map *hlmp, Rt_map *almp)
1322020b2b6SRod Evans {
1332020b2b6SRod Evans Audit_client *acp;
1342020b2b6SRod Evans Aliste idx;
1352020b2b6SRod Evans Lm_list *hlml = LIST(hlmp);
1362020b2b6SRod Evans
1372020b2b6SRod Evans for (ALIST_TRAVERSE(hlml->lm_aud_cookies, idx, acp)) {
1382020b2b6SRod Evans if (acp->ac_lmp == almp)
1392020b2b6SRod Evans return (acp);
1402020b2b6SRod Evans }
1412020b2b6SRod Evans return (NULL);
1422020b2b6SRod Evans }
1432020b2b6SRod Evans
1442020b2b6SRod Evans static Audit_client *
_audit_create_head_client(Rt_map * hlmp,Rt_map * almp)1452020b2b6SRod Evans _audit_create_head_client(Rt_map *hlmp, Rt_map *almp)
1462020b2b6SRod Evans {
1472020b2b6SRod Evans Audit_client ac, *acp;
1482020b2b6SRod Evans Lm_list *hlml = LIST(hlmp);
1492020b2b6SRod Evans
1502020b2b6SRod Evans ac.ac_lmp = almp;
1512020b2b6SRod Evans ac.ac_cookie = (uintptr_t)hlmp;
1522020b2b6SRod Evans ac.ac_flags = 0;
1532020b2b6SRod Evans
1542020b2b6SRod Evans if ((acp = alist_append(&(hlml->lm_aud_cookies), &ac,
1552020b2b6SRod Evans sizeof (Audit_client), AL_CNT_COOKIES)) == NULL)
1562020b2b6SRod Evans return (NULL);
1572020b2b6SRod Evans
1582020b2b6SRod Evans return (acp);
1592020b2b6SRod Evans }
1602020b2b6SRod Evans
1612020b2b6SRod Evans /*
1622020b2b6SRod Evans * Determine the appropriate client. Each client structure identifies the
1632020b2b6SRod Evans * link-map of the auditor it is associated with. From the client structure,
1642020b2b6SRod Evans * the address of the associated cookie, that represents the object being
1652020b2b6SRod Evans * audited, is retrieved so that the address can be passed to any audit call.
1662020b2b6SRod Evans *
1672020b2b6SRod Evans * Note, objects that are being locally audited, can provide la_preinit() and
1682020b2b6SRod Evans * la_activity() routines. These routines must be passed cookies that represent
1692020b2b6SRod Evans * the object that heads the link-map list of the object being audited. These
1702020b2b6SRod Evans * cookies are not maintained on this objects Audit_client structure, but are
1712020b2b6SRod Evans * obtained from the associated link-map lists lm_cookies alist.
1722020b2b6SRod Evans */
1737c478bd9Sstevel@tonic-gate static Audit_client *
_audit_client(Audit_info * aip,Rt_map * almp)1747c478bd9Sstevel@tonic-gate _audit_client(Audit_info *aip, Rt_map *almp)
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate int ndx;
1777c478bd9Sstevel@tonic-gate
17857ef7aa9SRod Evans if (aip == NULL)
17957ef7aa9SRod Evans return (NULL);
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate for (ndx = 0; ndx < aip->ai_cnt; ndx++) {
1827c478bd9Sstevel@tonic-gate if (aip->ai_clients[ndx].ac_lmp == almp)
1837c478bd9Sstevel@tonic-gate return (&(aip->ai_clients[ndx]));
1847c478bd9Sstevel@tonic-gate }
18557ef7aa9SRod Evans return (NULL);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /*
1897247f888Srie * la_filter() caller. Traverse through all audit libraries and call any
1907c478bd9Sstevel@tonic-gate * la_filter() entry points found. A zero return from an auditor indicates
1917c478bd9Sstevel@tonic-gate * that the filtee should be ignored.
1927c478bd9Sstevel@tonic-gate */
1937c478bd9Sstevel@tonic-gate static int
_audit_objfilter(APlist * list,Rt_map * frlmp,const char * ref,Rt_map * felmp,uint_t flags)19457ef7aa9SRod Evans _audit_objfilter(APlist *list, Rt_map *frlmp, const char *ref, Rt_map *felmp,
1957c478bd9Sstevel@tonic-gate uint_t flags)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate Audit_list *alp;
19857ef7aa9SRod Evans Aliste idx;
1992020b2b6SRod Evans Lm_list *frlml = LIST(frlmp);
2007c478bd9Sstevel@tonic-gate
20157ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
2027c478bd9Sstevel@tonic-gate Audit_client *fracp, *feacp;
2032020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
2042020b2b6SRod Evans Lm_list *alml = LIST(almp);
205f441771bSRod Evans int ret;
2067c478bd9Sstevel@tonic-gate
20757ef7aa9SRod Evans if (alp->al_objfilter == NULL)
2087c478bd9Sstevel@tonic-gate continue;
2092020b2b6SRod Evans if ((fracp = _audit_client(AUDINFO(frlmp), almp)) == NULL)
2107c478bd9Sstevel@tonic-gate continue;
2112020b2b6SRod Evans if ((feacp = _audit_client(AUDINFO(felmp), almp)) == NULL)
2127c478bd9Sstevel@tonic-gate continue;
2137c478bd9Sstevel@tonic-gate
2142020b2b6SRod Evans DBG_CALL(Dbg_audit_objfilter(frlml, DBG_AUD_CALL,
2152020b2b6SRod Evans alp->al_libname, NAME(frlmp), NAME(felmp), ref));
2162020b2b6SRod Evans
2172020b2b6SRod Evans leave(alml, thr_flg_reenter);
218f441771bSRod Evans ret = (*alp->al_objfilter)(&(fracp->ac_cookie), ref,
219f441771bSRod Evans &(feacp->ac_cookie), flags);
2208cd45542Sraf (void) enter(thr_flg_reenter);
2212020b2b6SRod Evans
2222020b2b6SRod Evans if (ret == 0) {
2232020b2b6SRod Evans DBG_CALL(Dbg_audit_objfilter(frlml, DBG_AUD_RET,
2242020b2b6SRod Evans alp->al_libname, NAME(frlmp), NULL, NULL));
225f441771bSRod Evans return (0);
2267c478bd9Sstevel@tonic-gate }
2272020b2b6SRod Evans }
2287c478bd9Sstevel@tonic-gate return (1);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate int
audit_objfilter(Rt_map * frlmp,const char * ref,Rt_map * felmp,uint_t flags)2327c478bd9Sstevel@tonic-gate audit_objfilter(Rt_map *frlmp, const char *ref, Rt_map *felmp, uint_t flags)
2337c478bd9Sstevel@tonic-gate {
2342020b2b6SRod Evans uint_t rtldflags;
2352020b2b6SRod Evans int respond = 1;
2367c478bd9Sstevel@tonic-gate
2372a8d6ebaSRod Evans if (rt_critical())
2382a8d6ebaSRod Evans return (respond);
2392a8d6ebaSRod Evans
2402020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJFILTER))
24357ef7aa9SRod Evans respond = _audit_objfilter(auditors->ad_list, frlmp,
2447c478bd9Sstevel@tonic-gate ref, felmp, flags);
2457c478bd9Sstevel@tonic-gate if (respond && AUDITORS(frlmp) &&
2467c478bd9Sstevel@tonic-gate (AUDITORS(frlmp)->ad_flags & LML_TFLG_AUD_OBJFILTER))
24757ef7aa9SRod Evans respond = _audit_objfilter(AUDITORS(frlmp)->ad_list, frlmp,
2487c478bd9Sstevel@tonic-gate ref, felmp, flags);
2497c478bd9Sstevel@tonic-gate
2502020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate return (respond);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate /*
2567247f888Srie * la_objsearch() caller. Traverse through all audit libraries and call any
2577c478bd9Sstevel@tonic-gate * la_objsearch() entry points found.
2587c478bd9Sstevel@tonic-gate *
2597c478bd9Sstevel@tonic-gate * Effectively any audit library can change the name we're working with, so we
2607c478bd9Sstevel@tonic-gate * continue to propagate the new name to each audit library. Any 0 return
2617c478bd9Sstevel@tonic-gate * terminates the search.
2627c478bd9Sstevel@tonic-gate */
2637c478bd9Sstevel@tonic-gate static char *
_audit_objsearch(APlist * list,char * oname,Rt_map * clmp,uint_t flags)2642020b2b6SRod Evans _audit_objsearch(APlist *list, char *oname, Rt_map *clmp, uint_t flags)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate Audit_list *alp;
26757ef7aa9SRod Evans Aliste idx;
2682020b2b6SRod Evans Lm_list *clml = LIST(clmp);
2697c478bd9Sstevel@tonic-gate
27057ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
2717c478bd9Sstevel@tonic-gate Audit_client *acp;
2722020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
2732020b2b6SRod Evans Lm_list *alml = LIST(almp);
2742020b2b6SRod Evans char *nname = oname;
2757c478bd9Sstevel@tonic-gate
27657ef7aa9SRod Evans if (alp->al_objsearch == NULL)
2777c478bd9Sstevel@tonic-gate continue;
2782020b2b6SRod Evans if ((acp = _audit_client(AUDINFO(clmp), almp)) == NULL)
2797c478bd9Sstevel@tonic-gate continue;
2807c478bd9Sstevel@tonic-gate
2812020b2b6SRod Evans DBG_CALL(Dbg_audit_objsearch(clml, DBG_AUD_CALL,
2822020b2b6SRod Evans alp->al_libname, nname, flags, NULL));
2832020b2b6SRod Evans
2842020b2b6SRod Evans leave(alml, thr_flg_reenter);
2857c478bd9Sstevel@tonic-gate nname = (*alp->al_objsearch)(nname, &(acp->ac_cookie), flags);
2868cd45542Sraf (void) enter(thr_flg_reenter);
2872020b2b6SRod Evans
2882020b2b6SRod Evans /*
2892020b2b6SRod Evans * Diagnose any return name that differs from the original name
2902020b2b6SRod Evans * passed to the auditor.
2912020b2b6SRod Evans */
2922020b2b6SRod Evans if (nname && (nname[0] == '\0'))
2932020b2b6SRod Evans nname = NULL;
2942020b2b6SRod Evans if ((nname != oname) || strcmp(nname, oname))
2952020b2b6SRod Evans DBG_CALL(Dbg_audit_objsearch(clml, DBG_AUD_RET,
2962020b2b6SRod Evans alp->al_libname, oname, flags, nname));
2972020b2b6SRod Evans
2982020b2b6SRod Evans if ((oname = nname) == NULL)
2997c478bd9Sstevel@tonic-gate break;
3002020b2b6SRod Evans
3017c478bd9Sstevel@tonic-gate }
3022020b2b6SRod Evans return (oname);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate char *
audit_objsearch(Rt_map * clmp,const char * name,uint_t flags)3067c478bd9Sstevel@tonic-gate audit_objsearch(Rt_map *clmp, const char *name, uint_t flags)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate char *nname = (char *)name;
3092020b2b6SRod Evans uint_t rtldflags;
3107c478bd9Sstevel@tonic-gate
3112a8d6ebaSRod Evans if (rt_critical())
3122a8d6ebaSRod Evans return (nname);
3132a8d6ebaSRod Evans
3142020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJSEARCH))
31757ef7aa9SRod Evans nname = _audit_objsearch(auditors->ad_list, nname,
3187c478bd9Sstevel@tonic-gate clmp, flags);
3197c478bd9Sstevel@tonic-gate if (nname && AUDITORS(clmp) &&
3207c478bd9Sstevel@tonic-gate (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_OBJSEARCH))
32157ef7aa9SRod Evans nname = _audit_objsearch(AUDITORS(clmp)->ad_list, nname,
3227c478bd9Sstevel@tonic-gate clmp, flags);
3237c478bd9Sstevel@tonic-gate
3242020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
3257c478bd9Sstevel@tonic-gate
3265aefb655Srie DBG_CALL(Dbg_libs_audit(LIST(clmp), name, nname));
3277c478bd9Sstevel@tonic-gate return (nname);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate /*
3317247f888Srie * la_activity() caller. Traverse through all audit libraries and call any
3327c478bd9Sstevel@tonic-gate * la_activity() entry points found.
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate static void
_audit_activity(APlist * list,Rt_map * clmp,uint_t flags,Boolean client)3352020b2b6SRod Evans _audit_activity(APlist *list, Rt_map *clmp, uint_t flags, Boolean client)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate Audit_list *alp;
33857ef7aa9SRod Evans Aliste idx;
3397247f888Srie Lm_list *clml = LIST(clmp);
3407c478bd9Sstevel@tonic-gate
34157ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
3427c478bd9Sstevel@tonic-gate Audit_client *acp;
3437247f888Srie Rt_map *almp = alp->al_lmp;
3447247f888Srie Lm_list *alml = LIST(almp);
3452020b2b6SRod Evans uintptr_t *cookie;
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate if (alp->al_activity == 0)
3487c478bd9Sstevel@tonic-gate continue;
3492020b2b6SRod Evans
3502020b2b6SRod Evans /*
3512020b2b6SRod Evans * Determine what cookie is required. Any auditing that
3522020b2b6SRod Evans * originates from the object that heads the link-map list has
3532020b2b6SRod Evans * its own cookie. Local auditors must obtain the cookie that
3542020b2b6SRod Evans * represents the object that heads the link-map list.
3552020b2b6SRod Evans */
3562020b2b6SRod Evans if (client)
3572020b2b6SRod Evans acp = _audit_client(AUDINFO(clmp), almp);
3582020b2b6SRod Evans else
3592020b2b6SRod Evans acp = _audit_get_head_client(clml->lm_head, almp);
3602020b2b6SRod Evans
3612020b2b6SRod Evans if (acp == NULL)
3627c478bd9Sstevel@tonic-gate continue;
3632020b2b6SRod Evans cookie = &(acp->ac_cookie);
3647c478bd9Sstevel@tonic-gate
3657247f888Srie /*
3667247f888Srie * Make sure the audit library only sees one addition/deletion
3677247f888Srie * at a time. This ensures the library doesn't see numerous
3687247f888Srie * events from lazy loading a series of libraries. Keep track
3697247f888Srie * of this caller having called an auditor, so that the
3707247f888Srie * appropriate "consistent" event can be supplied on leaving
3717247f888Srie * ld.so.1.
3727247f888Srie */
3737247f888Srie if ((flags == LA_ACT_ADD) || (flags == LA_ACT_DELETE)) {
3747247f888Srie if (alml->lm_flags & LML_FLG_AUDITNOTIFY)
3757247f888Srie continue;
3767247f888Srie
3777247f888Srie alml->lm_flags |= LML_FLG_AUDITNOTIFY;
3782020b2b6SRod Evans clml->lm_flags |= LML_FLG_ACTAUDIT;
3797247f888Srie } else {
3807247f888Srie if ((alml->lm_flags & LML_FLG_AUDITNOTIFY) == 0)
3817247f888Srie continue;
3827247f888Srie
3837247f888Srie alml->lm_flags &= ~LML_FLG_AUDITNOTIFY;
3847247f888Srie }
3857247f888Srie
3862020b2b6SRod Evans DBG_CALL(Dbg_audit_activity(clml, alp->al_libname,
3872020b2b6SRod Evans NAME(clml->lm_head), flags));
3882020b2b6SRod Evans
3892020b2b6SRod Evans leave(alml, thr_flg_reenter);
3902020b2b6SRod Evans (*alp->al_activity)(cookie, flags);
3918cd45542Sraf (void) enter(thr_flg_reenter);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate void
audit_activity(Rt_map * clmp,uint_t flags)3967c478bd9Sstevel@tonic-gate audit_activity(Rt_map *clmp, uint_t flags)
3977c478bd9Sstevel@tonic-gate {
3982020b2b6SRod Evans Rt_map *lmp;
3992020b2b6SRod Evans Aliste idx;
4002020b2b6SRod Evans uint_t rtldflags;
4017c478bd9Sstevel@tonic-gate
4022a8d6ebaSRod Evans if (rt_critical())
4032a8d6ebaSRod Evans return;
4042a8d6ebaSRod Evans
4052020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_ACTIVITY))
4082020b2b6SRod Evans _audit_activity(auditors->ad_list, clmp, flags, TRUE);
4097c478bd9Sstevel@tonic-gate if (AUDITORS(clmp) &&
4107c478bd9Sstevel@tonic-gate (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_ACTIVITY))
4112020b2b6SRod Evans _audit_activity(AUDITORS(clmp)->ad_list, clmp, flags, TRUE);
4127c478bd9Sstevel@tonic-gate
4132020b2b6SRod Evans for (APLIST_TRAVERSE(aud_activity, idx, lmp)) {
4142020b2b6SRod Evans if ((clmp != lmp) && AUDITORS(lmp) &&
4152020b2b6SRod Evans (AUDITORS(lmp)->ad_flags & LML_TFLG_AUD_ACTIVITY)) {
4162020b2b6SRod Evans _audit_activity(AUDITORS(lmp)->ad_list, lmp, flags,
4172020b2b6SRod Evans FALSE);
4182020b2b6SRod Evans }
4192020b2b6SRod Evans }
4202020b2b6SRod Evans
4212020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
4222020b2b6SRod Evans }
4232020b2b6SRod Evans
4242020b2b6SRod Evans /*
4252020b2b6SRod Evans * Determine whether an auditor is in use by the head link-map object.
4262020b2b6SRod Evans */
4272020b2b6SRod Evans static int
_audit_used_by_head(Rt_map * hlmp,Rt_map * almp)4282020b2b6SRod Evans _audit_used_by_head(Rt_map *hlmp, Rt_map *almp)
4292020b2b6SRod Evans {
4302020b2b6SRod Evans Audit_list *alp;
4312020b2b6SRod Evans Aliste idx;
4322020b2b6SRod Evans
4332020b2b6SRod Evans for (APLIST_TRAVERSE(AUDITORS(hlmp)->ad_list, idx, alp)) {
4342020b2b6SRod Evans if (alp->al_lmp == almp)
4352020b2b6SRod Evans return (1);
4362020b2b6SRod Evans }
4372020b2b6SRod Evans return (0);
4382020b2b6SRod Evans }
4392020b2b6SRod Evans
4402020b2b6SRod Evans /*
4412020b2b6SRod Evans * la_objopen() caller for the head link-map. Global auditors, or an auditor
4422020b2b6SRod Evans * started from the object that heads a link-map list (typically the dynamic
4432020b2b6SRod Evans * executable), are passed to la_objopen(). However, local auditors can
4442020b2b6SRod Evans * provide activity and preinit events, and for these events, a cookie
4452020b2b6SRod Evans * representing the head link-map list object is expected. This routine obtains
4462020b2b6SRod Evans * these cookies from the link-map list lm_cookies element. This element
4472020b2b6SRod Evans * ensures all clients of the same auditor use the same cookie.
4482020b2b6SRod Evans *
4492020b2b6SRod Evans * Although a local auditor will get an la_objopen() call for the object that
4502020b2b6SRod Evans * heads the link-map list of the object being audited, the auditor is not
4512020b2b6SRod Evans * permitted to request binding information for this head object. The head
4522020b2b6SRod Evans * object has already been in existence, and bindings may have been resolved
4532020b2b6SRod Evans * with it. This local auditor is coming into existence too late, and thus we
4542020b2b6SRod Evans * don't allow any bindings to be caught at all.
4552020b2b6SRod Evans */
4562020b2b6SRod Evans static int
_audit_add_head(Rt_map * clmp,Rt_map * hlmp,int preinit,int activity)4572020b2b6SRod Evans _audit_add_head(Rt_map *clmp, Rt_map *hlmp, int preinit, int activity)
4582020b2b6SRod Evans {
4592020b2b6SRod Evans Lm_list *clml = LIST(clmp);
4602020b2b6SRod Evans Lmid_t lmid = get_linkmap_id(clml);
4612020b2b6SRod Evans Audit_list *alp;
4622020b2b6SRod Evans Aliste idx;
4632020b2b6SRod Evans int save = 0;
4642020b2b6SRod Evans
4652020b2b6SRod Evans for (APLIST_TRAVERSE(AUDITORS(clmp)->ad_list, idx, alp)) {
4662020b2b6SRod Evans Audit_client *acp;
4672020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
4682020b2b6SRod Evans Lm_list *alml = LIST(almp);
4692020b2b6SRod Evans uintptr_t *cookie;
4702020b2b6SRod Evans uint_t rtldflags;
4712020b2b6SRod Evans
4722020b2b6SRod Evans /*
4732020b2b6SRod Evans * Ensure this local auditor isn't already in existence as an
4742020b2b6SRod Evans * auditor for the head of the link-map list. If it is, then
4752020b2b6SRod Evans * this auditor will have already receive preinit and activity
4762020b2b6SRod Evans * events.
4772020b2b6SRod Evans */
4782020b2b6SRod Evans if (AUDITORS(hlmp) && _audit_used_by_head(hlmp, almp))
4792020b2b6SRod Evans continue;
4802020b2b6SRod Evans
4812020b2b6SRod Evans /*
4822020b2b6SRod Evans * Create a cookie that represents the object that heads the
4832020b2b6SRod Evans * link-map list. If the cookie already exists, then this
4842020b2b6SRod Evans * auditor has already been established for another objects
4852020b2b6SRod Evans * local auditing. In this case, do not issue a la_objopen()
4862020b2b6SRod Evans * or la_activity() event, as these will have already occurred.
4872020b2b6SRod Evans */
4882020b2b6SRod Evans if ((acp = _audit_get_head_client(clml->lm_head, almp)) != NULL)
4892020b2b6SRod Evans continue;
4902020b2b6SRod Evans if ((acp =
4912020b2b6SRod Evans _audit_create_head_client(clml->lm_head, almp)) == NULL)
4922020b2b6SRod Evans return (0);
4932020b2b6SRod Evans
4942020b2b6SRod Evans cookie = &(acp->ac_cookie);
4952020b2b6SRod Evans save++;
4962020b2b6SRod Evans
4972020b2b6SRod Evans /*
4982020b2b6SRod Evans * Call the la_objopen() if available.
4992020b2b6SRod Evans */
5002020b2b6SRod Evans if (alp->al_objopen) {
5012020b2b6SRod Evans uint_t flags;
5022020b2b6SRod Evans
5032020b2b6SRod Evans DBG_CALL(Dbg_audit_objopen(clml, DBG_AUD_CALL,
5042020b2b6SRod Evans alp->al_libname, NAME(hlmp), 0, FALSE));
5052020b2b6SRod Evans
5062020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
5072020b2b6SRod Evans leave(alml, thr_flg_reenter);
5082020b2b6SRod Evans flags = (*alp->al_objopen)((Link_map *)hlmp, lmid,
5092020b2b6SRod Evans cookie);
5102020b2b6SRod Evans (void) enter(thr_flg_reenter);
5112020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
5122020b2b6SRod Evans
5132020b2b6SRod Evans if (flags) {
5142020b2b6SRod Evans DBG_CALL(Dbg_audit_objopen(clml, DBG_AUD_RET,
5152020b2b6SRod Evans alp->al_libname, NAME(hlmp), flags, TRUE));
5162020b2b6SRod Evans }
5172020b2b6SRod Evans }
5182020b2b6SRod Evans
5192020b2b6SRod Evans /*
5202020b2b6SRod Evans * Call the la_activity() if available.
5212020b2b6SRod Evans */
5222020b2b6SRod Evans if (alp->al_activity) {
5232020b2b6SRod Evans alml->lm_flags |= LML_FLG_AUDITNOTIFY;
5242020b2b6SRod Evans clml->lm_flags |= LML_FLG_ACTAUDIT;
5252020b2b6SRod Evans
5262020b2b6SRod Evans DBG_CALL(Dbg_audit_activity(clml, alp->al_libname,
5272020b2b6SRod Evans NAME(clml->lm_head), LA_ACT_ADD));
5282020b2b6SRod Evans
5292020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
5302020b2b6SRod Evans leave(alml, thr_flg_reenter);
5312020b2b6SRod Evans (*alp->al_activity)(cookie, LA_ACT_ADD);
5322020b2b6SRod Evans (void) enter(thr_flg_reenter);
5332020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
5342020b2b6SRod Evans }
5352020b2b6SRod Evans }
5362020b2b6SRod Evans
5372020b2b6SRod Evans /*
5382020b2b6SRod Evans * If new head link-map cookies have been generated, then maintain
5392020b2b6SRod Evans * any preinit and/or activity requirements.
5402020b2b6SRod Evans */
5412020b2b6SRod Evans if (save) {
5422020b2b6SRod Evans if (preinit && (aplist_append(&aud_preinit, clmp,
5432020b2b6SRod Evans AL_CNT_AUDITORS) == NULL))
5442020b2b6SRod Evans return (0);
5452020b2b6SRod Evans if (activity && (aplist_append(&aud_activity, clmp,
5462020b2b6SRod Evans AL_CNT_AUDITORS) == NULL))
5472020b2b6SRod Evans return (0);
5482020b2b6SRod Evans }
5492020b2b6SRod Evans return (1);
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate * la_objopen() caller. Create an audit information structure for the indicated
5547c478bd9Sstevel@tonic-gate * link-map, regardless of an la_objopen() entry point. This structure is used
5557c478bd9Sstevel@tonic-gate * to supply information to various audit interfaces (see LML_MSK_AUDINFO).
5562020b2b6SRod Evans * Traverse through all audit libraries and call any la_objopen() entry points
5577c478bd9Sstevel@tonic-gate * found.
5587c478bd9Sstevel@tonic-gate */
5597c478bd9Sstevel@tonic-gate static int
_audit_objopen(APlist * list,Rt_map * nlmp,Lmid_t lmid,Audit_info * aip,int * ndx)56057ef7aa9SRod Evans _audit_objopen(APlist *list, Rt_map *nlmp, Lmid_t lmid, Audit_info *aip,
5617c478bd9Sstevel@tonic-gate int *ndx)
5627c478bd9Sstevel@tonic-gate {
5632020b2b6SRod Evans Lm_list *nlml = LIST(nlmp);
5647c478bd9Sstevel@tonic-gate Audit_list *alp;
56557ef7aa9SRod Evans Aliste idx;
5667c478bd9Sstevel@tonic-gate
56757ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
5687c478bd9Sstevel@tonic-gate uint_t flags;
5697c478bd9Sstevel@tonic-gate Audit_client *acp;
5702020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
5712020b2b6SRod Evans Lm_list *alml = LIST(almp);
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate * Associate a cookie with the audit library, and assign the
5757c478bd9Sstevel@tonic-gate * initial cookie as the present link-map.
5767c478bd9Sstevel@tonic-gate */
5777c478bd9Sstevel@tonic-gate acp = &aip->ai_clients[(*ndx)++];
5787c478bd9Sstevel@tonic-gate acp->ac_lmp = alp->al_lmp;
5797c478bd9Sstevel@tonic-gate acp->ac_cookie = (uintptr_t)nlmp;
5807c478bd9Sstevel@tonic-gate
58157ef7aa9SRod Evans if (alp->al_objopen == NULL)
5827c478bd9Sstevel@tonic-gate continue;
5837c478bd9Sstevel@tonic-gate
5842020b2b6SRod Evans DBG_CALL(Dbg_audit_objopen(nlml, DBG_AUD_CALL, alp->al_libname,
5852020b2b6SRod Evans NAME(nlmp), 0, FALSE));
5867c478bd9Sstevel@tonic-gate
5872020b2b6SRod Evans leave(alml, thr_flg_reenter);
5887c478bd9Sstevel@tonic-gate flags = (*alp->al_objopen)((Link_map *)nlmp, lmid,
5897c478bd9Sstevel@tonic-gate &(acp->ac_cookie));
5908cd45542Sraf (void) enter(thr_flg_reenter);
5917c478bd9Sstevel@tonic-gate
5922020b2b6SRod Evans /*
5932020b2b6SRod Evans * Diagnose any flags returned by the auditor.
5942020b2b6SRod Evans */
5952020b2b6SRod Evans if (flags) {
5962020b2b6SRod Evans DBG_CALL(Dbg_audit_objopen(nlml, DBG_AUD_RET,
5972020b2b6SRod Evans alp->al_libname, NAME(nlmp), flags, FALSE));
5982020b2b6SRod Evans }
5992020b2b6SRod Evans
6007c478bd9Sstevel@tonic-gate if (flags & LA_FLG_BINDTO)
6017c478bd9Sstevel@tonic-gate acp->ac_flags |= FLG_AC_BINDTO;
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate if (flags & LA_FLG_BINDFROM) {
6047c478bd9Sstevel@tonic-gate ulong_t pltcnt;
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate acp->ac_flags |= FLG_AC_BINDFROM;
60756deab07SRod Evans
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate * We only need dynamic plt's if a pltenter and/or a
6107c478bd9Sstevel@tonic-gate * pltexit() entry point exist in one of our auditing
6117c478bd9Sstevel@tonic-gate * libraries.
6127c478bd9Sstevel@tonic-gate */
6137c478bd9Sstevel@tonic-gate if (aip->ai_dynplts || (JMPREL(nlmp) == 0) ||
6147c478bd9Sstevel@tonic-gate ((audit_flags & (AF_PLTENTER | AF_PLTEXIT)) == 0))
6157c478bd9Sstevel@tonic-gate continue;
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate * Create one dynplt for every 'PLT' that exists in the
6197c478bd9Sstevel@tonic-gate * object.
6207c478bd9Sstevel@tonic-gate */
6217c478bd9Sstevel@tonic-gate pltcnt = PLTRELSZ(nlmp) / RELENT(nlmp);
6227c478bd9Sstevel@tonic-gate if ((aip->ai_dynplts = calloc(pltcnt,
62356deab07SRod Evans dyn_plt_ent_size)) == NULL)
6247c478bd9Sstevel@tonic-gate return (0);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate return (1);
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate int
audit_objopen(Rt_map * clmp,Rt_map * nlmp)6317c478bd9Sstevel@tonic-gate audit_objopen(Rt_map *clmp, Rt_map *nlmp)
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate Lmid_t lmid = get_linkmap_id(LIST(nlmp));
6342020b2b6SRod Evans int respond = 1, ndx = 0;
6352020b2b6SRod Evans uint_t rtldflags;
6367c478bd9Sstevel@tonic-gate uint_t clients = 0;
6377c478bd9Sstevel@tonic-gate Audit_info *aip;
6387c478bd9Sstevel@tonic-gate
6392a8d6ebaSRod Evans if (rt_critical())
6402a8d6ebaSRod Evans return (respond);
6412a8d6ebaSRod Evans
6427c478bd9Sstevel@tonic-gate /*
6432020b2b6SRod Evans * Determine the number of auditors that can receive information
6442020b2b6SRod Evans * regarding this object. This provides the number of client
6452020b2b6SRod Evans * structures required for this object.
6467c478bd9Sstevel@tonic-gate */
6477c478bd9Sstevel@tonic-gate if (auditors)
6487c478bd9Sstevel@tonic-gate clients = auditors->ad_cnt;
6497c478bd9Sstevel@tonic-gate if (AUDITORS(clmp))
6507c478bd9Sstevel@tonic-gate clients += AUDITORS(clmp)->ad_cnt;
6517c478bd9Sstevel@tonic-gate if ((nlmp != clmp) && AUDITORS(nlmp))
6527c478bd9Sstevel@tonic-gate clients += AUDITORS(nlmp)->ad_cnt;
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate /*
6552020b2b6SRod Evans * Allocate an audit information structure. Each audited object
6562020b2b6SRod Evans * maintains a AUDINFO() structure. As this structure can only be
6572020b2b6SRod Evans * created once all auditors are loaded, a client count can now be
6582020b2b6SRod Evans * computed.
6592020b2b6SRod Evans *
6602020b2b6SRod Evans * The allocation of the audit information structure includes an array
6612020b2b6SRod Evans * of audit clients, 1 per audit library that has been loaded.
6627c478bd9Sstevel@tonic-gate *
6637c478bd9Sstevel@tonic-gate * ---------------
6647c478bd9Sstevel@tonic-gate * | ai_cnt |
6657c478bd9Sstevel@tonic-gate * Audit_info | ai_clients |-------
6667c478bd9Sstevel@tonic-gate * | ai_dynplts | |
6677c478bd9Sstevel@tonic-gate * |---------------| |
6687c478bd9Sstevel@tonic-gate * Audit_client | 1 |<------
6697c478bd9Sstevel@tonic-gate * |---------------|
6707c478bd9Sstevel@tonic-gate * | 2 |
6717c478bd9Sstevel@tonic-gate * .........
6727c478bd9Sstevel@tonic-gate */
6737c478bd9Sstevel@tonic-gate if ((AUDINFO(nlmp) = aip = calloc(1, sizeof (Audit_info) +
67456deab07SRod Evans (sizeof (Audit_client) * clients))) == NULL)
6757c478bd9Sstevel@tonic-gate return (0);
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate aip->ai_cnt = clients;
6787c478bd9Sstevel@tonic-gate aip->ai_clients = (Audit_client *)((uintptr_t)aip +
6797c478bd9Sstevel@tonic-gate sizeof (Audit_info));
6807c478bd9Sstevel@tonic-gate
6812020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate if (auditors)
68457ef7aa9SRod Evans respond = _audit_objopen(auditors->ad_list, nlmp,
6857c478bd9Sstevel@tonic-gate lmid, aip, &ndx);
6867c478bd9Sstevel@tonic-gate if (respond && AUDITORS(clmp))
68757ef7aa9SRod Evans respond = _audit_objopen(AUDITORS(clmp)->ad_list, nlmp,
6887c478bd9Sstevel@tonic-gate lmid, aip, &ndx);
6897c478bd9Sstevel@tonic-gate if (respond && (nlmp != clmp) && AUDITORS(nlmp))
69057ef7aa9SRod Evans respond = _audit_objopen(AUDITORS(nlmp)->ad_list, nlmp,
6917c478bd9Sstevel@tonic-gate lmid, aip, &ndx);
6927c478bd9Sstevel@tonic-gate
6932020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate return (respond);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate /*
6992020b2b6SRod Evans * la_objclose() caller. Traverse through all audit libraries and call any
7007c478bd9Sstevel@tonic-gate * la_objclose() entry points found.
7017c478bd9Sstevel@tonic-gate */
7027c478bd9Sstevel@tonic-gate void
_audit_objclose(APlist * list,Rt_map * lmp)70357ef7aa9SRod Evans _audit_objclose(APlist *list, Rt_map *lmp)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate Audit_list *alp;
70657ef7aa9SRod Evans Aliste idx;
7072020b2b6SRod Evans Lm_list *lml = LIST(lmp);
7087c478bd9Sstevel@tonic-gate
70957ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
7107c478bd9Sstevel@tonic-gate Audit_client *acp;
7112020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
7122020b2b6SRod Evans Lm_list *alml = LIST(almp);
7137c478bd9Sstevel@tonic-gate
71457ef7aa9SRod Evans if (alp->al_objclose == NULL)
7157c478bd9Sstevel@tonic-gate continue;
7162020b2b6SRod Evans if ((acp = _audit_client(AUDINFO(lmp), almp)) == NULL)
7177c478bd9Sstevel@tonic-gate continue;
7187c478bd9Sstevel@tonic-gate
7192020b2b6SRod Evans DBG_CALL(Dbg_audit_objclose(lml, alp->al_libname, NAME(lmp)));
7202020b2b6SRod Evans
7212020b2b6SRod Evans leave(alml, thr_flg_reenter);
7227c478bd9Sstevel@tonic-gate (*alp->al_objclose)(&(acp->ac_cookie));
7238cd45542Sraf (void) enter(thr_flg_reenter);
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate
7272020b2b6SRod Evans /*
7282020b2b6SRod Evans * Determine any la_objclose() requirements. An object that is about to be
7292020b2b6SRod Evans * deleted needs to trigger an la_objclose() event to any associated auditors.
7302020b2b6SRod Evans * In the case of local auditing, a deleted object may have a number of callers,
7312020b2b6SRod Evans * and each of these callers may have their own auditing requirements. To
7322020b2b6SRod Evans * ensure only one la_objclose() event is sent to each auditor, collect the
7332020b2b6SRod Evans * auditors from any callers and make sure there's no duplication.
7342020b2b6SRod Evans */
7352020b2b6SRod Evans inline static void
add_objclose_list(Rt_map * lmp,APlist ** alpp)7362020b2b6SRod Evans add_objclose_list(Rt_map *lmp, APlist **alpp)
7377c478bd9Sstevel@tonic-gate {
7382020b2b6SRod Evans if (AFLAGS(lmp) & LML_TFLG_AUD_OBJCLOSE) {
7392020b2b6SRod Evans Audit_list *alp;
7402020b2b6SRod Evans Aliste idx;
7412020b2b6SRod Evans
7422020b2b6SRod Evans for (APLIST_TRAVERSE(AUDITORS(lmp)->ad_list, idx, alp)) {
7432020b2b6SRod Evans if (aplist_test(alpp, alp, AL_CNT_AUDITORS) == 0)
7442020b2b6SRod Evans return;
7452020b2b6SRod Evans }
7462020b2b6SRod Evans }
7472020b2b6SRod Evans }
7482020b2b6SRod Evans
7492020b2b6SRod Evans void
audit_objclose(Rt_map * lmp,Rt_map * clmp)7502020b2b6SRod Evans audit_objclose(Rt_map *lmp, Rt_map *clmp)
7512020b2b6SRod Evans {
7522020b2b6SRod Evans APlist *alp = NULL;
7532020b2b6SRod Evans uint_t rtldflags;
7547c478bd9Sstevel@tonic-gate
7552a8d6ebaSRod Evans if (rt_critical())
7562a8d6ebaSRod Evans return;
7572a8d6ebaSRod Evans
7582020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJCLOSE))
76157ef7aa9SRod Evans _audit_objclose(auditors->ad_list, lmp);
7627c478bd9Sstevel@tonic-gate
7632020b2b6SRod Evans /*
7642020b2b6SRod Evans * If this link-map list contains local auditors, determine if this
7652020b2b6SRod Evans * object, or any of this objects CALLERS have instantiated auditors
7662020b2b6SRod Evans * that need to know of la_objclose() events.
7672020b2b6SRod Evans */
7682020b2b6SRod Evans if (LIST(lmp)->lm_flags & LML_FLG_LOCAUDIT) {
7692020b2b6SRod Evans Bnd_desc *bdp;
7702020b2b6SRod Evans Aliste idx;
7712020b2b6SRod Evans
7722020b2b6SRod Evans add_objclose_list(lmp, &alp);
7732020b2b6SRod Evans
7742020b2b6SRod Evans for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp))
7752020b2b6SRod Evans add_objclose_list(bdp->b_caller, &alp);
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate
7787c478bd9Sstevel@tonic-gate /*
7792020b2b6SRod Evans * If this close originated from dlclose(), determine whether the caller
7802020b2b6SRod Evans * requires a la_objclose() event.
7812020b2b6SRod Evans */
7822020b2b6SRod Evans if (clmp)
7832020b2b6SRod Evans add_objclose_list(clmp, &alp);
7842020b2b6SRod Evans
7852020b2b6SRod Evans if (alp) {
7862020b2b6SRod Evans _audit_objclose(alp, lmp);
7872020b2b6SRod Evans free((void *)alp);
7882020b2b6SRod Evans }
7892020b2b6SRod Evans
7902020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
7912020b2b6SRod Evans }
7922020b2b6SRod Evans
7932020b2b6SRod Evans /*
7942020b2b6SRod Evans * la_pltenter() caller. Traverse through all audit libraries and call any
7957c478bd9Sstevel@tonic-gate * la_pltenter() entry points found. NOTE: this routine is called via the
7967c478bd9Sstevel@tonic-gate * glue code established in elf_plt_trace_write(), the symbol descriptor is
7977c478bd9Sstevel@tonic-gate * created as part of the glue and for 32bit environments the st_name is a
7987c478bd9Sstevel@tonic-gate * pointer to the real symbol name (ie. it's already been adjusted with the
7997c478bd9Sstevel@tonic-gate * objects base offset). For 64bit environments the st_name remains the
8007c478bd9Sstevel@tonic-gate * original symbol offset and in this case it is used to compute the real name
8017c478bd9Sstevel@tonic-gate * pointer and pass as a separate argument to the auditor.
8027c478bd9Sstevel@tonic-gate */
8037c478bd9Sstevel@tonic-gate static void
_audit_pltenter(APlist * list,Rt_map * rlmp,Rt_map * dlmp,Sym * sym,uint_t ndx,void * regs,uint_t * flags)80457ef7aa9SRod Evans _audit_pltenter(APlist *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym,
8057c478bd9Sstevel@tonic-gate uint_t ndx, void *regs, uint_t *flags)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate Audit_list *alp;
80857ef7aa9SRod Evans Aliste idx;
8092020b2b6SRod Evans Lm_list *rlml = LIST(rlmp);
8107c478bd9Sstevel@tonic-gate #if defined(_ELF64)
8117c478bd9Sstevel@tonic-gate const char *name = (const char *)(sym->st_name + STRTAB(dlmp));
8127c478bd9Sstevel@tonic-gate #else
8137c478bd9Sstevel@tonic-gate const char *name = (const char *)(sym->st_name);
8147c478bd9Sstevel@tonic-gate #endif
8157c478bd9Sstevel@tonic-gate
81657ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
8177c478bd9Sstevel@tonic-gate Audit_client *racp, *dacp;
8182020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
8192020b2b6SRod Evans Lm_list *alml = LIST(almp);
8202020b2b6SRod Evans Addr ovalue = sym->st_value;
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate if (alp->al_pltenter == 0)
8237c478bd9Sstevel@tonic-gate continue;
8242020b2b6SRod Evans if ((racp = _audit_client(AUDINFO(rlmp), almp)) == NULL)
8257c478bd9Sstevel@tonic-gate continue;
8262020b2b6SRod Evans if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
8277c478bd9Sstevel@tonic-gate continue;
8287c478bd9Sstevel@tonic-gate if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
8297c478bd9Sstevel@tonic-gate ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
8307c478bd9Sstevel@tonic-gate continue;
8317c478bd9Sstevel@tonic-gate
8322020b2b6SRod Evans DBG_CALL(Dbg_audit_pltenter(rlml, DBG_AUD_CALL,
8332020b2b6SRod Evans alp->al_libname, name, ovalue));
8342020b2b6SRod Evans
8352020b2b6SRod Evans leave(alml, thr_flg_reenter);
8367c478bd9Sstevel@tonic-gate sym->st_value = (Addr)(*alp->al_pltenter)(sym, ndx,
8377c478bd9Sstevel@tonic-gate &(racp->ac_cookie), &(dacp->ac_cookie), regs,
8387247f888Srie /* BEGIN CSTYLED */
8397c478bd9Sstevel@tonic-gate #if defined(_ELF64)
8407c478bd9Sstevel@tonic-gate flags, name);
8417c478bd9Sstevel@tonic-gate #else
8427c478bd9Sstevel@tonic-gate flags);
8437c478bd9Sstevel@tonic-gate #endif
8447247f888Srie /* END CSTYLED */
8458cd45542Sraf (void) enter(thr_flg_reenter);
8467c478bd9Sstevel@tonic-gate
8472020b2b6SRod Evans if (ovalue != sym->st_value) {
8482020b2b6SRod Evans DBG_CALL(Dbg_audit_pltenter(rlml, DBG_AUD_RET,
8492020b2b6SRod Evans alp->al_libname, name, sym->st_value));
8502020b2b6SRod Evans }
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate Addr
audit_pltenter(Rt_map * rlmp,Rt_map * dlmp,Sym * sym,uint_t ndx,void * regs,uint_t * flags)8557c478bd9Sstevel@tonic-gate audit_pltenter(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx,
8567c478bd9Sstevel@tonic-gate void *regs, uint_t *flags)
8577c478bd9Sstevel@tonic-gate {
8582020b2b6SRod Evans Sym nsym = *sym;
8592020b2b6SRod Evans uint_t rtldflags;
8607c478bd9Sstevel@tonic-gate
8612a8d6ebaSRod Evans if (rt_critical())
8622020b2b6SRod Evans return (nsym.st_value);
8632a8d6ebaSRod Evans
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate * We're effectively entering ld.so.1 from user (glue) code.
8667c478bd9Sstevel@tonic-gate */
8678cd45542Sraf (void) enter(0);
8682020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTENTER))
8712020b2b6SRod Evans _audit_pltenter(auditors->ad_list, rlmp, dlmp, &nsym,
8727c478bd9Sstevel@tonic-gate ndx, regs, flags);
8737c478bd9Sstevel@tonic-gate if (AUDITORS(rlmp) &&
8747c478bd9Sstevel@tonic-gate (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTENTER))
8752020b2b6SRod Evans _audit_pltenter(AUDITORS(rlmp)->ad_list, rlmp, dlmp, &nsym,
8767c478bd9Sstevel@tonic-gate ndx, regs, flags);
8777c478bd9Sstevel@tonic-gate
8782020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
8798cd45542Sraf leave(LIST(rlmp), 0);
8807c478bd9Sstevel@tonic-gate
8812020b2b6SRod Evans return (nsym.st_value);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate /*
8852020b2b6SRod Evans * la_pltexit() caller. Traverse through all audit libraries and call any
8867c478bd9Sstevel@tonic-gate * la_pltexit() entry points found. See notes above (_audit_pltenter) for
8877c478bd9Sstevel@tonic-gate * discussion on st_name.
8887c478bd9Sstevel@tonic-gate */
8897c478bd9Sstevel@tonic-gate static Addr
_audit_pltexit(APlist * list,uintptr_t retval,Rt_map * rlmp,Rt_map * dlmp,Sym * sym,uint_t ndx)89057ef7aa9SRod Evans _audit_pltexit(APlist *list, uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp,
8917c478bd9Sstevel@tonic-gate Sym *sym, uint_t ndx)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate Audit_list *alp;
89457ef7aa9SRod Evans Aliste idx;
8957c478bd9Sstevel@tonic-gate #if defined(_ELF64)
8967c478bd9Sstevel@tonic-gate const char *name = (const char *)(sym->st_name + STRTAB(dlmp));
8972020b2b6SRod Evans #else
8982020b2b6SRod Evans const char *name = (const char *)(sym->st_name);
8997c478bd9Sstevel@tonic-gate #endif
9002020b2b6SRod Evans Lm_list *rlml = LIST(rlmp);
9017c478bd9Sstevel@tonic-gate
90257ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
9037c478bd9Sstevel@tonic-gate Audit_client *racp, *dacp;
9042020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
9052020b2b6SRod Evans Lm_list *alml = LIST(almp);
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate if (alp->al_pltexit == 0)
9087c478bd9Sstevel@tonic-gate continue;
9092020b2b6SRod Evans if ((racp = _audit_client(AUDINFO(rlmp), almp)) == NULL)
9107c478bd9Sstevel@tonic-gate continue;
9112020b2b6SRod Evans if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
9127c478bd9Sstevel@tonic-gate continue;
9137c478bd9Sstevel@tonic-gate if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
9147c478bd9Sstevel@tonic-gate ((dacp->ac_flags & FLG_AC_BINDTO) == 0))
9157c478bd9Sstevel@tonic-gate continue;
9167c478bd9Sstevel@tonic-gate
9172020b2b6SRod Evans DBG_CALL(Dbg_audit_pltexit(rlml, alp->al_libname, name));
9182020b2b6SRod Evans
9192020b2b6SRod Evans leave(alml, thr_flg_reenter);
9207c478bd9Sstevel@tonic-gate retval = (*alp->al_pltexit)(sym, ndx,
9217c478bd9Sstevel@tonic-gate &(racp->ac_cookie), &(dacp->ac_cookie),
9227247f888Srie /* BEGIN CSTYLED */
9237c478bd9Sstevel@tonic-gate #if defined(_ELF64)
9247c478bd9Sstevel@tonic-gate retval, name);
9257c478bd9Sstevel@tonic-gate #else
9267c478bd9Sstevel@tonic-gate retval);
9277c478bd9Sstevel@tonic-gate #endif
9287247f888Srie /* END CSTYLED */
9298cd45542Sraf (void) enter(thr_flg_reenter);
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate return (retval);
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate Addr
audit_pltexit(uintptr_t retval,Rt_map * rlmp,Rt_map * dlmp,Sym * sym,uint_t ndx)9357c478bd9Sstevel@tonic-gate audit_pltexit(uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp, Sym *sym,
9367c478bd9Sstevel@tonic-gate uint_t ndx)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate uintptr_t _retval = retval;
9392020b2b6SRod Evans uint_t rtldflags;
9407c478bd9Sstevel@tonic-gate
9412a8d6ebaSRod Evans if (rt_critical())
9422a8d6ebaSRod Evans return (_retval);
9432a8d6ebaSRod Evans
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate * We're effectively entering ld.so.1 from user (glue) code.
9467c478bd9Sstevel@tonic-gate */
9478cd45542Sraf (void) enter(0);
9482020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTEXIT))
95157ef7aa9SRod Evans _retval = _audit_pltexit(auditors->ad_list, _retval,
9527c478bd9Sstevel@tonic-gate rlmp, dlmp, sym, ndx);
9537c478bd9Sstevel@tonic-gate if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTEXIT))
95457ef7aa9SRod Evans _retval = _audit_pltexit(AUDITORS(rlmp)->ad_list, _retval,
9557c478bd9Sstevel@tonic-gate rlmp, dlmp, sym, ndx);
9567c478bd9Sstevel@tonic-gate
9572020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
9588cd45542Sraf leave(LIST(rlmp), 0);
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate return (_retval);
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate /*
9652020b2b6SRod Evans * la_symbind() caller. Traverse through all audit libraries and call any
9667c478bd9Sstevel@tonic-gate * la_symbind() entry points found.
9677c478bd9Sstevel@tonic-gate */
9687c478bd9Sstevel@tonic-gate static Addr
_audit_symbind(APlist * list,Rt_map * rlmp,Rt_map * dlmp,Sym * sym,uint_t ndx,uint_t * flags,int * called)96957ef7aa9SRod Evans _audit_symbind(APlist *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx,
9707c478bd9Sstevel@tonic-gate uint_t *flags, int *called)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate Audit_list *alp;
97357ef7aa9SRod Evans Aliste idx;
9742020b2b6SRod Evans Lm_list *rlml = LIST(rlmp);
9757c478bd9Sstevel@tonic-gate #if defined(_ELF64)
9767c478bd9Sstevel@tonic-gate const char *name = (const char *)(sym->st_name + STRTAB(dlmp));
9777c478bd9Sstevel@tonic-gate #else
9787c478bd9Sstevel@tonic-gate const char *name = (const char *)(sym->st_name);
9797c478bd9Sstevel@tonic-gate #endif
9807c478bd9Sstevel@tonic-gate
98157ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
9827c478bd9Sstevel@tonic-gate Audit_client *racp, *dacp;
9832020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
9842020b2b6SRod Evans Lm_list *alml = LIST(almp);
9852020b2b6SRod Evans Addr ovalue = sym->st_value;
9862020b2b6SRod Evans uint_t lflags, oflags = *flags;
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate if (alp->al_symbind == 0)
9897c478bd9Sstevel@tonic-gate continue;
990*38f4bdddSBryan Cantrill
991*38f4bdddSBryan Cantrill if ((racp = _audit_client(AUDINFO(rlmp), almp)) != NULL &&
992*38f4bdddSBryan Cantrill (racp->ac_flags & FLG_AC_BINDFROM) == 0)
9937c478bd9Sstevel@tonic-gate continue;
994*38f4bdddSBryan Cantrill
9952020b2b6SRod Evans if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
9967c478bd9Sstevel@tonic-gate continue;
997*38f4bdddSBryan Cantrill
998*38f4bdddSBryan Cantrill if ((dacp->ac_flags & FLG_AC_BINDTO) == 0)
9997c478bd9Sstevel@tonic-gate continue;
10007c478bd9Sstevel@tonic-gate
10017c478bd9Sstevel@tonic-gate /*
1002*38f4bdddSBryan Cantrill * The la_symbind interface is only called when the destination
1003*38f4bdddSBryan Cantrill * object has been identified as BINDTO and either the
1004*38f4bdddSBryan Cantrill * destination object is being locally audited or the calling
1005*38f4bdddSBryan Cantrill * object has been identified as BINDFROM. Use a local version
1006*38f4bdddSBryan Cantrill * of the flags, so that any user update can be collected.
10077c478bd9Sstevel@tonic-gate */
10082020b2b6SRod Evans (*called)++;
10092020b2b6SRod Evans lflags = (oflags & ~(LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
10107c478bd9Sstevel@tonic-gate
10112020b2b6SRod Evans DBG_CALL(Dbg_audit_symbind(rlml, DBG_AUD_CALL,
10122020b2b6SRod Evans alp->al_libname, name, ovalue, oflags));
10132020b2b6SRod Evans
10142020b2b6SRod Evans leave(alml, thr_flg_reenter);
1015*38f4bdddSBryan Cantrill sym->st_value = (*alp->al_symbind)(sym, ndx, racp == NULL ?
1016*38f4bdddSBryan Cantrill NULL : &(racp->ac_cookie), &(dacp->ac_cookie),
10177247f888Srie /* BEGIN CSTYLED */
10187c478bd9Sstevel@tonic-gate #if defined(_ELF64)
10197c478bd9Sstevel@tonic-gate &lflags, name);
10207c478bd9Sstevel@tonic-gate #else
10217c478bd9Sstevel@tonic-gate &lflags);
10227c478bd9Sstevel@tonic-gate #endif
10237247f888Srie /* END CSTYLED */
10248cd45542Sraf (void) enter(thr_flg_reenter);
10257c478bd9Sstevel@tonic-gate
10267c478bd9Sstevel@tonic-gate /*
10277c478bd9Sstevel@tonic-gate * If the auditor indicated that they did not want to process
10287c478bd9Sstevel@tonic-gate * pltenter, or pltexit audits for this symbol, retain this
10297c478bd9Sstevel@tonic-gate * information. Also retain whether an alternative symbol value
10307c478bd9Sstevel@tonic-gate * has been supplied.
10317c478bd9Sstevel@tonic-gate */
10327c478bd9Sstevel@tonic-gate *flags |= (lflags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
10332020b2b6SRod Evans if ((ovalue != sym->st_value) &&
10342020b2b6SRod Evans (alp->al_vernum >= LAV_VERSION2))
10357c478bd9Sstevel@tonic-gate *flags |= LA_SYMB_ALTVALUE;
10367c478bd9Sstevel@tonic-gate
10372020b2b6SRod Evans if ((ovalue != sym->st_value) || (oflags != *flags)) {
10382020b2b6SRod Evans DBG_CALL(Dbg_audit_symbind(rlml, DBG_AUD_RET,
10392020b2b6SRod Evans alp->al_libname, name, sym->st_value, *flags));
10402020b2b6SRod Evans }
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate return (sym->st_value);
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate Addr
audit_symbind(Rt_map * rlmp,Rt_map * dlmp,Sym * sym,uint_t ndx,Addr value,uint_t * flags)10467c478bd9Sstevel@tonic-gate audit_symbind(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, Addr value,
10477c478bd9Sstevel@tonic-gate uint_t *flags)
10487c478bd9Sstevel@tonic-gate {
10492020b2b6SRod Evans Sym nsym;
10502020b2b6SRod Evans int called = 0;
10512020b2b6SRod Evans uint_t rtldflags;
10527c478bd9Sstevel@tonic-gate
10537c478bd9Sstevel@tonic-gate /*
10547c478bd9Sstevel@tonic-gate * Construct a new symbol from that supplied but with the real address.
10557c478bd9Sstevel@tonic-gate * In the 64-bit world the st_name field is only 32-bits which isn't
10567c478bd9Sstevel@tonic-gate * big enough to hold a character pointer. We pass this pointer as a
10577c478bd9Sstevel@tonic-gate * separate parameter for 64-bit audit libraries.
10587c478bd9Sstevel@tonic-gate */
10592020b2b6SRod Evans nsym = *sym;
10602020b2b6SRod Evans nsym.st_value = value;
10617c478bd9Sstevel@tonic-gate
10622a8d6ebaSRod Evans if (rt_critical())
10632020b2b6SRod Evans return (nsym.st_value);
10642a8d6ebaSRod Evans
10657c478bd9Sstevel@tonic-gate #if !defined(_ELF64)
10662020b2b6SRod Evans nsym.st_name += (Word)STRTAB(dlmp);
10677c478bd9Sstevel@tonic-gate #endif
10682020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_SYMBIND))
10712020b2b6SRod Evans nsym.st_value = _audit_symbind(auditors->ad_list,
10722020b2b6SRod Evans rlmp, dlmp, &nsym, ndx, flags, &called);
1073*38f4bdddSBryan Cantrill
10747c478bd9Sstevel@tonic-gate if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_SYMBIND))
10752020b2b6SRod Evans nsym.st_value = _audit_symbind(AUDITORS(rlmp)->ad_list,
10762020b2b6SRod Evans rlmp, dlmp, &nsym, ndx, flags, &called);
10777c478bd9Sstevel@tonic-gate
1078*38f4bdddSBryan Cantrill if (dlmp != rlmp && AUDITORS(dlmp) &&
1079*38f4bdddSBryan Cantrill (AUDITORS(dlmp)->ad_flags & LML_TFLG_AUD_SYMBIND)) {
1080*38f4bdddSBryan Cantrill nsym.st_value = _audit_symbind(AUDITORS(dlmp)->ad_list,
1081*38f4bdddSBryan Cantrill rlmp, dlmp, &nsym, ndx, flags, &called);
1082*38f4bdddSBryan Cantrill }
1083*38f4bdddSBryan Cantrill
10847c478bd9Sstevel@tonic-gate /*
10857c478bd9Sstevel@tonic-gate * If no la_symbind() was called for this interface, fabricate that no
10867c478bd9Sstevel@tonic-gate * la_pltenter, or la_pltexit is required. This helps reduce the glue
10877c478bd9Sstevel@tonic-gate * code created for further auditing.
10887c478bd9Sstevel@tonic-gate */
10892020b2b6SRod Evans if (called == 0)
10907c478bd9Sstevel@tonic-gate *flags |= (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
10917c478bd9Sstevel@tonic-gate
10922020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
10937c478bd9Sstevel@tonic-gate
10942020b2b6SRod Evans return (nsym.st_value);
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate /*
10987247f888Srie * la_preinit() caller. Traverse through all audit libraries and call any
10997c478bd9Sstevel@tonic-gate * la_preinit() entry points found.
11007c478bd9Sstevel@tonic-gate */
11017c478bd9Sstevel@tonic-gate static void
_audit_preinit(APlist * list,Rt_map * clmp,Boolean client)11022020b2b6SRod Evans _audit_preinit(APlist *list, Rt_map *clmp, Boolean client)
11037c478bd9Sstevel@tonic-gate {
11047c478bd9Sstevel@tonic-gate Audit_list *alp;
110557ef7aa9SRod Evans Aliste idx;
11062020b2b6SRod Evans Lm_list *clml = LIST(clmp);
11077c478bd9Sstevel@tonic-gate
110857ef7aa9SRod Evans for (APLIST_TRAVERSE(list, idx, alp)) {
11097c478bd9Sstevel@tonic-gate Audit_client *acp;
11102020b2b6SRod Evans Rt_map *almp = alp->al_lmp;
11112020b2b6SRod Evans Lm_list *alml = LIST(almp);
11122020b2b6SRod Evans uintptr_t *cookie;
11137c478bd9Sstevel@tonic-gate
11147c478bd9Sstevel@tonic-gate if (alp->al_preinit == 0)
11157c478bd9Sstevel@tonic-gate continue;
11167c478bd9Sstevel@tonic-gate
11172020b2b6SRod Evans /*
11182020b2b6SRod Evans * Determine what cookie is required. Any auditing that
11192020b2b6SRod Evans * originates from the object that heads the link-map list has
11202020b2b6SRod Evans * its own cookie. Local auditors must obtain the cookie that
11212020b2b6SRod Evans * represents the object that heads the link-map list.
11222020b2b6SRod Evans */
11232020b2b6SRod Evans if (client)
11242020b2b6SRod Evans acp = _audit_client(AUDINFO(clmp), almp);
11252020b2b6SRod Evans else
11262020b2b6SRod Evans acp = _audit_get_head_client(clml->lm_head, almp);
11272020b2b6SRod Evans
11282020b2b6SRod Evans if (acp == NULL)
11292020b2b6SRod Evans continue;
11302020b2b6SRod Evans cookie = &(acp->ac_cookie);
11312020b2b6SRod Evans
11322020b2b6SRod Evans DBG_CALL(Dbg_audit_preinit(clml, alp->al_libname,
11332020b2b6SRod Evans NAME(clml->lm_head)));
11342020b2b6SRod Evans
11352020b2b6SRod Evans leave(alml, thr_flg_reenter);
11362020b2b6SRod Evans (*alp->al_preinit)(cookie);
11378cd45542Sraf (void) enter(thr_flg_reenter);
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate }
11407c478bd9Sstevel@tonic-gate
11417c478bd9Sstevel@tonic-gate void
audit_preinit(Rt_map * mlmp)11422020b2b6SRod Evans audit_preinit(Rt_map *mlmp)
11437c478bd9Sstevel@tonic-gate {
11442020b2b6SRod Evans Rt_map *clmp;
11452020b2b6SRod Evans Aliste idx;
11462020b2b6SRod Evans uint_t rtldflags;
11477c478bd9Sstevel@tonic-gate
11482a8d6ebaSRod Evans if (rt_critical())
11492a8d6ebaSRod Evans return;
11502a8d6ebaSRod Evans
11512020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
11527c478bd9Sstevel@tonic-gate
11537c478bd9Sstevel@tonic-gate if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PREINIT))
11542020b2b6SRod Evans _audit_preinit(auditors->ad_list, mlmp, TRUE);
11557c478bd9Sstevel@tonic-gate
11562020b2b6SRod Evans if (AUDITORS(mlmp) && (AUDITORS(mlmp)->ad_flags & LML_TFLG_AUD_PREINIT))
11572020b2b6SRod Evans _audit_preinit(AUDITORS(mlmp)->ad_list, mlmp, TRUE);
11582020b2b6SRod Evans
11592020b2b6SRod Evans for (APLIST_TRAVERSE(aud_preinit, idx, clmp)) {
11602020b2b6SRod Evans if (AUDITORS(clmp) &&
11612020b2b6SRod Evans (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_PREINIT))
11622020b2b6SRod Evans _audit_preinit(AUDITORS(clmp)->ad_list, clmp, FALSE);
11632020b2b6SRod Evans }
11642020b2b6SRod Evans
11652020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
11667c478bd9Sstevel@tonic-gate }
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate /*
11697c478bd9Sstevel@tonic-gate * Clean up (free) an audit descriptor. First, gather a list of all handles,
11707c478bd9Sstevel@tonic-gate * and then close each one down. This is done rather than using the handles
11717c478bd9Sstevel@tonic-gate * directly from the auditors, as the audit list can be torn down as a result
11727c478bd9Sstevel@tonic-gate * of the dlclose. In other words, what you're pointing at can be removed
11732020b2b6SRod Evans * while you're still pointing at it.
11747c478bd9Sstevel@tonic-gate */
11757c478bd9Sstevel@tonic-gate void
audit_desc_cleanup(Rt_map * clmp)11767247f888Srie audit_desc_cleanup(Rt_map *clmp)
11777c478bd9Sstevel@tonic-gate {
11787247f888Srie Audit_desc *adp = AUDITORS(clmp);
11797c478bd9Sstevel@tonic-gate Audit_list *alp;
118057ef7aa9SRod Evans Aliste idx;
1181cce0e03bSab196087 APlist *ghalp = NULL;
11827c478bd9Sstevel@tonic-gate
118357ef7aa9SRod Evans if (adp == NULL)
11847c478bd9Sstevel@tonic-gate return;
11857c478bd9Sstevel@tonic-gate if (adp->ad_name)
11867c478bd9Sstevel@tonic-gate free(adp->ad_name);
11877c478bd9Sstevel@tonic-gate
118857ef7aa9SRod Evans for (APLIST_TRAVERSE(adp->ad_list, idx, alp))
1189cce0e03bSab196087 (void) aplist_append(&ghalp, alp->al_ghp, AL_CNT_GROUPS);
11907c478bd9Sstevel@tonic-gate
119157ef7aa9SRod Evans free(adp->ad_list);
119257ef7aa9SRod Evans adp->ad_list = NULL;
11937c478bd9Sstevel@tonic-gate
11947247f888Srie free(adp);
11952020b2b6SRod Evans
11962020b2b6SRod Evans /*
11972020b2b6SRod Evans * Indicate that the caller is no longer being audited.
11982020b2b6SRod Evans */
119957ef7aa9SRod Evans AUDITORS(clmp) = NULL;
12002020b2b6SRod Evans AFLAGS(clmp) &= ~LML_TFLG_AUD_MASK;
12017247f888Srie
12027c478bd9Sstevel@tonic-gate if (ghalp) {
1203cce0e03bSab196087 Grp_hdl *ghp;
1204cce0e03bSab196087 Aliste idx;
12057c478bd9Sstevel@tonic-gate
1206cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx, ghp)) {
1207cce0e03bSab196087 (void) dlclose_intn(ghp, clmp);
12087247f888Srie }
12097c478bd9Sstevel@tonic-gate free(ghalp);
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate
12137c478bd9Sstevel@tonic-gate /*
12142020b2b6SRod Evans * Objects that establish local auditors may have been added to preinit or
12152020b2b6SRod Evans * activity lists. Remove the object from this list if it is present.
12162020b2b6SRod Evans */
12172020b2b6SRod Evans static void
remove_auditor(APlist * alp,Rt_map * clmp)12182020b2b6SRod Evans remove_auditor(APlist *alp, Rt_map *clmp)
12192020b2b6SRod Evans {
12202020b2b6SRod Evans Rt_map *lmp;
12212020b2b6SRod Evans Aliste idx;
12222020b2b6SRod Evans
12232020b2b6SRod Evans for (APLIST_TRAVERSE(alp, idx, lmp)) {
12242020b2b6SRod Evans if (lmp == clmp) {
12252020b2b6SRod Evans aplist_delete(alp, &idx);
12262020b2b6SRod Evans return;
12272020b2b6SRod Evans }
12282020b2b6SRod Evans }
12292020b2b6SRod Evans }
12302020b2b6SRod Evans
12312020b2b6SRod Evans /*
12327c478bd9Sstevel@tonic-gate * Clean up (free) an audit information structure.
12337c478bd9Sstevel@tonic-gate */
12347c478bd9Sstevel@tonic-gate void
audit_info_cleanup(Rt_map * clmp)12357247f888Srie audit_info_cleanup(Rt_map *clmp)
12367c478bd9Sstevel@tonic-gate {
12377247f888Srie Audit_info *aip = AUDINFO(clmp);
12387247f888Srie
123957ef7aa9SRod Evans if (aip == NULL)
12407c478bd9Sstevel@tonic-gate return;
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate if (aip->ai_dynplts)
12437c478bd9Sstevel@tonic-gate free(aip->ai_dynplts);
12442020b2b6SRod Evans
12452020b2b6SRod Evans if (aud_preinit)
12462020b2b6SRod Evans remove_auditor(aud_preinit, clmp);
12472020b2b6SRod Evans if (aud_activity)
12482020b2b6SRod Evans remove_auditor(aud_activity, clmp);
12492020b2b6SRod Evans
12507c478bd9Sstevel@tonic-gate free(aip);
12517c478bd9Sstevel@tonic-gate }
12527c478bd9Sstevel@tonic-gate
12537c478bd9Sstevel@tonic-gate /*
12547c478bd9Sstevel@tonic-gate * Create a data structure of symbol lookup names and associated flags to help
12557c478bd9Sstevel@tonic-gate * simplify audit_symget() use.
12567c478bd9Sstevel@tonic-gate */
12577c478bd9Sstevel@tonic-gate typedef struct {
12587c478bd9Sstevel@tonic-gate Msg sname;
12597c478bd9Sstevel@tonic-gate uint_t alflag;
12607c478bd9Sstevel@tonic-gate uint_t auflag;
12617c478bd9Sstevel@tonic-gate } Aud_info;
12627c478bd9Sstevel@tonic-gate
12637c478bd9Sstevel@tonic-gate static const Aud_info aud_info[] = {
12642020b2b6SRod Evans { MSG_SYM_LAVERSION, 0, 0 }, /* MSG_ORIG(MSG_SYM_LAVERSION) */
12657c478bd9Sstevel@tonic-gate { MSG_SYM_LAPREINIT, /* MSG_ORIG(MSG_SYM_LAPREINIT) */
12667c478bd9Sstevel@tonic-gate LML_TFLG_AUD_PREINIT, 0 },
12677c478bd9Sstevel@tonic-gate { MSG_SYM_LAOBJSEARCH, /* MSG_ORIG(MSG_SYM_LAOBJSEARCH) */
12687c478bd9Sstevel@tonic-gate LML_TFLG_AUD_OBJSEARCH, 0 },
12697c478bd9Sstevel@tonic-gate { MSG_SYM_LAOBJOPEN, /* MSG_ORIG(MSG_SYM_LAOBJOPEN) */
12707c478bd9Sstevel@tonic-gate LML_TFLG_AUD_OBJOPEN, 0 },
12717c478bd9Sstevel@tonic-gate { MSG_SYM_LAOBJFILTER, /* MSG_ORIG(MSG_SYM_LAOBJFILTER */
12727c478bd9Sstevel@tonic-gate LML_TFLG_AUD_OBJFILTER, 0 },
12737c478bd9Sstevel@tonic-gate { MSG_SYM_LAOBJCLOSE, /* MSG_ORIG(MSG_SYM_LAOBJCLOSE) */
12747c478bd9Sstevel@tonic-gate LML_TFLG_AUD_OBJCLOSE, 0 },
12757c478bd9Sstevel@tonic-gate { MSG_SYM_LAACTIVITY, /* MSG_ORIG(MSG_SYM_LAACTIVITY) */
12767c478bd9Sstevel@tonic-gate LML_TFLG_AUD_ACTIVITY, 0 },
12777c478bd9Sstevel@tonic-gate
12787c478bd9Sstevel@tonic-gate #if defined(_ELF64)
12797c478bd9Sstevel@tonic-gate { MSG_SYM_LASYMBIND_64, /* MSG_ORIG(MSG_SYM_LASYMBIND_64) */
12807c478bd9Sstevel@tonic-gate #else
12817c478bd9Sstevel@tonic-gate { MSG_SYM_LASYMBIND, /* MSG_ORIG(MSG_SYM_LASYMBIND) */
12827c478bd9Sstevel@tonic-gate #endif
12837c478bd9Sstevel@tonic-gate LML_TFLG_AUD_SYMBIND, 0 },
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate #if defined(__sparcv9)
12867c478bd9Sstevel@tonic-gate { MSG_SYM_LAV9PLTENTER, /* MSG_ORIG(MSG_SYM_LAV9PLTENTER) */
12877c478bd9Sstevel@tonic-gate #elif defined(__sparc)
12887c478bd9Sstevel@tonic-gate { MSG_SYM_LAV8PLTENTER, /* MSG_ORIG(MSG_SYM_LAV8PLTENTER) */
12897c478bd9Sstevel@tonic-gate #elif defined(__amd64)
12907c478bd9Sstevel@tonic-gate { MSG_SYM_LAAMD64PLTENTER, /* MSG_ORIG(MSG_SYM_LAAMD64PLTENTER) */
129102ca3e02Srie #elif defined(__i386)
12927c478bd9Sstevel@tonic-gate { MSG_SYM_LAX86PLTENTER, /* MSG_ORIG(MSG_SYM_LAX86PLTENTER) */
12937c478bd9Sstevel@tonic-gate #else
12947c478bd9Sstevel@tonic-gate #error platform not defined!
12957c478bd9Sstevel@tonic-gate #endif
12967c478bd9Sstevel@tonic-gate LML_TFLG_AUD_PLTENTER, AF_PLTENTER },
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate #if defined(_ELF64)
12997c478bd9Sstevel@tonic-gate { MSG_SYM_LAPLTEXIT_64, /* MSG_ORIG(MSG_SYM_LAPLTEXIT_64) */
13007c478bd9Sstevel@tonic-gate #else
13017c478bd9Sstevel@tonic-gate { MSG_SYM_LAPLTEXIT, /* MSG_ORIG(MSG_SYM_LAPLTEXIT) */
13027c478bd9Sstevel@tonic-gate #endif
13037c478bd9Sstevel@tonic-gate LML_TFLG_AUD_PLTEXIT, AF_PLTEXIT }
13047c478bd9Sstevel@tonic-gate };
13057c478bd9Sstevel@tonic-gate
13067c478bd9Sstevel@tonic-gate #define AI_LAVERSION 0
13077c478bd9Sstevel@tonic-gate #define AI_LAPREINIT 1
13087c478bd9Sstevel@tonic-gate #define AI_LAOBJSEARCH 2
13097c478bd9Sstevel@tonic-gate #define AI_LAOBJOPEN 3
13107c478bd9Sstevel@tonic-gate #define AI_LAOBJFILTER 4
13117c478bd9Sstevel@tonic-gate #define AI_LAOBJCLOSE 5
13127c478bd9Sstevel@tonic-gate #define AI_LAACTIVITY 6
13137c478bd9Sstevel@tonic-gate #define AI_LASYMBIND 7
13147c478bd9Sstevel@tonic-gate #define AI_LAPLTENTER 8
13157c478bd9Sstevel@tonic-gate #define AI_LAPLTEXIT 9
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate static Addr
audit_symget(Audit_list * alp,int info,int * in_nfavl)13189aa23310Srie audit_symget(Audit_list *alp, int info, int *in_nfavl)
13197c478bd9Sstevel@tonic-gate {
132008278a5eSRod Evans Rt_map *lmp = alp->al_lmp;
13217c478bd9Sstevel@tonic-gate const char *sname = MSG_ORIG(aud_info[info].sname);
13227c478bd9Sstevel@tonic-gate uint_t alflag = aud_info[info].alflag;
13237c478bd9Sstevel@tonic-gate uint_t auflag = aud_info[info].auflag;
13247c478bd9Sstevel@tonic-gate uint_t binfo;
13257c478bd9Sstevel@tonic-gate Slookup sl;
132608278a5eSRod Evans Sresult sr;
13277c478bd9Sstevel@tonic-gate
132875e7992aSrie /*
132908278a5eSRod Evans * Initialize the symbol lookup, and symbol result, data structures.
133075e7992aSrie */
133175e7992aSrie SLOOKUP_INIT(sl, sname, lml_rtld.lm_head, lmp, ld_entry_cnt,
133208278a5eSRod Evans 0, 0, 0, 0, (LKUP_FIRST | LKUP_DLSYM));
133308278a5eSRod Evans SRESULT_INIT(sr, sname);
13347c478bd9Sstevel@tonic-gate
133508278a5eSRod Evans if (LM_LOOKUP_SYM(lmp)(&sl, &sr, &binfo, in_nfavl)) {
133608278a5eSRod Evans Addr addr = sr.sr_sym->st_value;
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate if (!(FLAGS(lmp) & FLG_RT_FIXED))
13397c478bd9Sstevel@tonic-gate addr += ADDR(lmp);
13407c478bd9Sstevel@tonic-gate
13417c478bd9Sstevel@tonic-gate if (alflag)
13427c478bd9Sstevel@tonic-gate alp->al_flags |= alflag;
13437c478bd9Sstevel@tonic-gate if (auflag)
13447c478bd9Sstevel@tonic-gate audit_flags |= auflag;
13457c478bd9Sstevel@tonic-gate
13462020b2b6SRod Evans /*
13472020b2b6SRod Evans * Note, unlike most other diagnostics, where we wish to
13482020b2b6SRod Evans * identify the lmid of the caller, here we use the lmid of
13492020b2b6SRod Evans * the auditor itself to show the association of the auditor
13502020b2b6SRod Evans * and the interfaces it provides.
13512020b2b6SRod Evans */
13525aefb655Srie DBG_CALL(Dbg_audit_interface(LIST(alp->al_lmp),
135308278a5eSRod Evans alp->al_libname, sr.sr_name));
13547c478bd9Sstevel@tonic-gate return (addr);
135508278a5eSRod Evans }
13567c478bd9Sstevel@tonic-gate return (0);
13577c478bd9Sstevel@tonic-gate }
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate /*
13607c478bd9Sstevel@tonic-gate * Centralize cleanup routines.
13617c478bd9Sstevel@tonic-gate */
13627c478bd9Sstevel@tonic-gate static int
audit_disable(char * name,Rt_map * clmp,Grp_hdl * ghp,Audit_list * alp)13637c478bd9Sstevel@tonic-gate audit_disable(char *name, Rt_map *clmp, Grp_hdl *ghp, Audit_list *alp)
13647c478bd9Sstevel@tonic-gate {
13655aefb655Srie eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_AUD_DISABLED), name);
13667c478bd9Sstevel@tonic-gate if (ghp)
13677c478bd9Sstevel@tonic-gate (void) dlclose_intn(ghp, clmp);
13687c478bd9Sstevel@tonic-gate if (alp)
13697c478bd9Sstevel@tonic-gate free(alp);
13707c478bd9Sstevel@tonic-gate
13717c478bd9Sstevel@tonic-gate return (0);
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate /*
13757c478bd9Sstevel@tonic-gate * Given a list of one or more audit libraries, open each one and establish a
13767c478bd9Sstevel@tonic-gate * a descriptor representing the entry points it provides.
13777c478bd9Sstevel@tonic-gate */
13787c478bd9Sstevel@tonic-gate int
audit_setup(Rt_map * clmp,Audit_desc * adp,uint_t orig,int * in_nfavl)13799aa23310Srie audit_setup(Rt_map *clmp, Audit_desc *adp, uint_t orig, int *in_nfavl)
13807c478bd9Sstevel@tonic-gate {
13817c478bd9Sstevel@tonic-gate char *ptr, *next;
13825aefb655Srie Lm_list *clml = LIST(clmp);
13832020b2b6SRod Evans Rt_map *hlmp;
13842020b2b6SRod Evans int error = 1, activity = 0, preinit = 0;
13852020b2b6SRod Evans uint_t rtldflags;
13867c478bd9Sstevel@tonic-gate
13872020b2b6SRod Evans /*
13882020b2b6SRod Evans * Determine the type of auditing for diagnostics.
13892020b2b6SRod Evans */
13902020b2b6SRod Evans if (DBG_ENABLED) {
13912020b2b6SRod Evans int type;
13922020b2b6SRod Evans
13932020b2b6SRod Evans if (orig & PD_FLG_EXTLOAD)
13942020b2b6SRod Evans type = DBG_AUD_PRELOAD;
13952020b2b6SRod Evans else if (FLAGS1(clmp) & FL1_RT_GLOBAUD)
13962020b2b6SRod Evans type = DBG_AUD_GLOBAL;
13972020b2b6SRod Evans else
13982020b2b6SRod Evans type = DBG_AUD_LOCAL;
13992020b2b6SRod Evans
14002020b2b6SRod Evans DBG_CALL(Dbg_audit_lib(clmp, adp->ad_name, type));
14012020b2b6SRod Evans }
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate /*
14047c478bd9Sstevel@tonic-gate * Mark that we have at least one auditing link map
14057c478bd9Sstevel@tonic-gate */
14067c478bd9Sstevel@tonic-gate rtld_flags2 |= RT_FL2_HASAUDIT;
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate /*
14097c478bd9Sstevel@tonic-gate * The audit definitions may be a list (which will already have been
14107c478bd9Sstevel@tonic-gate * dupped) so split it into individual tokens.
14117c478bd9Sstevel@tonic-gate */
141256d7adc6Srie for (ptr = strtok_r(adp->ad_name, MSG_ORIG(MSG_STR_DELIMIT), &next);
141356d7adc6Srie ptr; ptr = strtok_r(NULL, MSG_ORIG(MSG_STR_DELIMIT), &next)) {
14147c478bd9Sstevel@tonic-gate Grp_hdl *ghp;
14157c478bd9Sstevel@tonic-gate Rt_map *lmp;
14162020b2b6SRod Evans Lm_list *lml;
14177c478bd9Sstevel@tonic-gate Rt_map **tobj;
14187c478bd9Sstevel@tonic-gate Audit_list *alp;
14197c478bd9Sstevel@tonic-gate
14202020b2b6SRod Evans DBG_CALL(Dbg_util_nl(clml, DBG_NL_STD));
14212020b2b6SRod Evans
14227c478bd9Sstevel@tonic-gate /*
14237c478bd9Sstevel@tonic-gate * Open the audit library on its own link-map.
14247c478bd9Sstevel@tonic-gate */
14257c478bd9Sstevel@tonic-gate if ((ghp = dlmopen_intn((Lm_list *)LM_ID_NEWLM, ptr,
14267c478bd9Sstevel@tonic-gate (RTLD_FIRST | RTLD_GLOBAL | RTLD_WORLD), clmp,
142757ef7aa9SRod Evans FLG_RT_AUDIT, orig)) == NULL) {
14287c478bd9Sstevel@tonic-gate error = audit_disable(ptr, clmp, 0, 0);
14297c478bd9Sstevel@tonic-gate continue;
14307c478bd9Sstevel@tonic-gate }
14315aefb655Srie lmp = ghp->gh_ownlmp;
14322020b2b6SRod Evans lml = LIST(lmp);
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate /*
14357c478bd9Sstevel@tonic-gate * If this auditor has already been loaded, reuse it.
14367c478bd9Sstevel@tonic-gate */
14372020b2b6SRod Evans if ((alp = lml->lm_alp) != NULL) {
143857ef7aa9SRod Evans if (aplist_append(&(adp->ad_list), alp,
143957ef7aa9SRod Evans AL_CNT_AUDITORS) == NULL)
14407c478bd9Sstevel@tonic-gate return (audit_disable(ptr, clmp, ghp, alp));
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate adp->ad_cnt++;
14437c478bd9Sstevel@tonic-gate adp->ad_flags |= alp->al_flags;
14442020b2b6SRod Evans
14452020b2b6SRod Evans /*
14462020b2b6SRod Evans * If this existing auditor provides preinit or
14472020b2b6SRod Evans * activity routines, track their existence. The
14482020b2b6SRod Evans * instantiation of a local auditor requires a cookie
14492020b2b6SRod Evans * be created that represents the object that heads
14502020b2b6SRod Evans * the link-map list of the object being audited.
14512020b2b6SRod Evans */
14522020b2b6SRod Evans if (alp->al_preinit)
14532020b2b6SRod Evans preinit++;
14542020b2b6SRod Evans if (alp->al_activity)
14552020b2b6SRod Evans activity++;
14562020b2b6SRod Evans
14577c478bd9Sstevel@tonic-gate continue;
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate /*
146143d7826aSRod Evans * Prior to the Unified Process Model (UPM) environment, an
146243d7826aSRod Evans * rtld lock had to be held upon leave(). However, even within
146343d7826aSRod Evans * a UPM environment, an old auditor, that has a lazy dependency
146443d7826aSRod Evans * on libc, is still a possibility. As libc isn't loaded, we
146543d7826aSRod Evans * don't know the process model, and will determine this later.
146643d7826aSRod Evans * Refer to external.c:get_lcinterface().
14677c478bd9Sstevel@tonic-gate */
14687c478bd9Sstevel@tonic-gate if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0)
14692020b2b6SRod Evans lml->lm_flags |= LML_FLG_HOLDLOCK;
14707c478bd9Sstevel@tonic-gate
14717c478bd9Sstevel@tonic-gate /*
14727c478bd9Sstevel@tonic-gate * Allocate an audit list descriptor for this object and
14737c478bd9Sstevel@tonic-gate * search for all known entry points.
14747c478bd9Sstevel@tonic-gate */
147556deab07SRod Evans if ((alp = calloc(1, sizeof (Audit_list))) == NULL)
14767c478bd9Sstevel@tonic-gate return (audit_disable(ptr, clmp, ghp, 0));
14777c478bd9Sstevel@tonic-gate
14787c478bd9Sstevel@tonic-gate alp->al_libname = NAME(lmp);
14797c478bd9Sstevel@tonic-gate alp->al_lmp = lmp;
14807c478bd9Sstevel@tonic-gate alp->al_ghp = ghp;
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate /*
14837c478bd9Sstevel@tonic-gate * All audit libraries must handshake through la_version().
14847c478bd9Sstevel@tonic-gate * Determine that the symbol exists, finish initializing the
14857c478bd9Sstevel@tonic-gate * object, and then call the function.
14867c478bd9Sstevel@tonic-gate */
14879aa23310Srie if ((alp->al_version = (uint_t(*)())audit_symget(alp,
14889aa23310Srie AI_LAVERSION, in_nfavl)) == 0) {
14892020b2b6SRod Evans eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM),
14907c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_SYM_LAVERSION));
14917c478bd9Sstevel@tonic-gate error = audit_disable(ptr, clmp, ghp, alp);
14927c478bd9Sstevel@tonic-gate continue;
14937c478bd9Sstevel@tonic-gate }
14947c478bd9Sstevel@tonic-gate
14952020b2b6SRod Evans if ((tobj = tsort(lmp, lml->lm_init, RT_SORT_REV)) ==
14967c478bd9Sstevel@tonic-gate (Rt_map **)S_ERROR)
14977c478bd9Sstevel@tonic-gate return (audit_disable(ptr, clmp, ghp, alp));
14987c478bd9Sstevel@tonic-gate
14992020b2b6SRod Evans if (tobj)
15007c478bd9Sstevel@tonic-gate call_init(tobj, DBG_INIT_SORT);
15017c478bd9Sstevel@tonic-gate
15022020b2b6SRod Evans APPLICATION_ENTER(rtldflags);
15032020b2b6SRod Evans leave(lml, thr_flg_reenter);
15042020b2b6SRod Evans alp->al_vernum = (*alp->al_version)(LAV_CURRENT);
15052020b2b6SRod Evans (void) enter(thr_flg_reenter);
15062020b2b6SRod Evans APPLICATION_RETURN(rtldflags);
15072020b2b6SRod Evans
15082020b2b6SRod Evans DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
15092020b2b6SRod Evans LAV_CURRENT, alp->al_vernum));
15107c478bd9Sstevel@tonic-gate
15117c478bd9Sstevel@tonic-gate if ((alp->al_vernum < LAV_VERSION1) ||
15127c478bd9Sstevel@tonic-gate (alp->al_vernum > LAV_CURRENT)) {
15132020b2b6SRod Evans eprintf(lml, ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS),
15147c478bd9Sstevel@tonic-gate LAV_CURRENT, alp->al_vernum);
15157c478bd9Sstevel@tonic-gate error = audit_disable(ptr, clmp, ghp, alp);
15167c478bd9Sstevel@tonic-gate continue;
15177c478bd9Sstevel@tonic-gate }
15187c478bd9Sstevel@tonic-gate
151957ef7aa9SRod Evans if (aplist_append(&(adp->ad_list), alp,
152057ef7aa9SRod Evans AL_CNT_AUDITORS) == NULL)
15217c478bd9Sstevel@tonic-gate return (audit_disable(ptr, clmp, ghp, alp));
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate adp->ad_cnt++;
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate /*
15267c478bd9Sstevel@tonic-gate * Collect any remaining entry points.
15277c478bd9Sstevel@tonic-gate */
15289aa23310Srie alp->al_objsearch = (char *(*)())audit_symget(alp,
15299aa23310Srie AI_LAOBJSEARCH, in_nfavl);
15309aa23310Srie alp->al_objopen = (uint_t(*)())audit_symget(alp,
15319aa23310Srie AI_LAOBJOPEN, in_nfavl);
15329aa23310Srie alp->al_objfilter = (int(*)())audit_symget(alp,
15339aa23310Srie AI_LAOBJFILTER, in_nfavl);
15349aa23310Srie alp->al_objclose = (uint_t(*)())audit_symget(alp,
15359aa23310Srie AI_LAOBJCLOSE, in_nfavl);
15369aa23310Srie alp->al_symbind = (uintptr_t(*)())audit_symget(alp,
15379aa23310Srie AI_LASYMBIND, in_nfavl);
15389aa23310Srie alp->al_pltenter = (uintptr_t(*)())audit_symget(alp,
15399aa23310Srie AI_LAPLTENTER, in_nfavl);
15409aa23310Srie alp->al_pltexit = (uintptr_t(*)())audit_symget(alp,
15419aa23310Srie AI_LAPLTEXIT, in_nfavl);
15427c478bd9Sstevel@tonic-gate
15432020b2b6SRod Evans if ((alp->al_preinit = (void(*)())audit_symget(alp,
15442020b2b6SRod Evans AI_LAPREINIT, in_nfavl)) != NULL)
15452020b2b6SRod Evans preinit++;
15462020b2b6SRod Evans if ((alp->al_activity = (void(*)())audit_symget(alp,
15472020b2b6SRod Evans AI_LAACTIVITY, in_nfavl)) != NULL)
15482020b2b6SRod Evans activity++;
15492020b2b6SRod Evans
15507c478bd9Sstevel@tonic-gate /*
15517c478bd9Sstevel@tonic-gate * Collect the individual object flags, and assign this audit
15527c478bd9Sstevel@tonic-gate * list descriptor to its associated link-map list.
15537c478bd9Sstevel@tonic-gate */
15547c478bd9Sstevel@tonic-gate adp->ad_flags |= alp->al_flags;
15552020b2b6SRod Evans lml->lm_alp = alp;
155656d7adc6Srie }
15577c478bd9Sstevel@tonic-gate
15587c478bd9Sstevel@tonic-gate /*
15592020b2b6SRod Evans * If the caller isn't the head of its own link-map list, then any
15602020b2b6SRod Evans * preinit or activity entry points need to be tracked separately.
15612020b2b6SRod Evans * These "events" are not associated with a particular link-map, and
15622020b2b6SRod Evans * thus a traversal of any existing preinit and activity clients is
15632020b2b6SRod Evans * required.
15642020b2b6SRod Evans *
15652020b2b6SRod Evans * If either of these events are required, establish a cookie for the
15662020b2b6SRod Evans * object at the head of the link-map list, and make an initial ADD
15672020b2b6SRod Evans * activity for these local auditors.
15682020b2b6SRod Evans */
15692020b2b6SRod Evans if ((preinit || activity) && ((hlmp = clml->lm_head) != clmp) &&
15702020b2b6SRod Evans (_audit_add_head(clmp, hlmp, preinit, activity) == 0))
15712020b2b6SRod Evans return (0);
15722020b2b6SRod Evans
15732020b2b6SRod Evans /*
15747c478bd9Sstevel@tonic-gate * Free the original audit string, as this descriptor may be used again
15757c478bd9Sstevel@tonic-gate * to add additional auditing.
15767c478bd9Sstevel@tonic-gate */
15777c478bd9Sstevel@tonic-gate free(adp->ad_name);
157857ef7aa9SRod Evans adp->ad_name = NULL;
15797c478bd9Sstevel@tonic-gate
15807c478bd9Sstevel@tonic-gate return (error);
15817c478bd9Sstevel@tonic-gate }
1582