/* * la_filter() caller. Traverses through all audit libraries and call any * la_filter() entry points found. A zero return from an auditor indicates * that the filtee should be ignored. */ static int _audit_objfilter(List *list, Rt_map *frlmp, const char *ref, Rt_map *felmp, uint_t flags) { Audit_list *alp; Listnode *lnp; for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client *fracp, *feacp; if (alp->al_objfilter == 0) continue; if ((fracp = _audit_client(AUDINFO(frlmp), alp->al_lmp)) == 0) continue; if ((feacp = _audit_client(AUDINFO(felmp), alp->al_lmp)) == 0) continue; leave(LIST(alp->al_lmp)); if ((*alp->al_objfilter)(&(fracp->ac_cookie), ref, &(feacp->ac_cookie), flags) == 0) return (0); (void) enter(); } return (1); }
/* * la_pltexit() caller. Traverses through all audit library and calls any * la_pltexit() entry points found. See notes above (_audit_pltenter) for * discussion on st_name. */ static Addr _audit_pltexit(List *list, uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx) { Audit_list *alp; Listnode *lnp; #if defined(_ELF64) const char *name = (const char *)(sym->st_name + STRTAB(dlmp)); #endif for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client *racp, *dacp; if (alp->al_pltexit == 0) continue; if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == 0) continue; if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == 0) continue; if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) || ((dacp->ac_flags & FLG_AC_BINDTO) == 0)) continue; leave(LIST(alp->al_lmp)); retval = (*alp->al_pltexit)(sym, ndx, &(racp->ac_cookie), &(dacp->ac_cookie), #if defined(_ELF64) retval, name); #else retval); #endif (void) enter(); } return (retval); }
/* * la_activity() caller. Traverse through all audit libraries and call any * la_activity() entry points found. */ static void _audit_activity(APlist *list, Rt_map *clmp, uint_t flags, Boolean client) { Audit_list *alp; Aliste idx; Lm_list *clml = LIST(clmp); for (APLIST_TRAVERSE(list, idx, alp)) { Audit_client *acp; Rt_map *almp = alp->al_lmp; Lm_list *alml = LIST(almp); uintptr_t *cookie; if (alp->al_activity == 0) continue; /* * Determine what cookie is required. Any auditing that * originates from the object that heads the link-map list has * its own cookie. Local auditors must obtain the cookie that * represents the object that heads the link-map list. */ if (client) acp = _audit_client(AUDINFO(clmp), almp); else acp = _audit_get_head_client(clml->lm_head, almp); if (acp == NULL) continue; cookie = &(acp->ac_cookie); /* * Make sure the audit library only sees one addition/deletion * at a time. This ensures the library doesn't see numerous * events from lazy loading a series of libraries. Keep track * of this caller having called an auditor, so that the * appropriate "consistent" event can be supplied on leaving * ld.so.1. */ if ((flags == LA_ACT_ADD) || (flags == LA_ACT_DELETE)) { if (alml->lm_flags & LML_FLG_AUDITNOTIFY) continue; alml->lm_flags |= LML_FLG_AUDITNOTIFY; clml->lm_flags |= LML_FLG_ACTAUDIT; } else { if ((alml->lm_flags & LML_FLG_AUDITNOTIFY) == 0) continue; alml->lm_flags &= ~LML_FLG_AUDITNOTIFY; } DBG_CALL(Dbg_audit_activity(clml, alp->al_libname, NAME(clml->lm_head), flags)); leave(alml, thr_flg_reenter); (*alp->al_activity)(cookie, flags); (void) enter(thr_flg_reenter); } }
/* * la_pltenter() caller. Traverses through all audit library and calls any * la_pltenter() entry points found. NOTE: this routine is called via the * glue code established in elf_plt_trace_write(), the symbol descriptor is * created as part of the glue and for 32bit environments the st_name is a * pointer to the real symbol name (ie. it's already been adjusted with the * objects base offset). For 64bit environments the st_name remains the * original symbol offset and in this case it is used to compute the real name * pointer and pass as a separate argument to the auditor. */ static void _audit_pltenter(List *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, void *regs, uint_t *flags) { Audit_list *alp; Listnode *lnp; #if defined(_ELF64) const char *name = (const char *)(sym->st_name + STRTAB(dlmp)); #else const char *name = (const char *)(sym->st_name); #endif for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client *racp, *dacp; Addr prev = sym->st_value; if (alp->al_pltenter == 0) continue; if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == 0) continue; if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == 0) continue; if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) || ((dacp->ac_flags & FLG_AC_BINDTO) == 0)) continue; leave(LIST(alp->al_lmp)); sym->st_value = (Addr)(*alp->al_pltenter)(sym, ndx, &(racp->ac_cookie), &(dacp->ac_cookie), regs, #if defined(_ELF64) flags, name); #else flags); #endif (void) enter(); DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname, MSG_ORIG(MSG_AUD_PLTENTER), name, prev, sym->st_name)); } }
/* * la_filter() caller. Traverse through all audit libraries and call any * la_filter() entry points found. A zero return from an auditor indicates * that the filtee should be ignored. */ static int _audit_objfilter(APlist *list, Rt_map *frlmp, const char *ref, Rt_map *felmp, uint_t flags) { Audit_list *alp; Aliste idx; Lm_list *frlml = LIST(frlmp); for (APLIST_TRAVERSE(list, idx, alp)) { Audit_client *fracp, *feacp; Rt_map *almp = alp->al_lmp; Lm_list *alml = LIST(almp); int ret; if (alp->al_objfilter == NULL) continue; if ((fracp = _audit_client(AUDINFO(frlmp), almp)) == NULL) continue; if ((feacp = _audit_client(AUDINFO(felmp), almp)) == NULL) continue; DBG_CALL(Dbg_audit_objfilter(frlml, DBG_AUD_CALL, alp->al_libname, NAME(frlmp), NAME(felmp), ref)); leave(alml, thr_flg_reenter); ret = (*alp->al_objfilter)(&(fracp->ac_cookie), ref, &(feacp->ac_cookie), flags); (void) enter(thr_flg_reenter); if (ret == 0) { DBG_CALL(Dbg_audit_objfilter(frlml, DBG_AUD_RET, alp->al_libname, NAME(frlmp), NULL, NULL)); return (0); } } return (1); }
/* * la_preinit() caller. Traverses through all audit libraries and calls any * la_preinit() entry points found. */ static void _audit_preinit(List *list, Rt_map *clmp) { Audit_list *alp; Listnode *lnp; for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client *acp; if (alp->al_preinit == 0) continue; if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == 0) continue; leave(LIST(alp->al_lmp)); (*alp->al_preinit)(&(acp->ac_cookie)); (void) enter(); } }
/* * la_objclose() caller. Traverses through all audit library and calls any * la_objclose() entry points found. */ void _audit_objclose(List * list, Rt_map * lmp) { Audit_list * alp; Listnode * lnp; for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client * acp; if (alp->al_objclose == 0) continue; if ((acp = _audit_client(AUDINFO(lmp), alp->al_lmp)) == 0) continue; leave(LIST(alp->al_lmp)); (*alp->al_objclose)(&(acp->ac_cookie)); (void) enter(); } }
/* * la_activity() caller. Traverses through all audit library and calls any * la_activity() entry points found. */ static void _audit_activity(List * list, Rt_map * clmp, uint_t flags) { Audit_list * alp; Listnode * lnp; for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client * acp; if (alp->al_activity == 0) continue; if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == 0) continue; leave(LIST(alp->al_lmp)); (*alp->al_activity)(&(acp->ac_cookie), flags); (void) enter(); } }
/* * la_objsearch() caller. Traverse through all audit libraries and call any * la_objsearch() entry points found. * * Effectively any audit library can change the name we're working with, so we * continue to propagate the new name to each audit library. Any 0 return * terminates the search. */ static char * _audit_objsearch(APlist *list, char *oname, Rt_map *clmp, uint_t flags) { Audit_list *alp; Aliste idx; Lm_list *clml = LIST(clmp); for (APLIST_TRAVERSE(list, idx, alp)) { Audit_client *acp; Rt_map *almp = alp->al_lmp; Lm_list *alml = LIST(almp); char *nname = oname; if (alp->al_objsearch == NULL) continue; if ((acp = _audit_client(AUDINFO(clmp), almp)) == NULL) continue; DBG_CALL(Dbg_audit_objsearch(clml, DBG_AUD_CALL, alp->al_libname, nname, flags, NULL)); leave(alml, thr_flg_reenter); nname = (*alp->al_objsearch)(nname, &(acp->ac_cookie), flags); (void) enter(thr_flg_reenter); /* * Diagnose any return name that differs from the original name * passed to the auditor. */ if (nname && (nname[0] == '\0')) nname = NULL; if ((nname != oname) || strcmp(nname, oname)) DBG_CALL(Dbg_audit_objsearch(clml, DBG_AUD_RET, alp->al_libname, oname, flags, nname)); if ((oname = nname) == NULL) break; } return (oname); }
/* * la_objsearch() caller. Traverses through all audit libraries and call any * la_objsearch() entry points found. * * Effectively any audit library can change the name we're working with, so we * continue to propagate the new name to each audit library. Any 0 return * terminates the search. */ static char * _audit_objsearch(List *list, char *name, Rt_map *clmp, uint_t flags) { Audit_list *alp; Listnode *lnp; char *nname = (char *)name; for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client *acp; if (alp->al_objsearch == 0) continue; if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == 0) continue; leave(LIST(alp->al_lmp)); nname = (*alp->al_objsearch)(nname, &(acp->ac_cookie), flags); (void) enter(); if (nname == 0) break; } return (nname); }
/* * la_objclose() caller. Traverse through all audit libraries and call any * la_objclose() entry points found. */ void _audit_objclose(APlist *list, Rt_map *lmp) { Audit_list *alp; Aliste idx; Lm_list *lml = LIST(lmp); for (APLIST_TRAVERSE(list, idx, alp)) { Audit_client *acp; Rt_map *almp = alp->al_lmp; Lm_list *alml = LIST(almp); if (alp->al_objclose == NULL) continue; if ((acp = _audit_client(AUDINFO(lmp), almp)) == NULL) continue; DBG_CALL(Dbg_audit_objclose(lml, alp->al_libname, NAME(lmp))); leave(alml, thr_flg_reenter); (*alp->al_objclose)(&(acp->ac_cookie)); (void) enter(thr_flg_reenter); } }
/* * la_symbind() caller. Traverses through all audit library and calls any * la_symbind() entry points found. */ static Addr _audit_symbind(List *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, uint_t *flags, int *called) { Audit_list *alp; Listnode *lnp; #if defined(_ELF64) const char *name = (const char *)(sym->st_name + STRTAB(dlmp)); #else const char *name = (const char *)(sym->st_name); #endif for (LIST_TRAVERSE(list, lnp, alp)) { Audit_client *racp, *dacp; Addr prev = sym->st_value; uint_t lflags; if (alp->al_symbind == 0) continue; if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == 0) continue; if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == 0) continue; if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) || ((dacp->ac_flags & FLG_AC_BINDTO) == 0)) continue; /* * The la_symbind interface is only called when the calling * object has been identified as BINDFROM, and the destination * object has been identified as BINDTO. Use a local version of * the flags, so that any user update can be collected. */ called++; lflags = (*flags & ~(LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)); leave(LIST(alp->al_lmp)); sym->st_value = (*alp->al_symbind)(sym, ndx, &(racp->ac_cookie), &(dacp->ac_cookie), #if defined(_ELF64) &lflags, name); #else &lflags); #endif (void) enter(); /* * If the auditor indicated that they did not want to process * pltenter, or pltexit audits for this symbol, retain this * information. Also retain whether an alternative symbol value * has been supplied. */ *flags |= (lflags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)); if ((prev != sym->st_value) && (alp->al_vernum >= LAV_VERSION2)) *flags |= LA_SYMB_ALTVALUE; DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname, MSG_ORIG(MSG_AUD_SYMBIND), name, prev, sym->st_value)); } return (sym->st_value); }