#include <stdio.h>
#include <sys/types.h>
#include <sys/lwp.h>
#include <stdio.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <string.h>
#include <debug.h>
#include "_rtld.h"
#include "_audit.h"
#include "_elf.h"
#include "msg.h"
uint_t audit_flags = 0;
static Audit_client *
_audit_get_head_client(Rt_map *hlmp, Rt_map *almp)
{
Audit_client *acp;
Aliste idx;
Lm_list *hlml = LIST(hlmp);
for (ALIST_TRAVERSE(hlml->lm_aud_cookies, idx, acp)) {
if (acp->ac_lmp == almp)
return (acp);
}
return (NULL);
}
static Audit_client *
_audit_create_head_client(Rt_map *hlmp, Rt_map *almp)
{
Audit_client ac, *acp;
Lm_list *hlml = LIST(hlmp);
ac.ac_lmp = almp;
ac.ac_cookie = (uintptr_t)hlmp;
ac.ac_flags = 0;
if ((acp = alist_append(&(hlml->lm_aud_cookies), &ac,
sizeof (Audit_client), AL_CNT_COOKIES)) == NULL)
return (NULL);
return (acp);
}
static Audit_client *
_audit_client(Audit_info *aip, Rt_map *almp)
{
int ndx;
if (aip == NULL)
return (NULL);
for (ndx = 0; ndx < aip->ai_cnt; ndx++) {
if (aip->ai_clients[ndx].ac_lmp == almp)
return (&(aip->ai_clients[ndx]));
}
return (NULL);
}
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);
}
int
audit_objfilter(Rt_map *frlmp, const char *ref, Rt_map *felmp, uint_t flags)
{
uint_t rtldflags;
int respond = 1;
if (rt_critical())
return (respond);
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJFILTER))
respond = _audit_objfilter(auditors->ad_list, frlmp,
ref, felmp, flags);
if (respond && AUDITORS(frlmp) &&
(AUDITORS(frlmp)->ad_flags & LML_TFLG_AUD_OBJFILTER))
respond = _audit_objfilter(AUDITORS(frlmp)->ad_list, frlmp,
ref, felmp, flags);
APPLICATION_RETURN(rtldflags);
return (respond);
}
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);
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);
}
char *
audit_objsearch(Rt_map *clmp, const char *name, uint_t flags)
{
char *nname = (char *)name;
uint_t rtldflags;
if (rt_critical())
return (nname);
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJSEARCH))
nname = _audit_objsearch(auditors->ad_list, nname,
clmp, flags);
if (nname && AUDITORS(clmp) &&
(AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_OBJSEARCH))
nname = _audit_objsearch(AUDITORS(clmp)->ad_list, nname,
clmp, flags);
APPLICATION_RETURN(rtldflags);
DBG_CALL(Dbg_libs_audit(LIST(clmp), name, nname));
return (nname);
}
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;
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);
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);
}
}
void
audit_activity(Rt_map *clmp, uint_t flags)
{
Rt_map *lmp;
Aliste idx;
uint_t rtldflags;
if (rt_critical())
return;
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_ACTIVITY))
_audit_activity(auditors->ad_list, clmp, flags, TRUE);
if (AUDITORS(clmp) &&
(AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_ACTIVITY))
_audit_activity(AUDITORS(clmp)->ad_list, clmp, flags, TRUE);
for (APLIST_TRAVERSE(aud_activity, idx, lmp)) {
if ((clmp != lmp) && AUDITORS(lmp) &&
(AUDITORS(lmp)->ad_flags & LML_TFLG_AUD_ACTIVITY)) {
_audit_activity(AUDITORS(lmp)->ad_list, lmp, flags,
FALSE);
}
}
APPLICATION_RETURN(rtldflags);
}
static int
_audit_used_by_head(Rt_map *hlmp, Rt_map *almp)
{
Audit_list *alp;
Aliste idx;
for (APLIST_TRAVERSE(AUDITORS(hlmp)->ad_list, idx, alp)) {
if (alp->al_lmp == almp)
return (1);
}
return (0);
}
static int
_audit_add_head(Rt_map *clmp, Rt_map *hlmp, int preinit, int activity)
{
Lm_list *clml = LIST(clmp);
Lmid_t lmid = get_linkmap_id(clml);
Audit_list *alp;
Aliste idx;
int save = 0;
for (APLIST_TRAVERSE(AUDITORS(clmp)->ad_list, idx, alp)) {
Audit_client *acp;
Rt_map *almp = alp->al_lmp;
Lm_list *alml = LIST(almp);
uintptr_t *cookie;
uint_t rtldflags;
if (AUDITORS(hlmp) && _audit_used_by_head(hlmp, almp))
continue;
if ((acp = _audit_get_head_client(clml->lm_head, almp)) != NULL)
continue;
if ((acp =
_audit_create_head_client(clml->lm_head, almp)) == NULL)
return (0);
cookie = &(acp->ac_cookie);
save++;
if (alp->al_objopen) {
uint_t flags;
DBG_CALL(Dbg_audit_objopen(clml, DBG_AUD_CALL,
alp->al_libname, NAME(hlmp), 0, FALSE));
APPLICATION_ENTER(rtldflags);
leave(alml, thr_flg_reenter);
flags = (*alp->al_objopen)((Link_map *)hlmp, lmid,
cookie);
(void) enter(thr_flg_reenter);
APPLICATION_RETURN(rtldflags);
if (flags) {
DBG_CALL(Dbg_audit_objopen(clml, DBG_AUD_RET,
alp->al_libname, NAME(hlmp), flags, TRUE));
}
}
if (alp->al_activity) {
alml->lm_flags |= LML_FLG_AUDITNOTIFY;
clml->lm_flags |= LML_FLG_ACTAUDIT;
DBG_CALL(Dbg_audit_activity(clml, alp->al_libname,
NAME(clml->lm_head), LA_ACT_ADD));
APPLICATION_ENTER(rtldflags);
leave(alml, thr_flg_reenter);
(*alp->al_activity)(cookie, LA_ACT_ADD);
(void) enter(thr_flg_reenter);
APPLICATION_RETURN(rtldflags);
}
}
if (save) {
if (preinit && (aplist_append(&aud_preinit, clmp,
AL_CNT_AUDITORS) == NULL))
return (0);
if (activity && (aplist_append(&aud_activity, clmp,
AL_CNT_AUDITORS) == NULL))
return (0);
}
return (1);
}
static int
_audit_objopen(APlist *list, Rt_map *nlmp, Lmid_t lmid, Audit_info *aip,
int *ndx)
{
Lm_list *nlml = LIST(nlmp);
Audit_list *alp;
Aliste idx;
for (APLIST_TRAVERSE(list, idx, alp)) {
uint_t flags;
Audit_client *acp;
Rt_map *almp = alp->al_lmp;
Lm_list *alml = LIST(almp);
acp = &aip->ai_clients[(*ndx)++];
acp->ac_lmp = alp->al_lmp;
acp->ac_cookie = (uintptr_t)nlmp;
if (alp->al_objopen == NULL)
continue;
DBG_CALL(Dbg_audit_objopen(nlml, DBG_AUD_CALL, alp->al_libname,
NAME(nlmp), 0, FALSE));
leave(alml, thr_flg_reenter);
flags = (*alp->al_objopen)((Link_map *)nlmp, lmid,
&(acp->ac_cookie));
(void) enter(thr_flg_reenter);
if (flags) {
DBG_CALL(Dbg_audit_objopen(nlml, DBG_AUD_RET,
alp->al_libname, NAME(nlmp), flags, FALSE));
}
if (flags & LA_FLG_BINDTO)
acp->ac_flags |= FLG_AC_BINDTO;
if (flags & LA_FLG_BINDFROM) {
ulong_t pltcnt;
acp->ac_flags |= FLG_AC_BINDFROM;
if (aip->ai_dynplts || (JMPREL(nlmp) == 0) ||
((audit_flags & (AF_PLTENTER | AF_PLTEXIT)) == 0))
continue;
pltcnt = PLTRELSZ(nlmp) / RELENT(nlmp);
if ((aip->ai_dynplts = calloc(pltcnt,
dyn_plt_ent_size)) == NULL)
return (0);
}
}
return (1);
}
int
audit_objopen(Rt_map *clmp, Rt_map *nlmp)
{
Lmid_t lmid = get_linkmap_id(LIST(nlmp));
int respond = 1, ndx = 0;
uint_t rtldflags;
uint_t clients = 0;
Audit_info *aip;
if (rt_critical())
return (respond);
if (auditors)
clients = auditors->ad_cnt;
if (AUDITORS(clmp))
clients += AUDITORS(clmp)->ad_cnt;
if ((nlmp != clmp) && AUDITORS(nlmp))
clients += AUDITORS(nlmp)->ad_cnt;
if ((AUDINFO(nlmp) = aip = calloc(1, sizeof (Audit_info) +
(sizeof (Audit_client) * clients))) == NULL)
return (0);
aip->ai_cnt = clients;
aip->ai_clients = (Audit_client *)((uintptr_t)aip +
sizeof (Audit_info));
APPLICATION_ENTER(rtldflags);
if (auditors)
respond = _audit_objopen(auditors->ad_list, nlmp,
lmid, aip, &ndx);
if (respond && AUDITORS(clmp))
respond = _audit_objopen(AUDITORS(clmp)->ad_list, nlmp,
lmid, aip, &ndx);
if (respond && (nlmp != clmp) && AUDITORS(nlmp))
respond = _audit_objopen(AUDITORS(nlmp)->ad_list, nlmp,
lmid, aip, &ndx);
APPLICATION_RETURN(rtldflags);
return (respond);
}
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);
(void) (*alp->al_objclose)(&(acp->ac_cookie));
(void) enter(thr_flg_reenter);
}
}
inline static void
add_objclose_list(Rt_map *lmp, APlist **alpp)
{
if (AFLAGS(lmp) & LML_TFLG_AUD_OBJCLOSE) {
Audit_list *alp;
Aliste idx;
for (APLIST_TRAVERSE(AUDITORS(lmp)->ad_list, idx, alp)) {
if (aplist_test(alpp, alp, AL_CNT_AUDITORS) == 0)
return;
}
}
}
void
audit_objclose(Rt_map *lmp, Rt_map *clmp)
{
APlist *alp = NULL;
uint_t rtldflags;
if (rt_critical())
return;
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJCLOSE))
_audit_objclose(auditors->ad_list, lmp);
if (LIST(lmp)->lm_flags & LML_FLG_LOCAUDIT) {
Bnd_desc *bdp;
Aliste idx;
add_objclose_list(lmp, &alp);
for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp))
add_objclose_list(bdp->b_caller, &alp);
}
if (clmp)
add_objclose_list(clmp, &alp);
if (alp) {
_audit_objclose(alp, lmp);
free((void *)alp);
}
APPLICATION_RETURN(rtldflags);
}
static void
_audit_pltenter(APlist *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym,
uint_t ndx, void *regs, uint_t *flags)
{
Audit_list *alp;
Aliste idx;
Lm_list *rlml = LIST(rlmp);
#if defined(_ELF64)
const char *name = (const char *)(sym->st_name + STRTAB(dlmp));
#else
const char *name = (const char *)(sym->st_name);
#endif
for (APLIST_TRAVERSE(list, idx, alp)) {
Audit_client *racp, *dacp;
Rt_map *almp = alp->al_lmp;
Lm_list *alml = LIST(almp);
Addr ovalue = sym->st_value;
if (alp->al_pltenter == 0)
continue;
if ((racp = _audit_client(AUDINFO(rlmp), almp)) == NULL)
continue;
if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
continue;
if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
((dacp->ac_flags & FLG_AC_BINDTO) == 0))
continue;
DBG_CALL(Dbg_audit_pltenter(rlml, DBG_AUD_CALL,
alp->al_libname, name, ovalue));
leave(alml, thr_flg_reenter);
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(thr_flg_reenter);
if (ovalue != sym->st_value) {
DBG_CALL(Dbg_audit_pltenter(rlml, DBG_AUD_RET,
alp->al_libname, name, sym->st_value));
}
}
}
Addr
audit_pltenter(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx,
void *regs, uint_t *flags)
{
Sym nsym = *sym;
uint_t rtldflags;
if (rt_critical())
return (nsym.st_value);
(void) enter(0);
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTENTER))
_audit_pltenter(auditors->ad_list, rlmp, dlmp, &nsym,
ndx, regs, flags);
if (AUDITORS(rlmp) &&
(AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTENTER))
_audit_pltenter(AUDITORS(rlmp)->ad_list, rlmp, dlmp, &nsym,
ndx, regs, flags);
APPLICATION_RETURN(rtldflags);
leave(LIST(rlmp), 0);
return (nsym.st_value);
}
static Addr
_audit_pltexit(APlist *list, uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp,
Sym *sym, uint_t ndx)
{
Audit_list *alp;
Aliste idx;
#if defined(_ELF64)
const char *name = (const char *)(sym->st_name + STRTAB(dlmp));
#else
const char *name = (const char *)(sym->st_name);
#endif
Lm_list *rlml = LIST(rlmp);
for (APLIST_TRAVERSE(list, idx, alp)) {
Audit_client *racp, *dacp;
Rt_map *almp = alp->al_lmp;
Lm_list *alml = LIST(almp);
if (alp->al_pltexit == 0)
continue;
if ((racp = _audit_client(AUDINFO(rlmp), almp)) == NULL)
continue;
if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
continue;
if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) ||
((dacp->ac_flags & FLG_AC_BINDTO) == 0))
continue;
DBG_CALL(Dbg_audit_pltexit(rlml, alp->al_libname, name));
leave(alml, thr_flg_reenter);
retval = (*alp->al_pltexit)(sym, ndx,
&(racp->ac_cookie), &(dacp->ac_cookie),
#if defined(_ELF64)
retval, name);
#else
retval);
#endif
(void) enter(thr_flg_reenter);
}
return (retval);
}
Addr
audit_pltexit(uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp, Sym *sym,
uint_t ndx)
{
uintptr_t _retval = retval;
uint_t rtldflags;
if (rt_critical())
return (_retval);
(void) enter(0);
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTEXIT))
_retval = _audit_pltexit(auditors->ad_list, _retval,
rlmp, dlmp, sym, ndx);
if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTEXIT))
_retval = _audit_pltexit(AUDITORS(rlmp)->ad_list, _retval,
rlmp, dlmp, sym, ndx);
APPLICATION_RETURN(rtldflags);
leave(LIST(rlmp), 0);
return (_retval);
}
static Addr
_audit_symbind(APlist *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx,
uint_t *flags, int *called)
{
Audit_list *alp;
Aliste idx;
Lm_list *rlml = LIST(rlmp);
#if defined(_ELF64)
const char *name = (const char *)(sym->st_name + STRTAB(dlmp));
#else
const char *name = (const char *)(sym->st_name);
#endif
for (APLIST_TRAVERSE(list, idx, alp)) {
Audit_client *racp, *dacp;
Rt_map *almp = alp->al_lmp;
Lm_list *alml = LIST(almp);
Addr ovalue = sym->st_value;
uint_t lflags, oflags = *flags;
if (alp->al_symbind == 0)
continue;
if ((racp = _audit_client(AUDINFO(rlmp), almp)) != NULL &&
(racp->ac_flags & FLG_AC_BINDFROM) == 0)
continue;
if ((dacp = _audit_client(AUDINFO(dlmp), almp)) == NULL)
continue;
if ((dacp->ac_flags & FLG_AC_BINDTO) == 0)
continue;
(*called)++;
lflags = (oflags & ~(LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
DBG_CALL(Dbg_audit_symbind(rlml, DBG_AUD_CALL,
alp->al_libname, name, ovalue, oflags));
leave(alml, thr_flg_reenter);
sym->st_value = (*alp->al_symbind)(sym, ndx, racp == NULL ?
NULL : &(racp->ac_cookie), &(dacp->ac_cookie),
#if defined(_ELF64)
&lflags, name);
#else
&lflags);
#endif
(void) enter(thr_flg_reenter);
*flags |= (lflags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT));
if ((ovalue != sym->st_value) &&
(alp->al_vernum >= LAV_VERSION2))
*flags |= LA_SYMB_ALTVALUE;
if ((ovalue != sym->st_value) || (oflags != *flags)) {
DBG_CALL(Dbg_audit_symbind(rlml, DBG_AUD_RET,
alp->al_libname, name, sym->st_value, *flags));
}
}
return (sym->st_value);
}
Addr
audit_symbind(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, Addr value,
uint_t *flags)
{
Sym nsym;
int called = 0;
uint_t rtldflags;
nsym = *sym;
nsym.st_value = value;
if (rt_critical())
return (nsym.st_value);
#if !defined(_ELF64)
nsym.st_name += (Word)STRTAB(dlmp);
#endif
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_SYMBIND))
nsym.st_value = _audit_symbind(auditors->ad_list,
rlmp, dlmp, &nsym, ndx, flags, &called);
if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_SYMBIND))
nsym.st_value = _audit_symbind(AUDITORS(rlmp)->ad_list,
rlmp, dlmp, &nsym, ndx, flags, &called);
if (dlmp != rlmp && AUDITORS(dlmp) &&
(AUDITORS(dlmp)->ad_flags & LML_TFLG_AUD_SYMBIND)) {
nsym.st_value = _audit_symbind(AUDITORS(dlmp)->ad_list,
rlmp, dlmp, &nsym, ndx, flags, &called);
}
if (called == 0)
*flags |= (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
APPLICATION_RETURN(rtldflags);
return (nsym.st_value);
}
static void
_audit_preinit(APlist *list, Rt_map *clmp, 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_preinit == 0)
continue;
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);
DBG_CALL(Dbg_audit_preinit(clml, alp->al_libname,
NAME(clml->lm_head)));
leave(alml, thr_flg_reenter);
(*alp->al_preinit)(cookie);
(void) enter(thr_flg_reenter);
}
}
void
audit_preinit(Rt_map *mlmp)
{
Rt_map *clmp;
Aliste idx;
uint_t rtldflags;
if (rt_critical())
return;
APPLICATION_ENTER(rtldflags);
if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PREINIT))
_audit_preinit(auditors->ad_list, mlmp, TRUE);
if (AUDITORS(mlmp) && (AUDITORS(mlmp)->ad_flags & LML_TFLG_AUD_PREINIT))
_audit_preinit(AUDITORS(mlmp)->ad_list, mlmp, TRUE);
for (APLIST_TRAVERSE(aud_preinit, idx, clmp)) {
if (AUDITORS(clmp) &&
(AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_PREINIT))
_audit_preinit(AUDITORS(clmp)->ad_list, clmp, FALSE);
}
APPLICATION_RETURN(rtldflags);
}
void
audit_desc_cleanup(Rt_map *clmp)
{
Audit_desc *adp = AUDITORS(clmp);
Audit_list *alp;
Aliste idx;
APlist *ghalp = NULL;
if (adp == NULL)
return;
if (adp->ad_name)
free(adp->ad_name);
for (APLIST_TRAVERSE(adp->ad_list, idx, alp))
(void) aplist_append(&ghalp, alp->al_ghp, AL_CNT_GROUPS);
free(adp->ad_list);
adp->ad_list = NULL;
free(adp);
AUDITORS(clmp) = NULL;
AFLAGS(clmp) &= ~LML_TFLG_AUD_MASK;
if (ghalp) {
Grp_hdl *ghp;
Aliste idx;
for (APLIST_TRAVERSE(ghalp, idx, ghp)) {
(void) dlclose_intn(ghp, clmp);
}
free(ghalp);
}
}
static void
remove_auditor(APlist *alp, Rt_map *clmp)
{
Rt_map *lmp;
Aliste idx;
for (APLIST_TRAVERSE(alp, idx, lmp)) {
if (lmp == clmp) {
aplist_delete(alp, &idx);
return;
}
}
}
void
audit_info_cleanup(Rt_map *clmp)
{
Audit_info *aip = AUDINFO(clmp);
if (aip == NULL)
return;
if (aip->ai_dynplts)
free(aip->ai_dynplts);
if (aud_preinit)
remove_auditor(aud_preinit, clmp);
if (aud_activity)
remove_auditor(aud_activity, clmp);
free(aip);
}
typedef struct {
Msg sname;
uint_t alflag;
uint_t auflag;
} Aud_info;
static const Aud_info aud_info[] = {
{ MSG_SYM_LAVERSION, 0, 0 },
{ MSG_SYM_LAPREINIT,
LML_TFLG_AUD_PREINIT, 0 },
{ MSG_SYM_LAOBJSEARCH,
LML_TFLG_AUD_OBJSEARCH, 0 },
{ MSG_SYM_LAOBJOPEN,
LML_TFLG_AUD_OBJOPEN, 0 },
{ MSG_SYM_LAOBJFILTER,
LML_TFLG_AUD_OBJFILTER, 0 },
{ MSG_SYM_LAOBJCLOSE,
LML_TFLG_AUD_OBJCLOSE, 0 },
{ MSG_SYM_LAACTIVITY,
LML_TFLG_AUD_ACTIVITY, 0 },
#if defined(_ELF64)
{ MSG_SYM_LASYMBIND_64,
#else
{ MSG_SYM_LASYMBIND,
#endif
LML_TFLG_AUD_SYMBIND, 0 },
#if defined(__sparcv9)
{ MSG_SYM_LAV9PLTENTER,
#elif defined(__sparc)
{ MSG_SYM_LAV8PLTENTER,
#elif defined(__amd64)
{ MSG_SYM_LAAMD64PLTENTER,
#elif defined(__i386)
{ MSG_SYM_LAX86PLTENTER,
#else
#error platform not defined!
#endif
LML_TFLG_AUD_PLTENTER, AF_PLTENTER },
#if defined(_ELF64)
{ MSG_SYM_LAPLTEXIT_64,
#else
{ MSG_SYM_LAPLTEXIT,
#endif
LML_TFLG_AUD_PLTEXIT, AF_PLTEXIT }
};
#define AI_LAVERSION 0
#define AI_LAPREINIT 1
#define AI_LAOBJSEARCH 2
#define AI_LAOBJOPEN 3
#define AI_LAOBJFILTER 4
#define AI_LAOBJCLOSE 5
#define AI_LAACTIVITY 6
#define AI_LASYMBIND 7
#define AI_LAPLTENTER 8
#define AI_LAPLTEXIT 9
static Addr
audit_symget(Audit_list *alp, int info, int *in_nfavl)
{
Rt_map *lmp = alp->al_lmp;
const char *sname = MSG_ORIG(aud_info[info].sname);
uint_t alflag = aud_info[info].alflag;
uint_t auflag = aud_info[info].auflag;
uint_t binfo;
Slookup sl;
Sresult sr;
SLOOKUP_INIT(sl, sname, lml_rtld.lm_head, lmp, ld_entry_cnt,
0, 0, 0, 0, (LKUP_FIRST | LKUP_DLSYM));
SRESULT_INIT(sr, sname);
if (LM_LOOKUP_SYM(lmp)(&sl, &sr, &binfo, in_nfavl)) {
Addr addr = sr.sr_sym->st_value;
if (!(FLAGS(lmp) & FLG_RT_FIXED))
addr += ADDR(lmp);
if (alflag)
alp->al_flags |= alflag;
if (auflag)
audit_flags |= auflag;
DBG_CALL(Dbg_audit_interface(LIST(alp->al_lmp),
alp->al_libname, sr.sr_name));
return (addr);
}
return (0);
}
static int
audit_disable(char *name, Rt_map *clmp, Grp_hdl *ghp, Audit_list *alp)
{
eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_AUD_DISABLED), name);
if (ghp)
(void) dlclose_intn(ghp, clmp);
if (alp)
free(alp);
return (0);
}
int
audit_setup(Rt_map *clmp, Audit_desc *adp, uint_t orig, int *in_nfavl)
{
char *ptr, *next;
Lm_list *clml = LIST(clmp);
Rt_map *hlmp;
int error = 1, activity = 0, preinit = 0;
uint_t rtldflags;
if (DBG_ENABLED) {
int type;
if (orig & PD_FLG_EXTLOAD)
type = DBG_AUD_PRELOAD;
else if (FLAGS1(clmp) & FL1_RT_GLOBAUD)
type = DBG_AUD_GLOBAL;
else
type = DBG_AUD_LOCAL;
DBG_CALL(Dbg_audit_lib(clmp, adp->ad_name, type));
}
rtld_flags2 |= RT_FL2_HASAUDIT;
for (ptr = strtok_r(adp->ad_name, MSG_ORIG(MSG_STR_DELIMIT), &next);
ptr; ptr = strtok_r(NULL, MSG_ORIG(MSG_STR_DELIMIT), &next)) {
Grp_hdl *ghp;
Rt_map *lmp;
Lm_list *lml;
Rt_map **tobj;
Audit_list *alp;
DBG_CALL(Dbg_util_nl(clml, DBG_NL_STD));
if ((ghp = dlmopen_intn((Lm_list *)LM_ID_NEWLM, ptr,
(RTLD_FIRST | RTLD_GLOBAL | RTLD_WORLD), clmp,
FLG_RT_AUDIT, orig)) == NULL) {
error = audit_disable(ptr, clmp, 0, 0);
continue;
}
lmp = ghp->gh_ownlmp;
lml = LIST(lmp);
if ((alp = lml->lm_alp) != NULL) {
if (aplist_append(&(adp->ad_list), alp,
AL_CNT_AUDITORS) == NULL)
return (audit_disable(ptr, clmp, ghp, alp));
adp->ad_cnt++;
adp->ad_flags |= alp->al_flags;
if (alp->al_preinit)
preinit++;
if (alp->al_activity)
activity++;
continue;
}
if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0)
lml->lm_flags |= LML_FLG_HOLDLOCK;
if ((alp = calloc(1, sizeof (Audit_list))) == NULL)
return (audit_disable(ptr, clmp, ghp, 0));
alp->al_libname = NAME(lmp);
alp->al_lmp = lmp;
alp->al_ghp = ghp;
if ((alp->al_version = (uint_t(*)())audit_symget(alp,
AI_LAVERSION, in_nfavl)) == 0) {
eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM),
MSG_ORIG(MSG_SYM_LAVERSION));
error = audit_disable(ptr, clmp, ghp, alp);
continue;
}
if ((tobj = tsort(lmp, lml->lm_init, RT_SORT_REV)) ==
(Rt_map **)S_ERROR)
return (audit_disable(ptr, clmp, ghp, alp));
if (tobj)
call_init(tobj, DBG_INIT_SORT);
APPLICATION_ENTER(rtldflags);
leave(lml, thr_flg_reenter);
alp->al_vernum = (*alp->al_version)(LAV_CURRENT);
(void) enter(thr_flg_reenter);
APPLICATION_RETURN(rtldflags);
DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
LAV_CURRENT, alp->al_vernum));
if ((alp->al_vernum < LAV_VERSION1) ||
(alp->al_vernum > LAV_CURRENT)) {
eprintf(lml, ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS),
LAV_CURRENT, alp->al_vernum);
error = audit_disable(ptr, clmp, ghp, alp);
continue;
}
if (aplist_append(&(adp->ad_list), alp,
AL_CNT_AUDITORS) == NULL)
return (audit_disable(ptr, clmp, ghp, alp));
adp->ad_cnt++;
alp->al_objsearch = (char *(*)())audit_symget(alp,
AI_LAOBJSEARCH, in_nfavl);
alp->al_objopen = (uint_t(*)())audit_symget(alp,
AI_LAOBJOPEN, in_nfavl);
alp->al_objfilter = (int(*)())audit_symget(alp,
AI_LAOBJFILTER, in_nfavl);
alp->al_objclose = (uint_t(*)())audit_symget(alp,
AI_LAOBJCLOSE, in_nfavl);
alp->al_symbind = (uintptr_t(*)())audit_symget(alp,
AI_LASYMBIND, in_nfavl);
alp->al_pltenter = (uintptr_t(*)())audit_symget(alp,
AI_LAPLTENTER, in_nfavl);
alp->al_pltexit = (uintptr_t(*)())audit_symget(alp,
AI_LAPLTEXIT, in_nfavl);
if ((alp->al_preinit = (void(*)())audit_symget(alp,
AI_LAPREINIT, in_nfavl)) != NULL)
preinit++;
if ((alp->al_activity = (void(*)())audit_symget(alp,
AI_LAACTIVITY, in_nfavl)) != NULL)
activity++;
adp->ad_flags |= alp->al_flags;
lml->lm_alp = alp;
}
if ((preinit || activity) && ((hlmp = clml->lm_head) != clmp) &&
(_audit_add_head(clmp, hlmp, preinit, activity) == 0))
return (0);
free(adp->ad_name);
adp->ad_name = NULL;
return (error);
}