コード例 #1
0
ファイル: audit.c プロジェクト: AlainODea/illumos-gate
/*
 * 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);
	}
}
コード例 #2
0
ファイル: audit.c プロジェクト: andreiw/polaris
audit_symget(Audit_list * alp, int info)
{
	Rt_map		*_lmp, *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;
	Sym		*sym;
	Slookup		sl;

	sl.sl_name = sname;
	sl.sl_cmap = lml_rtld.lm_head;
	sl.sl_imap = lmp;
	sl.sl_hash = 0;
	sl.sl_rsymndx = 0;
	sl.sl_flags = LKUP_FIRST;

	if (sym = LM_LOOKUP_SYM(lmp)(&sl, &_lmp, &binfo)) {
		Addr	addr = 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, sname));
		return (addr);
	} else
		return (0);
}
コード例 #3
0
ファイル: audit.c プロジェクト: andreiw/polaris
/*
 * la_objopen() caller.  Create an audit information structure for the indicated
 * link-map, regardless of an la_objopen() entry point.  This structure is used
 * to supply information to various audit interfaces (see LML_MSK_AUDINFO).
 * Traverses through all audit library and calls any la_objopen() entry points
 * found.
 */
static int
_audit_objopen(List *list, Rt_map *nlmp, Lmid_t lmid, Audit_info *aip,
    int *ndx)
{
	Audit_list	*alp;
	Listnode	*lnp;

	for (LIST_TRAVERSE(list, lnp, alp)) {
		uint_t		flags;
		Audit_client	*acp;

		/*
		 * Associate a cookie with the audit library, and assign the
		 * initial cookie as the present link-map.
		 */
		acp = &aip->ai_clients[(*ndx)++];
		acp->ac_lmp = alp->al_lmp;
		acp->ac_cookie = (uintptr_t)nlmp;

		if (alp->al_objopen == 0)
			continue;

		DBG_CALL(Dbg_audit_object(LIST(alp->al_lmp), alp->al_libname,
		    NAME(nlmp)));

		leave(LIST(alp->al_lmp));
		flags = (*alp->al_objopen)((Link_map *)nlmp, lmid,
			&(acp->ac_cookie));
		(void) enter();

		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;
			/*
			 * We only need dynamic plt's if a pltenter and/or a
			 * pltexit() entry point exist in one of our auditing
			 * libraries.
			 */
			if (aip->ai_dynplts || (JMPREL(nlmp) == 0) ||
			    ((audit_flags & (AF_PLTENTER | AF_PLTEXIT)) == 0))
				continue;

			/*
			 * Create one dynplt for every 'PLT' that exists in the
			 * object.
			 */
			pltcnt = PLTRELSZ(nlmp) / RELENT(nlmp);
			if ((aip->ai_dynplts = calloc(pltcnt,
			    dyn_plt_ent_size)) == 0)
				return (0);
		}
	}
	return (1);
}
コード例 #4
0
ファイル: audit.c プロジェクト: AlainODea/illumos-gate
/*
 * 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);
}
コード例 #5
0
ファイル: i386_elf.c プロジェクト: carmark/illumos-gate
/*
 * Plt writing interface to allow debugging initialization to be generic.
 */
Pltbindtype
/* ARGSUSED1 */
elf_plt_write(uintptr_t addr, uintptr_t vaddr, void *rptr, uintptr_t symval,
	Xword pltndx)
{
	Rel		*rel = (Rel*)rptr;
	uintptr_t	pltaddr;

	pltaddr = addr + rel->r_offset;
	*(ulong_t *)pltaddr = (ulong_t)symval;
	DBG_CALL(pltcntfull++);
	return (PLT_T_FULL);
}
コード例 #6
0
ファイル: audit.c プロジェクト: AlainODea/illumos-gate
/*
 * 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);
}
コード例 #7
0
ファイル: tls.c プロジェクト: AlfredArouna/illumos-gate
void
tls_modaddrem(Rt_map *lmp, uint_t flag)
{
	Lm_list		*lml = LIST(lmp);
	TLS_modinfo	tmi;
	Phdr		*tlsphdr;
	void		(*fptr)(TLS_modinfo *);

	if (flag & TM_FLG_MODADD) {
		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODADD].lc_un.lc_func;
	} else if (FLAGS1(lmp) & FL1_RT_TLSADD) {
		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODREM].lc_un.lc_func;
	} else {
		return;
	}

	tlsphdr = PTTLS(lmp);

	bzero(&tmi, sizeof (tmi));
	tmi.tm_modname = PATHNAME(lmp);
	tmi.tm_modid = TLSMODID(lmp);
	tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr);

	if (!(FLAGS(lmp) & FLG_RT_FIXED))
		tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
		    ADDR(lmp));

	tmi.tm_filesz = tlsphdr->p_filesz;
	tmi.tm_memsz = tlsphdr->p_memsz;
	tmi.tm_flags = 0;
	tmi.tm_stattlsoffset = 0;

	DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
	(*fptr)(&tmi);

	/*
	 * Tag that this link-map has registered its TLS, and, if this object
	 * is being removed, free up the module id.
	 */
	FLAGS1(lmp) |= FL1_RT_TLSADD;

	if (flag & TM_FLG_MODREM)
		tls_freemodid(TLSMODID(lmp));
}
コード例 #8
0
ファイル: i386_elf.c プロジェクト: carmark/illumos-gate
int
elf_copy_gen(Rt_map *lmp)
{
	if (interp && ((ulong_t)interp->i_faddr !=
	    r_debug.rtd_rdebug.r_ldbase) &&
	    !(strcmp(interp->i_name, MSG_ORIG(MSG_PTH_LIBC)))) {

		DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, 0,
		    DBG_REL_START));

		if (_elf_copy_reloc(MSG_ORIG(MSG_SYM_CTYPE), lmp,
		    (Rt_map *)NEXT(lmp)) == 0)
			return (0);
		if (_elf_copy_reloc(MSG_ORIG(MSG_SYM_IOB), lmp,
		    (Rt_map *)NEXT(lmp)) == 0)
			return (0);
	}
	return (1);
}
コード例 #9
0
ファイル: audit.c プロジェクト: andreiw/polaris
/*
 * 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));
	}
}
コード例 #10
0
ファイル: audit.c プロジェクト: andreiw/polaris
char *
audit_objsearch(Rt_map *clmp, const char *name, uint_t flags)
{
	char	*nname = (char *)name;
	int	appl = 0;

	if ((rtld_flags & RT_FL_APPLIC) == 0)
		appl = rtld_flags |= RT_FL_APPLIC;

	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);

	if (appl)
		rtld_flags &= ~RT_FL_APPLIC;

	DBG_CALL(Dbg_libs_audit(LIST(clmp), name, nname));
	return (nname);
}
コード例 #11
0
ファイル: move.c プロジェクト: AlfredArouna/illumos-gate
/*
 * Warning message for bad move target.
 */
void
elf_move_bad(Lm_list *lml, Rt_map *lmp, Sym *sym, ulong_t num, Addr addr)
{
	const char	*name;
	int		trace;

	trace = (lml->lm_flags & LML_FLG_TRC_ENABLE) &&
	    (((rtld_flags & RT_FL_SILENCERR) == 0) ||
	    (lml->lm_flags & (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_WARN)));

	if ((trace == 0) && (DBG_ENABLED == 0))
		return;

	if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
		name = (const char *)(STRTAB(lmp) + sym->st_name);
	else
		name = MSG_INTL(MSG_STR_UNKNOWN);

	if (trace)
		(void) printf(MSG_INTL(MSG_LDD_MOVE_ERR), EC_XWORD(num), name,
		    EC_ADDR(addr));
	else
		DBG_CALL(Dbg_move_bad(lml, num, name, addr));
}
コード例 #12
0
ファイル: audit.c プロジェクト: AlainODea/illumos-gate
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);
}
コード例 #13
0
ファイル: audit.c プロジェクト: AlainODea/illumos-gate
/*
 * 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);
	}
}
コード例 #14
0
ファイル: i386_elf.c プロジェクト: carmark/illumos-gate
/*
 * Read and process the relocations for one link object, we assume all
 * relocation sections for loadable segments are stored contiguously in
 * the file.
 */
int
elf_reloc(Rt_map *lmp, uint_t plt, int *in_nfavl, APlist **textrel)
{
	ulong_t		relbgn, relend, relsiz, basebgn, pltbgn, pltend;
	ulong_t		_pltbgn, _pltend;
	ulong_t		dsymndx, roffset, rsymndx, psymndx = 0;
	uchar_t		rtype;
	long		value, pvalue;
	Sym		*symref, *psymref, *symdef, *psymdef;
	Syminfo		*sip;
	char		*name, *pname;
	Rt_map		*_lmp, *plmp;
	int		ret = 1, noplt = 0;
	int		relacount = RELACOUNT(lmp), plthint = 0;
	Rel		*rel;
	uint_t		binfo, pbinfo;
	APlist		*bound = NULL;

	/*
	 * Although only necessary for lazy binding, initialize the first
	 * global offset entry to go to elf_rtbndr().  dbx(1) seems
	 * to find this useful.
	 */
	if ((plt == 0) && PLTGOT(lmp)) {
		mmapobj_result_t	*mpp;

		/*
		 * Make sure the segment is writable.
		 */
		if ((((mpp =
		    find_segment((caddr_t)PLTGOT(lmp), lmp)) != NULL) &&
		    ((mpp->mr_prot & PROT_WRITE) == 0)) &&
		    ((set_prot(lmp, mpp, 1) == 0) ||
		    (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL)))
			return (0);

		elf_plt_init(PLTGOT(lmp), (caddr_t)lmp);
	}

	/*
	 * Initialize the plt start and end addresses.
	 */
	if ((pltbgn = (ulong_t)JMPREL(lmp)) != 0)
		pltend = pltbgn + (ulong_t)(PLTRELSZ(lmp));

	relsiz = (ulong_t)(RELENT(lmp));
	basebgn = ADDR(lmp);

	if (PLTRELSZ(lmp))
		plthint = PLTRELSZ(lmp) / relsiz;

	/*
	 * If we've been called upon to promote an RTLD_LAZY object to an
	 * RTLD_NOW then we're only interested in scaning the .plt table.
	 * An uninitialized .plt is the case where the associated got entry
	 * points back to the plt itself.  Determine the range of the real .plt
	 * entries using the _PROCEDURE_LINKAGE_TABLE_ symbol.
	 */
	if (plt) {
		Slookup	sl;
		Sresult	sr;

		relbgn = pltbgn;
		relend = pltend;
		if (!relbgn || (relbgn == relend))
			return (1);

		/*
		 * Initialize the symbol lookup, and symbol result, data
		 * structures.
		 */
		SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_PLT), lmp, lmp, ld_entry_cnt,
		    elf_hash(MSG_ORIG(MSG_SYM_PLT)), 0, 0, 0, LKUP_DEFT);
		SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_PLT));

		if (elf_find_sym(&sl, &sr, &binfo, NULL) == 0)
			return (1);

		symdef = sr.sr_sym;
		_pltbgn = symdef->st_value;
		if (!(FLAGS(lmp) & FLG_RT_FIXED) &&
		    (symdef->st_shndx != SHN_ABS))
			_pltbgn += basebgn;
		_pltend = _pltbgn + (((PLTRELSZ(lmp) / relsiz)) *
		    M_PLT_ENTSIZE) + M_PLT_RESERVSZ;

	} else {
		/*
		 * The relocation sections appear to the run-time linker as a
		 * single table.  Determine the address of the beginning and end
		 * of this table.  There are two different interpretations of
		 * the ABI at this point:
		 *
		 *   o	The REL table and its associated RELSZ indicate the
		 *	concatenation of *all* relocation sections (this is the
		 *	model our link-editor constructs).
		 *
		 *   o	The REL table and its associated RELSZ indicate the
		 *	concatenation of all *but* the .plt relocations.  These
		 *	relocations are specified individually by the JMPREL and
		 *	PLTRELSZ entries.
		 *
		 * Determine from our knowledege of the relocation range and
		 * .plt range, the range of the total relocation table.  Note
		 * that one other ABI assumption seems to be that the .plt
		 * relocations always follow any other relocations, the
		 * following range checking drops that assumption.
		 */
		relbgn = (ulong_t)(REL(lmp));
		relend = relbgn + (ulong_t)(RELSZ(lmp));
		if (pltbgn) {
			if (!relbgn || (relbgn > pltbgn))
				relbgn = pltbgn;
			if (!relbgn || (relend < pltend))
				relend = pltend;
		}
	}
	if (!relbgn || (relbgn == relend)) {
		DBG_CALL(Dbg_reloc_run(lmp, 0, plt, DBG_REL_NONE));
		return (1);
	}
	DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, plt, DBG_REL_START));

	/*
	 * If we're processing a dynamic executable in lazy mode there is no
	 * need to scan the .rel.plt table, however if we're processing a shared
	 * object in lazy mode the .got addresses associated to each .plt must
	 * be relocated to reflect the location of the shared object.
	 */
	if (pltbgn && ((MODE(lmp) & RTLD_NOW) == 0) &&
	    (FLAGS(lmp) & FLG_RT_FIXED))
		noplt = 1;

	sip = SYMINFO(lmp);
	/*
	 * Loop through relocations.
	 */
	while (relbgn < relend) {
		mmapobj_result_t	*mpp;
		uint_t			sb_flags = 0;

		rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH);

		/*
		 * If this is a RELATIVE relocation in a shared object (the
		 * common case), and if we are not debugging, then jump into a
		 * tighter relocation loop (elf_reloc_relative).
		 */
		if ((rtype == R_386_RELATIVE) &&
		    ((FLAGS(lmp) & FLG_RT_FIXED) == 0) && (DBG_ENABLED == 0)) {
			if (relacount) {
				relbgn = elf_reloc_relative_count(relbgn,
				    relacount, relsiz, basebgn, lmp,
				    textrel, 0);
				relacount = 0;
			} else {
				relbgn = elf_reloc_relative(relbgn, relend,
				    relsiz, basebgn, lmp, textrel, 0);
			}
			if (relbgn >= relend)
				break;
			rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH);
		}

		roffset = ((Rel *)relbgn)->r_offset;

		/*
		 * If this is a shared object, add the base address to offset.
		 */
		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
			/*
			 * If we're processing lazy bindings, we have to step
			 * through the plt entries and add the base address
			 * to the corresponding got entry.
			 */
			if (plthint && (plt == 0) &&
			    (rtype == R_386_JMP_SLOT) &&
			    ((MODE(lmp) & RTLD_NOW) == 0)) {
				relbgn = elf_reloc_relative_count(relbgn,
				    plthint, relsiz, basebgn, lmp, textrel, 0);
				plthint = 0;
				continue;
			}
			roffset += basebgn;
		}

		rsymndx = ELF_R_SYM(((Rel *)relbgn)->r_info);
		rel = (Rel *)relbgn;
		relbgn += relsiz;

		/*
		 * Optimizations.
		 */
		if (rtype == R_386_NONE)
			continue;
		if (noplt && ((ulong_t)rel >= pltbgn) &&
		    ((ulong_t)rel < pltend)) {
			relbgn = pltend;
			continue;
		}

		/*
		 * If we're promoting plts, determine if this one has already
		 * been written.
		 */
		if (plt && ((*(ulong_t *)roffset < _pltbgn) ||
		    (*(ulong_t *)roffset > _pltend)))
			continue;

		/*
		 * If this relocation is not against part of the image
		 * mapped into memory we skip it.
		 */
		if ((mpp = find_segment((caddr_t)roffset, lmp)) == NULL) {
			elf_reloc_bad(lmp, (void *)rel, rtype, roffset,
			    rsymndx);
			continue;
		}

		binfo = 0;
		/*
		 * If a symbol index is specified then get the symbol table
		 * entry, locate the symbol definition, and determine its
		 * address.
		 */
		if (rsymndx) {
			/*
			 * If a Syminfo section is provided, determine if this
			 * symbol is deferred, and if so, skip this relocation.
			 */
			if (sip && is_sym_deferred((ulong_t)rel, basebgn, lmp,
			    textrel, sip, rsymndx))
				continue;

			/*
			 * Get the local symbol table entry.
			 */
			symref = (Sym *)((ulong_t)SYMTAB(lmp) +
			    (rsymndx * SYMENT(lmp)));

			/*
			 * If this is a local symbol, just use the base address.
			 * (we should have no local relocations in the
			 * executable).
			 */
			if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) {
				value = basebgn;
				name = NULL;

				/*
				 * Special case TLS relocations.
				 */
				if (rtype == R_386_TLS_DTPMOD32) {
					/*
					 * Use the TLS modid.
					 */
					value = TLSMODID(lmp);

				} else if (rtype == R_386_TLS_TPOFF) {
					if ((value = elf_static_tls(lmp, symref,
					    rel, rtype, 0, roffset, 0)) == 0) {
						ret = 0;
						break;
					}
				}
			} else {
				/*
				 * If the symbol index is equal to the previous
				 * symbol index relocation we processed then
				 * reuse the previous values. (Note that there
				 * have been cases where a relocation exists
				 * against a copy relocation symbol, our ld(1)
				 * should optimize this away, but make sure we
				 * don't use the same symbol information should
				 * this case exist).
				 */
				if ((rsymndx == psymndx) &&
				    (rtype != R_386_COPY)) {
					/* LINTED */
					if (psymdef == 0) {
						DBG_CALL(Dbg_bind_weak(lmp,
						    (Addr)roffset, (Addr)
						    (roffset - basebgn), name));
						continue;
					}
					/* LINTED */
					value = pvalue;
					/* LINTED */
					name = pname;
					/* LINTED */
					symdef = psymdef;
					/* LINTED */
					symref = psymref;
					/* LINTED */
					_lmp = plmp;
					/* LINTED */
					binfo = pbinfo;

					if ((LIST(_lmp)->lm_tflags |
					    AFLAGS(_lmp)) &
					    LML_TFLG_AUD_SYMBIND) {
						value = audit_symbind(lmp, _lmp,
						    /* LINTED */
						    symdef, dsymndx, value,
						    &sb_flags);
					}
				} else {
					Slookup		sl;
					Sresult		sr;

					/*
					 * Lookup the symbol definition.
					 * Initialize the symbol lookup, and
					 * symbol result, data structures.
					 */
					name = (char *)(STRTAB(lmp) +
					    symref->st_name);

					SLOOKUP_INIT(sl, name, lmp, 0,
					    ld_entry_cnt, 0, rsymndx, symref,
					    rtype, LKUP_STDRELOC);
					SRESULT_INIT(sr, name);
					symdef = NULL;

					if (lookup_sym(&sl, &sr, &binfo,
					    in_nfavl)) {
						name = (char *)sr.sr_name;
						_lmp = sr.sr_dmap;
						symdef = sr.sr_sym;
					}

					/*
					 * If the symbol is not found and the
					 * reference was not to a weak symbol,
					 * report an error.  Weak references
					 * may be unresolved.
					 */
					/* BEGIN CSTYLED */
					if (symdef == 0) {
					    if (sl.sl_bind != STB_WEAK) {
						if (elf_reloc_error(lmp, name,
						    rel, binfo))
							continue;

					   	ret = 0;
						break;

					    } else {
						psymndx = rsymndx;
						psymdef = 0;

						DBG_CALL(Dbg_bind_weak(lmp,
						    (Addr)roffset, (Addr)
						    (roffset - basebgn), name));
						continue;
					    }
					}
					/* END CSTYLED */

					/*
					 * If symbol was found in an object
					 * other than the referencing object
					 * then record the binding.
					 */
					if ((lmp != _lmp) && ((FLAGS1(_lmp) &
					    FL1_RT_NOINIFIN) == 0)) {
						if (aplist_test(&bound, _lmp,
						    AL_CNT_RELBIND) == 0) {
							ret = 0;
							break;
						}
					}

					/*
					 * Calculate the location of definition;
					 * symbol value plus base address of
					 * containing shared object.
					 */
					if (IS_SIZE(rtype))
						value = symdef->st_size;
					else
						value = symdef->st_value;

					if (!(FLAGS(_lmp) & FLG_RT_FIXED) &&
					    !(IS_SIZE(rtype)) &&
					    (symdef->st_shndx != SHN_ABS) &&
					    (ELF_ST_TYPE(symdef->st_info) !=
					    STT_TLS))
						value += ADDR(_lmp);

					/*
					 * Retain this symbol index and the
					 * value in case it can be used for the
					 * subsequent relocations.
					 */
					if (rtype != R_386_COPY) {
						psymndx = rsymndx;
						pvalue = value;
						pname = name;
						psymdef = symdef;
						psymref = symref;
						plmp = _lmp;
						pbinfo = binfo;
					}
					if ((LIST(_lmp)->lm_tflags |
					    AFLAGS(_lmp)) &
					    LML_TFLG_AUD_SYMBIND) {
						dsymndx = (((uintptr_t)symdef -
						    (uintptr_t)SYMTAB(_lmp)) /
						    SYMENT(_lmp));
						value = audit_symbind(lmp, _lmp,
						    symdef, dsymndx, value,
						    &sb_flags);
					}
				}

				/*
				 * If relocation is PC-relative, subtract
				 * offset address.
				 */
				if (IS_PC_RELATIVE(rtype))
					value -= roffset;

				/*
				 * Special case TLS relocations.
				 */
				if (rtype == R_386_TLS_DTPMOD32) {
					/*
					 * Relocation value is the TLS modid.
					 */
					value = TLSMODID(_lmp);

				} else if (rtype == R_386_TLS_TPOFF) {
					if ((value = elf_static_tls(_lmp,
					    symdef, rel, rtype, name, roffset,
					    value)) == 0) {
						ret = 0;
						break;
					}
				}
			}
		} else {
			/*
			 * Special cases.
			 */
			if (rtype == R_386_TLS_DTPMOD32) {
				/*
				 * TLS relocation value is the TLS modid.
				 */
				value = TLSMODID(lmp);
			} else
				value = basebgn;

			name = NULL;
		}

		DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH,
		    M_REL_SHT_TYPE, rel, NULL, 0, name));

		/*
		 * Make sure the segment is writable.
		 */
		if (((mpp->mr_prot & PROT_WRITE) == 0) &&
		    ((set_prot(lmp, mpp, 1) == 0) ||
		    (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) {
			ret = 0;
			break;
		}

		/*
		 * Call relocation routine to perform required relocation.
		 */
		switch (rtype) {
		case R_386_COPY:
			if (elf_copy_reloc(name, symref, lmp, (void *)roffset,
			    symdef, _lmp, (const void *)value) == 0)
				ret = 0;
			break;
		case R_386_JMP_SLOT:
			if (((LIST(lmp)->lm_tflags | AFLAGS(lmp)) &
			    (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) &&
			    AUDINFO(lmp)->ai_dynplts) {
				int	fail = 0;
				int	pltndx = (((ulong_t)rel -
				    (uintptr_t)JMPREL(lmp)) / relsiz);
				int	symndx = (((uintptr_t)symdef -
				    (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp));

				(void) elf_plt_trace_write(roffset, lmp, _lmp,
				    symdef, symndx, pltndx, (caddr_t)value,
				    sb_flags, &fail);
				if (fail)
					ret = 0;
			} else {
				/*
				 * Write standard PLT entry to jump directly
				 * to newly bound function.
				 */
				DBG_CALL(Dbg_reloc_apply_val(LIST(lmp),
				    ELF_DBG_RTLD, (Xword)roffset,
				    (Xword)value));
				*(ulong_t *)roffset = value;
			}
			break;
		default:
			/*
			 * Write the relocation out.
			 */
			if (do_reloc_rtld(rtype, (uchar_t *)roffset,
			    (Word *)&value, name, NAME(lmp), LIST(lmp)) == 0)
				ret = 0;

			DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD,
			    (Xword)roffset, (Xword)value));
		}

		if ((ret == 0) &&
		    ((LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) == 0))
			break;

		if (binfo) {
			DBG_CALL(Dbg_bind_global(lmp, (Addr)roffset,
			    (Off)(roffset - basebgn), (Xword)(-1), PLT_T_FULL,
			    _lmp, (Addr)value, symdef->st_value, name, binfo));
		}
	}

	return (relocate_finish(lmp, bound, ret));
}
コード例 #15
0
ファイル: i386_elf.c プロジェクト: carmark/illumos-gate
/*
 * Function binding routine - invoked on the first call to a function through
 * the procedure linkage table;
 * passes first through an assembly language interface.
 *
 * Takes the offset into the relocation table of the associated
 * relocation entry and the address of the link map (rt_private_map struct)
 * for the entry.
 *
 * Returns the address of the function referenced after re-writing the PLT
 * entry to invoke the function directly.
 *
 * On error, causes process to terminate with a signal.
 */
ulong_t
elf_bndr(Rt_map *lmp, ulong_t reloff, caddr_t from)
{
	Rt_map		*nlmp, *llmp;
	ulong_t		addr, symval, rsymndx;
	char		*name;
	Rel		*rptr;
	Sym		*rsym, *nsym;
	uint_t		binfo, sb_flags = 0, dbg_class;
	Slookup		sl;
	Sresult		sr;
	int		entry, lmflags;
	Lm_list		*lml;

	/*
	 * For compatibility with libthread (TI_VERSION 1) we track the entry
	 * value.  A zero value indicates we have recursed into ld.so.1 to
	 * further process a locking request.  Under this recursion we disable
	 * tsort and cleanup activities.
	 */
	entry = enter(0);

	lml = LIST(lmp);
	if ((lmflags = lml->lm_flags) & LML_FLG_RTLDLM) {
		dbg_class = dbg_desc->d_class;
		dbg_desc->d_class = 0;
	}

	/*
	 * Perform some basic sanity checks.  If we didn't get a load map or
	 * the relocation offset is invalid then its possible someone has walked
	 * over the .got entries or jumped to plt0 out of the blue.
	 */
	if (!lmp || ((reloff % sizeof (Rel)) != 0)) {
		Conv_inv_buf_t inv_buf;

		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_PLTREF),
		    conv_reloc_386_type(R_386_JMP_SLOT, 0, &inv_buf),
		    EC_NATPTR(lmp), EC_XWORD(reloff), EC_NATPTR(from));
		rtldexit(lml, 1);
	}

	/*
	 * Use relocation entry to get symbol table entry and symbol name.
	 */
	addr = (ulong_t)JMPREL(lmp);
	rptr = (Rel *)(addr + reloff);
	rsymndx = ELF_R_SYM(rptr->r_info);
	rsym = (Sym *)((ulong_t)SYMTAB(lmp) + (rsymndx * SYMENT(lmp)));
	name = (char *)(STRTAB(lmp) + rsym->st_name);

	/*
	 * Determine the last link-map of this list, this'll be the starting
	 * point for any tsort() processing.
	 */
	llmp = lml->lm_tail;

	/*
	 * Find definition for symbol.  Initialize the symbol lookup, and
	 * symbol result, data structures.
	 */
	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0,
	    rsymndx, rsym, 0, LKUP_DEFT);
	SRESULT_INIT(sr, name);

	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) {
		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
		    demangle(name));
		rtldexit(lml, 1);
	}

	name = (char *)sr.sr_name;
	nlmp = sr.sr_dmap;
	nsym = sr.sr_sym;

	symval = nsym->st_value;

	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
	    (nsym->st_shndx != SHN_ABS))
		symval += ADDR(nlmp);
	if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) {
		/*
		 * Record that this new link map is now bound to the caller.
		 */
		if (bind_one(lmp, nlmp, BND_REFER) == 0)
			rtldexit(lml, 1);
	}

	if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_SYMBIND) {
		uint_t	symndx = (((uintptr_t)nsym -
		    (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp));
		symval = audit_symbind(lmp, nlmp, nsym, symndx, symval,
		    &sb_flags);
	}

	if (!(rtld_flags & RT_FL_NOBIND)) {
		addr = rptr->r_offset;
		if (!(FLAGS(lmp) & FLG_RT_FIXED))
			addr += ADDR(lmp);
		if (((lml->lm_tflags | AFLAGS(lmp)) &
		    (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) &&
		    AUDINFO(lmp)->ai_dynplts) {
			int	fail = 0;
			uint_t	pltndx = reloff / sizeof (Rel);
			uint_t	symndx = (((uintptr_t)nsym -
			    (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp));

			symval = (ulong_t)elf_plt_trace_write(addr, lmp, nlmp,
			    nsym, symndx, pltndx, (caddr_t)symval, sb_flags,
			    &fail);
			if (fail)
				rtldexit(lml, 1);
		} else {
			/*
			 * Write standard PLT entry to jump directly
			 * to newly bound function.
			 */
			*(ulong_t *)addr = symval;
		}
	}

	/*
	 * Print binding information and rebuild PLT entry.
	 */
	DBG_CALL(Dbg_bind_global(lmp, (Addr)from, (Off)(from - ADDR(lmp)),
	    (Xword)(reloff / sizeof (Rel)), PLT_T_FULL, nlmp, (Addr)symval,
	    nsym->st_value, name, binfo));

	/*
	 * Complete any processing for newly loaded objects.  Note we don't
	 * know exactly where any new objects are loaded (we know the object
	 * that supplied the symbol, but others may have been loaded lazily as
	 * we searched for the symbol), so sorting starts from the last
	 * link-map know on entry to this routine.
	 */
	if (entry)
		load_completion(llmp);

	/*
	 * Some operations like dldump() or dlopen()'ing a relocatable object
	 * result in objects being loaded on rtld's link-map, make sure these
	 * objects are initialized also.
	 */
	if ((LIST(nlmp)->lm_flags & LML_FLG_RTLDLM) && LIST(nlmp)->lm_init)
		load_completion(nlmp);

	/*
	 * Make sure the object to which we've bound has had it's .init fired.
	 * Cleanup before return to user code.
	 */
	if (entry) {
		is_dep_init(nlmp, lmp);
		leave(lml, 0);
	}

	if (lmflags & LML_FLG_RTLDLM)
		dbg_desc->d_class = dbg_class;

	return (symval);
}
コード例 #16
0
ファイル: order.c プロジェクト: andreiw/polaris
static Word
get_shfordered_dest(Ofl_desc *ofl, Ifl_desc *ifl, Word ndx, Word limit)
{
	Word t1_link = ndx, t2_link, ret_link;
	Is_desc *isp, *isp1, *isp2;
	int error = 0;

	/*
	 * Check the sh_info of myself.
	 */
	isp = ifl->ifl_isdesc[ndx];

	isp1 = isp;
	ret_link = t2_link = isp1->is_shdr->sh_link;
	t1_link = ndx;
	do {
		/*
		 * Check the validitiy of the link
		 */
		if (t2_link == 0 || t2_link >= limit) {
			error = DBG_ORDER_LINK_OUTRANGE;
			break;
		}
		isp2 = ifl->ifl_isdesc[t2_link];

		/*
		 * Pointing to a bad ordered section ?
		 */
		if ((isp2->is_flags & FLG_IS_ORDERED) == 0) {
			error = DBG_ORDER_LINK_ERROR;
			break;
		}

		/*
		 * Check sh_flag
		 */
		if (isp1->is_shdr->sh_flags != isp2->is_shdr->sh_flags) {
			error = DBG_ORDER_FLAGS;
			break;
		}

		/*
		 * Check the validity of sh_info field.
		 */
		if ((error = is_keylink_ok(ifl,
		    isp->is_shdr->sh_info, limit)) != 0) {
			break;
		}

		/*
		 * Can I break ?
		 */
		if (t1_link == t2_link)
			break;

		/*
		 * Get the next link
		 */
		t1_link = t2_link;
		isp1 = ifl->ifl_isdesc[t1_link];
		ret_link = t2_link = isp1->is_shdr->sh_link;

		/*
		 * Cyclic ?
		 */
		if (t2_link == ndx) {
			error = DBG_ORDER_CYCLIC;
			break;
		}
	/* CONSTANTCONDITION */
	} while (1);

	if (error != 0) {
		ret_link = 0;
		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
	}
	return (ret_link);
}
コード例 #17
0
ファイル: order.c プロジェクト: andreiw/polaris
uintptr_t
ld_sort_ordered(Ofl_desc *ofl)
{
	Listnode *lnp1;
	Os_desc *osp;

	DBG_CALL(Dbg_sec_order_list(ofl, 0));

	/*
	 * Sort Sections
	 */
	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp1, osp)) {
		int		i;
		List		islist;
		Listnode *	lnp2;
		Is_desc *	isp;
		Sort_desc *	st = osp->os_sort;

		if (setup_sortbuf(osp) == 0)
			return (S_ERROR);

		islist = osp->os_isdescs;
		osp->os_isdescs.head = 0;
		osp->os_isdescs.tail = 0;

		/*
		 * Sorting.
		 * First Sort the ordered sections.
		 */
		if (st->st_ordercnt != 0)
			qsort((char *)st->st_order, st->st_ordercnt,
				sizeof (Is_desc *), comp);

		/*
		 * Place SHN_BEFORE at head of list
		 */
		for (i = 0; i < st->st_beforecnt; i++) {
			if (list_appendc(&(osp->os_isdescs),
			    st->st_before[i]) == 0)
				return (S_ERROR);
		}

		/*
		 * Next come 'linked' ordered sections
		 */
		for (i = 0; i < st->st_ordercnt; i++) {
			if (list_appendc(&(osp->os_isdescs),
			    st->st_order[i]) == 0)
				return (S_ERROR);
		}

		/*
		 * Now we list any sections which have no sorting
		 * specifications - in the order they were input.
		 */
		for (LIST_TRAVERSE(&islist, lnp2, isp)) {
			if (isp->is_flags & FLG_IS_ORDERED)
				continue;
			if (list_appendc(&(osp->os_isdescs),
			    isp) == 0)
				return (S_ERROR);
		}

		/*
		 * And the end of the list are the SHN_AFTER sections.
		 */
		for (i = 0; i < st->st_aftercnt; i++) {
			if (list_appendc(&(osp->os_isdescs),
			    st->st_after[i]) == 0)
				return (S_ERROR);
		}
	}
	DBG_CALL(Dbg_sec_order_list(ofl, 1));
	return (0);
}
コード例 #18
0
ファイル: order.c プロジェクト: andreiw/polaris
/*
 * Called from process_elf().
 * This routine does the input processing of the ordered sections.
 */
uintptr_t
ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx, Word limit)
{
	Is_desc *	isp2, * isp = ifl->ifl_isdesc[ndx];
	Xword		shflags = isp->is_shdr->sh_flags;
	uint_t		keylink;
	Os_desc *	osp2, * osp;
	Word		dest_ndx;
	Sort_desc *	st;
	Listnode *	lnp;
	int		error = 0;

	/*
	 * I might have been checked and marked error already.
	 */
	if ((isp->is_flags & FLG_IS_ORDERED) == 0)
		return (0);

	if (shflags & SHF_ORDERED)
		keylink = isp->is_shdr->sh_info;
	else if (shflags & SHF_LINK_ORDER)
		keylink = isp->is_shdr->sh_link;
	else
		keylink = 0;

	if ((error = is_keylink_ok(ifl, keylink, limit)) != 0) {
		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
		isp->is_flags &= ~FLG_IS_ORDERED;
		if (isp->is_osdesc == NULL)
			return ((uintptr_t)ld_place_section(ofl, isp,
			    isp->is_key, 0));
		return ((uintptr_t)isp->is_osdesc);
	}

	/*
	 * If SHF_ORDERED is in effect, search for our destination section based
	 * off of sh_link, otherwise follow the default rules for the
	 * destination section.
	 */
	if (shflags & SHF_ORDERED) {
		if ((dest_ndx = get_shfordered_dest(ofl, ifl,
		    ndx, limit)) == 0) {
			isp->is_flags &= ~FLG_IS_ORDERED;
			if (isp->is_osdesc == NULL)
				return ((uintptr_t)ld_place_section(ofl, isp,
				    isp->is_key, 0));
			return ((uintptr_t)isp->is_osdesc);
		}
	} else {
		/*
		 * SHF_LINK_ORDER coalesces into default sections, set dest_ndx
		 * to NULL to trigger this.
		 */
		dest_ndx = 0;
	}

	/*
	 * Place the section into it's output section.
	 */
	if ((osp = isp->is_osdesc) == NULL) {
		if ((osp = ld_place_section(ofl, isp, isp->is_ident,
		    dest_ndx)) == (Os_desc *)S_ERROR)
			return ((uintptr_t)S_ERROR);
		if (!osp)
			return (0);
	}

	/*
	 * If the output section is not yet on the ordered
	 * list - place it on the list.
	 */
	osp2 = NULL;
	for (LIST_TRAVERSE(&ofl->ofl_ordered, lnp, osp2)) {
		if (osp2 == osp)
			break;
	}

	if (osp != osp2) {
		if (list_appendc(&(ofl->ofl_ordered), osp) == 0)
			return ((uintptr_t)S_ERROR);
	}

	/*
	 * Output section has been found - set up it's
	 * sorting information.
	 */
	if (osp->os_sort == 0) {
		if ((osp->os_sort = libld_calloc(1, sizeof (Sort_desc))) == 0)
			return (S_ERROR);
	}
	st = osp->os_sort;

	if (keylink == SHN_BEFORE) {
		st->st_beforecnt++;
	} else if (keylink == SHN_AFTER) {
		st->st_aftercnt++;
	} else {
		st->st_ordercnt++;
		isp2 = ifl->ifl_isdesc[keylink];
		if (isp2->is_flags & FLG_IS_DISCARD) {
			eprintf(ofl->ofl_lml, ERR_FATAL,
			    MSG_INTL(MSG_FIL_BADORDREF), ifl->ifl_name,
			    isp->is_name, isp->is_scnndx, isp2->is_name,
			    isp2->is_scnndx);
			return (S_ERROR);
		}
		osp2 = isp2->is_osdesc;
		osp2->os_flags |= FLG_OS_ORDER_KEY;
		osp2->os_sgdesc->sg_flags |= FLG_SG_KEY;
		isp2->is_flags |= FLG_IS_KEY;
	}

	return ((uintptr_t)osp);
}
コード例 #19
0
ファイル: libs.c プロジェクト: metricinc/illumos-gate
/*
 * Extract every object in the given archive directly without going through
 * the symbol table.
 *
 * entry:
 *	name - Name of archive
 *	fd - Open file descriptor for archive
 *	adp - Archive descriptor
 *	ofl - output descriptor
 *	found - Address of variable to set to TRUE if any objects are extracted
 *	rej - Rejection descriptor to pass to ld_process_ifl().
 *
 * exit:
 *	Returns FALSE on fatal error. On success, *found will be TRUE
 *	if any object was extracted, rej will be set if any object
 *	was rejected, and TRUE is returned.
 */
static Boolean
ar_extract_all(const char *name, int fd, Ar_desc *adp, Ofl_desc *ofl,
    Boolean *found, Rej_desc *rej)
{
	Elf_Cmd		cmd = ELF_C_READ;
	Elf		*arelf;
	const char	*arname, *arpath;
	size_t		off, next_off;

	DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, FALSE));

	while ((arelf = elf_begin(fd, cmd, adp->ad_elf)) != NULL) {
		/*
		 * Call elf_next() so that the next call to elf_begin() will
		 * fetch the archive member following this one. We do this now
		 * because it simplifies the logic below, and because the
		 * support libraries called below can set our handle to NULL.
		 */
		cmd = elf_next(arelf);

		/* Get member filename */
		if ((arname = ar_member_name(name, arelf, ofl)) == NULL)
			return (FALSE);

		/*
		 * Skip the symbol table, string table, or any other special
		 * archive member. These all start with a '/' character.
		 */
		if (*arname == '/') {
			(void) elf_end(arelf);
			continue;
		}

		/* Obtain archive member offset within the file */
		off = _elf_getarhdrbase(arelf);

		/*
		 * ld_sup_open() will reset the current iteration point for
		 * the archive to point at this member rather than the next
		 * one for the benefit of the support libraries. Since
		 * this loop relies on the current position not changing
		 * underneath it, we save and restore the current
		 * position around the support library call.
		 */
		next_off = _elf_getnextoff(adp->ad_elf);

		/* Construct the member's full pathname */
		if ((arpath = ar_member_path(name, arname)) == NULL)
			return (S_ERROR);

		/*
		 * Determine whether the support libraries wish to process
		 * this open. See comments in ld_process_open().
		 */
		ld_sup_open(ofl, &arpath, &arname, &fd,
		    (FLG_IF_EXTRACT | FLG_IF_NEEDED), &arelf, adp->ad_elf,
		    off, elf_kind(arelf));
		(void) elf_rand(adp->ad_elf, next_off);
		if (arelf == NULL)
			continue;

		DBG_CALL(Dbg_syms_ar_force(ofl->ofl_lml, name, arname));
		switch (ar_input(fd, adp, ofl, arelf, arpath, rej)) {
		case S_ERROR:
			return (FALSE);
		case 0:
			continue;
		}

		*found = TRUE;

	}

	/*
	 * As this archive was extracted by -z allextract, the ar_aux table
	 * and elf descriptor can be freed.  Set ad_elf to NULL to mark the
	 * archive is completely processed.
	 */
	(void) elf_end(adp->ad_elf);
	adp->ad_elf = NULL;

	return (TRUE);
}
コード例 #20
0
ファイル: setup.c プロジェクト: AlfredArouna/illumos-gate
Rt_map *
setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz,
    char *_rtldname, ulong_t ld_base, ulong_t interp_base, int fd, Phdr *phdr,
    char *execname, char **argv, uid_t uid, uid_t euid, gid_t gid, gid_t egid,
    void *aoutdyn, int auxflags, uint_t *hwcap)
{
	Rt_map			*rlmp, *mlmp, *clmp, **tobj = NULL;
	Ehdr			*ehdr;
	rtld_stat_t		status;
	int			features = 0, ldsoexec = 0;
	size_t			eaddr, esize;
	char			*str, *argvname;
	Word			lmflags;
	mmapobj_result_t	*mpp;
	Fdesc			fdr = { 0 }, fdm = { 0 };
	Rej_desc		rej = { 0 };
	APlist			*ealp = NULL;

	/*
	 * Now that ld.so has relocated itself, initialize our own 'environ' so
	 * as to establish an address suitable for any libc requirements.
	 */
	_environ = (char **)((ulong_t)auxv - sizeof (char *));
	_init();
	_environ = envp;

	/*
	 * Establish a base time.  Total time diagnostics start from entering
	 * ld.so.1 here, however the base time is reset each time the ld.so.1
	 * is re-entered.  Note also, there will be a large time associated
	 * with the first diagnostic from ld.so.1, as bootstrapping ld.so.1
	 * and establishing the liblddbg infrastructure takes some time.
	 */
	(void) gettimeofday(&DBG_TOTALTIME, NULL);
	DBG_DELTATIME = DBG_TOTALTIME;

	/*
	 * Determine how ld.so.1 has been executed.
	 */
	if ((fd == -1) && (phdr == NULL)) {
		/*
		 * If we received neither the AT_EXECFD nor the AT_PHDR aux
		 * vector, ld.so.1 must have been invoked directly from the
		 * command line.
		 */
		ldsoexec = 1;

		/*
		 * AT_SUN_EXECNAME provides the most precise name, if it is
		 * available, otherwise fall back to argv[0].  At this time,
		 * there is no process name.
		 */
		if (execname)
			rtldname = execname;
		else if (argv[0])
			rtldname = argv[0];
		else
			rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN);
	} else {
		/*
		 * Otherwise, we have a standard process.  AT_SUN_EXECNAME
		 * provides the most precise name, if it is available,
		 * otherwise fall back to argv[0].  Provided the application
		 * is already mapped, the process is the application, so
		 * simplify the application name for use in any diagnostics.
		 */
		if (execname)
			argvname = execname;
		else if (argv[0])
			argvname = execname = argv[0];
		else
			argvname = execname = (char *)MSG_INTL(MSG_STR_UNKNOWN);

		if (fd == -1) {
			if ((str = strrchr(argvname, '/')) != NULL)
				procname = ++str;
			else
				procname = argvname;
		}

		/*
		 * At this point, we don't know the runtime linkers full path
		 * name.  The _rtldname passed to us is the SONAME of the
		 * runtime linker, which is typically /lib/ld.so.1 no matter
		 * what the full path is.   Use this for now, we'll reset the
		 * runtime linkers name once the application is analyzed.
		 */
		if (_rtldname) {
			if ((str = strrchr(_rtldname, '/')) != NULL)
				rtldname = ++str;
			else
				rtldname = _rtldname;
		} else
			rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN);

		/* exec() brought in two objects for us. Count the second one */
		cnt_map++;
	}

	/*
	 * Initialize any global variables.
	 */
	at_flags = _flags;

	if ((org_scapset->sc_plat = _platform) != NULL)
		org_scapset->sc_platsz = strlen(_platform);

	if (org_scapset->sc_plat == NULL)
		platform_name(org_scapset);
	if (org_scapset->sc_mach == NULL)
		machine_name(org_scapset);

	/*
	 * If pagesize is unspecified find its value.
	 */
	if ((syspagsz = _syspagsz) == 0)
		syspagsz = _sysconfig(_CONFIG_PAGESIZE);

	/*
	 * Add the unused portion of the last data page to the free space list.
	 * The page size must be set before doing this.  Here, _end refers to
	 * the end of the runtime linkers bss.  Note that we do not use the
	 * unused data pages from any included .so's to supplement this free
	 * space as badly behaved .os's may corrupt this data space, and in so
	 * doing ruin our data.
	 */
	eaddr = S_DROUND((size_t)&_end);
	esize = eaddr % syspagsz;
	if (esize) {
		esize = syspagsz - esize;
		addfree((void *)eaddr, esize);
	}

	/*
	 * Establish initial link-map list flags, and link-map list alists.
	 */
	if (alist_append(&lml_main.lm_lists, NULL, sizeof (Lm_cntl),
	    AL_CNT_LMLISTS) == NULL)
		return (0);
	lml_main.lm_flags |= LML_FLG_BASELM;
	lml_main.lm_lmid = LM_ID_BASE;
	lml_main.lm_lmidstr = (char *)MSG_ORIG(MSG_LMID_BASE);

	if (alist_append(&lml_rtld.lm_lists, NULL, sizeof (Lm_cntl),
	    AL_CNT_LMLISTS) == NULL)
		return (0);
	lml_rtld.lm_flags |= (LML_FLG_RTLDLM | LML_FLG_HOLDLOCK);
	lml_rtld.lm_tflags |= LML_TFLG_NOAUDIT;
	lml_rtld.lm_lmid = LM_ID_LDSO;
	lml_rtld.lm_lmidstr = (char *)MSG_ORIG(MSG_LMID_LDSO);

	/*
	 * Determine whether we have a secure executable.
	 */
	security(uid, euid, gid, egid, auxflags);

	/*
	 * Make an initial pass of environment variables to pick off those
	 * related to locale processing.  At the same time, collect and save
	 * any LD_XXXX variables for later processing.  Note that this later
	 * processing will be skipped if ld.so.1 is invoked from the command
	 * line with -e LD_NOENVIRON.
	 */
	if (envp && (readenv_user((const char **)envp, &ealp) == 1))
		return (0);

	/*
	 * If ld.so.1 has been invoked directly, process its arguments.
	 */
	if (ldsoexec) {
		/*
		 * Process any arguments that are specific to ld.so.1, and
		 * reorganize the process stack to effectively remove ld.so.1
		 * from the stack.  Reinitialize the environment pointer, as
		 * this pointer may have been shifted after skipping ld.so.1's
		 * arguments.
		 */
		if (rtld_getopt(argv, &envp, &auxv, &(lml_main.lm_flags),
		    &(lml_main.lm_tflags), (aoutdyn != 0)) == 1) {
			eprintf(&lml_main, ERR_NONE, MSG_INTL(MSG_USG_BADOPT));
			return (0);
		}
		_environ = envp;

		/*
		 * Open the object that ld.so.1 is to execute.
		 */
		argvname = execname = argv[0];

		if ((fd = open(argvname, O_RDONLY)) == -1) {
			int	err = errno;
			eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
			    argvname, strerror(err));
			return (0);
		}
	}

	/*
	 * Having processed any ld.so.1 command line options, return to process
	 * any LD_XXXX environment variables.
	 */
	if (ealp) {
		if (((rtld_flags & RT_FL_NOENVIRON) == 0) &&
		    (procenv_user(ealp, &(lml_main.lm_flags),
		    &(lml_main.lm_tflags), (aoutdyn != 0)) == 1))
			return (0);
		free(ealp);
	}

	/*
	 * Initialize a hardware capability descriptor for use in comparing
	 * each loaded object.  The aux vector must provide AF_SUN_HWCAPVERIFY,
	 * as prior to this setting any hardware capabilities that were found
	 * could not be relied upon.
	 */
	if (auxflags & AF_SUN_HWCAPVERIFY) {
		rtld_flags2 |= RT_FL2_HWCAP;
		org_scapset->sc_hw_1 = (Xword)hwcap[0];
		org_scapset->sc_hw_2 = (Xword)hwcap[1];
	}

	/*
	 * Create a mapping descriptor for ld.so.1.  We can determine our
	 * two segments information from known symbols.
	 */
	if ((mpp = calloc(2, sizeof (mmapobj_result_t))) == NULL)
		return (0);
	mpp[0].mr_addr = (caddr_t)M_PTRUNC(ld_base);
	mpp[0].mr_msize = (caddr_t)&_etext - mpp[0].mr_addr;
	mpp[0].mr_fsize = mpp[0].mr_msize;
	mpp[0].mr_prot = (PROT_READ | PROT_EXEC);

	mpp[1].mr_addr = (caddr_t)M_PTRUNC((uintptr_t)&r_debug);
	mpp[1].mr_msize = (caddr_t)&_end - mpp[1].mr_addr;
	mpp[1].mr_fsize = (caddr_t)&_edata - mpp[1].mr_addr;
	mpp[1].mr_prot = (PROT_READ | PROT_WRITE | PROT_EXEC);

	if ((fdr.fd_nname = stravl_insert(_rtldname, 0, 0, 0)) == NULL)
		return (0);
	if ((rlmp = elf_new_lmp(&lml_rtld, ALIST_OFF_DATA, &fdr,
	    (Addr)mpp->mr_addr, (size_t)((uintptr_t)eaddr - (uintptr_t)ld_base),
	    NULL, NULL, NULL)) == NULL)
		return (0);

	MMAPS(rlmp) = mpp;
	MMAPCNT(rlmp) = 2;
	PADSTART(rlmp) = (ulong_t)mpp[0].mr_addr;
	PADIMLEN(rlmp) = (ulong_t)mpp[0].mr_addr + (ulong_t)mpp[1].mr_addr +
	    (ulong_t)mpp[1].mr_msize;

	MODE(rlmp) |= (RTLD_LAZY | RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD);
	FLAGS(rlmp) |= (FLG_RT_ANALYZED | FLG_RT_RELOCED | FLG_RT_INITDONE |
	    FLG_RT_INITCLCT | FLG_RT_FINICLCT | FLG_RT_MODESET);

	/*
	 * Initialize the runtime linkers information.
	 */
	interp = &_interp;
	interp->i_name = (char *)rtldname;
	interp->i_faddr = (caddr_t)ADDR(rlmp);
	ldso_plt_init(rlmp);

	/*
	 * Map in the file, if exec has not already done so, or if the file
	 * was passed as an argument to an explicit execution of ld.so.1 from
	 * the command line.
	 */
	if (fd != -1) {
		/*
		 * Map the file.  Once the object is mapped we no longer need
		 * the file descriptor.
		 */
		(void) rtld_fstat(fd, &status);
		fdm.fd_oname = argvname;
		fdm.fd_ftp = map_obj(&lml_main, &fdm, status.st_size, argvname,
		    fd, &rej);
		(void) close(fd);

		if (fdm.fd_ftp == NULL) {
			Conv_reject_desc_buf_t rej_buf;

			eprintf(&lml_main, ERR_FATAL,
			    MSG_INTL(err_reject[rej.rej_type]), argvname,
			    conv_reject_desc(&rej, &rej_buf, M_MACH));
			return (0);
		}

		/*
		 * Finish processing the loading of the file.
		 */
		if ((fdm.fd_nname = stravl_insert(argvname, 0, 0, 0)) == NULL)
			return (0);
		fdm.fd_dev = status.st_dev;
		fdm.fd_ino = status.st_ino;

		if ((mlmp = load_file(&lml_main, ALIST_OFF_DATA, NULL, &fdm,
		    NULL)) == NULL)
			return (0);

		/*
		 * We now have a process name for error diagnostics.
		 */
		if ((str = strrchr(argvname, '/')) != NULL)
			procname = ++str;
		else
			procname = argvname;

		if (ldsoexec) {
			mmapobj_result_t	*mpp = MMAPS(mlmp);
			uint_t			mnum, mapnum = MMAPCNT(mlmp);
			void			*brkbase = NULL;

			/*
			 * Since ld.so.1 was the primary executed object - the
			 * brk() base has not yet been initialized, we need to
			 * initialize it.  For an executable, initialize it to
			 * the end of the object.  For a shared object (ET_DYN)
			 * initialize it to the first page in memory.
			 */
			for (mnum = 0; mnum < mapnum; mnum++, mpp++)
				brkbase = mpp->mr_addr + mpp->mr_msize;

			if (brkbase == NULL)
				brkbase = (void *)syspagsz;

			if (_brk_unlocked(brkbase) == -1) {
				int	err = errno;

				eprintf(&lml_main, ERR_FATAL,
				    MSG_INTL(MSG_SYS_BRK), argvname,
				    strerror(err));
				return (0);
			}
		}
	} else {
		/*
		 * Set up function ptr and arguments according to the type
		 * of file class the executable is. (Currently only supported
		 * types are ELF and a.out format.)  Then create a link map
		 * for the executable.
		 */
		if (aoutdyn) {
#ifdef A_OUT
			mmapobj_result_t	*mpp;

			/*
			 * Create a mapping structure sufficient to describe
			 * a single two segments.  The ADDR() of the a.out is
			 * established as 0, which is required but the AOUT
			 * relocation code.
			 */
			if ((mpp =
			    calloc(sizeof (mmapobj_result_t), 2)) == NULL)
				return (0);

			if ((fdm.fd_nname =
			    stravl_insert(execname, 0, 0, 0)) == NULL)
				return (0);
			if ((mlmp = aout_new_lmp(&lml_main, ALIST_OFF_DATA,
			    &fdm, 0, 0, aoutdyn, NULL, NULL)) == NULL)
				return (0);

			/*
			 * Establish the true mapping information for the a.out.
			 */
			if (aout_get_mmap(&lml_main, mpp)) {
				free(mpp);
				return (0);
			}

			MSIZE(mlmp) =
			    (size_t)(mpp[1].mr_addr + mpp[1].mr_msize) -
			    S_ALIGN((size_t)mpp[0].mr_addr, syspagsz);
			MMAPS(mlmp) = mpp;
			MMAPCNT(mlmp) = 2;
			PADSTART(mlmp) = (ulong_t)mpp->mr_addr;
			PADIMLEN(mlmp) = mpp->mr_msize;

			/*
			 * Disable any object configuration cache (BCP apps
			 * bring in sbcp which can benefit from any object
			 * cache, but both the app and sbcp can't use the same
			 * objects).
			 */
			rtld_flags |= RT_FL_NOOBJALT;

			/*
			 * Make sure no-direct bindings are in effect.
			 */
			lml_main.lm_tflags |= LML_TFLG_NODIRECT;
#else
			eprintf(&lml_main, ERR_FATAL,
			    MSG_INTL(MSG_ERR_REJ_UNKFILE), argvname);
			return (0);
#endif
		} else if (phdr) {
			Phdr			*pptr;
			Off			i_offset = 0;
			Addr			base = 0;
			ulong_t			phsize;
			mmapobj_result_t	*mpp, *fmpp, *hmpp = NULL;
			uint_t			mapnum = 0;
			int			i;
			size_t			msize;

			/*
			 * Using the executables phdr address determine the base
			 * address of the input file.  NOTE, this assumes the
			 * program headers and elf header are part of the same
			 * mapped segment.  Although this has held for many
			 * years now, it might be more flexible if the kernel
			 * gave use the ELF headers start address, rather than
			 * the Program headers.
			 *
			 * Determine from the ELF header if we're been called
			 * from a shared object or dynamic executable.  If the
			 * latter, then any addresses within the object are used
			 * as is.  Addresses within shared objects must be added
			 * to the process's base address.
			 */
			ehdr = (Ehdr *)((Addr)phdr - phdr->p_offset);
			phsize = ehdr->e_phentsize;
			if (ehdr->e_type == ET_DYN)
				base = (Addr)ehdr;

			/*
			 * Allocate a mapping array to retain mapped segment
			 * information.
			 */
			if ((fmpp = mpp = calloc(ehdr->e_phnum,
			    sizeof (mmapobj_result_t))) == NULL)
				return (0);

			/*
			 * Extract the needed information from the segment
			 * headers.
			 */
			for (i = 0, pptr = phdr; i < ehdr->e_phnum; i++) {
				if (pptr->p_type == PT_INTERP) {
					i_offset = pptr->p_offset;
					interp->i_faddr =
					    (caddr_t)interp_base;
				}
				if ((pptr->p_type == PT_LOAD) &&
				    (pptr->p_filesz || pptr->p_memsz)) {
					int	perm = (PROT_READ | PROT_EXEC);
					size_t	off;

					if (i_offset && pptr->p_filesz &&
					    (i_offset >= pptr->p_offset) &&
					    (i_offset <=
					    (pptr->p_memsz + pptr->p_offset))) {
						interp->i_name = (char *)
						    pptr->p_vaddr + i_offset -
						    pptr->p_offset + base;
						i_offset = 0;
					}

					if (pptr->p_flags & PF_W)
						perm |= PROT_WRITE;

					/*
					 * Retain segments mapping info.  Round
					 * each segment to a page boundary, as
					 * this insures addresses are suitable
					 * for mprotect() if required.
					 */
					off = pptr->p_vaddr + base;
					if (hmpp == NULL) {
						hmpp = mpp;
						mpp->mr_addr = (caddr_t)ehdr;
					} else
						mpp->mr_addr = (caddr_t)off;

					off -= (size_t)(uintptr_t)mpp->mr_addr;
					mpp->mr_msize = pptr->p_memsz + off;
					mpp->mr_fsize = pptr->p_filesz + off;
					mpp->mr_prot = perm;

					mpp++, mapnum++;
				}

				pptr = (Phdr *)((ulong_t)pptr + phsize);
			}

			mpp--;
			msize = (size_t)(mpp->mr_addr + mpp->mr_msize) -
			    S_ALIGN((size_t)fmpp->mr_addr, syspagsz);

			if ((fdm.fd_nname =
			    stravl_insert(execname, 0, 0, 0)) == NULL)
				return (0);
			if ((mlmp = elf_new_lmp(&lml_main, ALIST_OFF_DATA,
			    &fdm, (Addr)hmpp->mr_addr, msize,
			    NULL, NULL, NULL)) == NULL)
				return (0);

			MMAPS(mlmp) = fmpp;
			MMAPCNT(mlmp) = mapnum;
			PADSTART(mlmp) = (ulong_t)fmpp->mr_addr;
			PADIMLEN(mlmp) = (ulong_t)fmpp->mr_addr +
			    (ulong_t)mpp->mr_addr + (ulong_t)mpp->mr_msize;
		}
	}

	/*
	 * Establish the interpretors name as that defined within the initial
	 * object (executable).  This provides for ORIGIN processing of ld.so.1
	 * dependencies.  Note, the NAME() of the object remains that which was
	 * passed to us as the SONAME on execution.
	 */
	if (ldsoexec == 0) {
		size_t	len = strlen(interp->i_name);

		if (expand(&interp->i_name, &len, 0, 0,
		    (PD_TKN_ISALIST | PD_TKN_CAP), rlmp) & PD_TKN_RESOLVED)
			fdr.fd_flags |= FLG_FD_RESOLVED;
	}
	fdr.fd_pname = interp->i_name;
	(void) fullpath(rlmp, &fdr);

	/*
	 * The runtime linker acts as a filtee for various dl*() functions that
	 * are defined in libc (and libdl).  Make sure this standard name for
	 * the runtime linker is also registered in the FullPathNode AVL tree.
	 */
	(void) fpavl_insert(&lml_rtld, rlmp, _rtldname, 0);

	/*
	 * Having established the true runtime linkers name, simplify the name
	 * for error diagnostics.
	 */
	if ((str = strrchr(PATHNAME(rlmp), '/')) != NULL)
		rtldname = ++str;
	else
		rtldname = PATHNAME(rlmp);

	/*
	 * Expand the fullpath name of the application.  This typically occurs
	 * as a part of loading an object, but as the kernel probably mapped
	 * it in, complete this processing now.
	 */
	(void) fullpath(mlmp, 0);

	/*
	 * Some troublesome programs will change the value of argv[0].  Dupping
	 * the process string protects us, and insures the string is left in
	 * any core files.
	 */
	if ((str = (char *)strdup(procname)) == NULL)
		return (0);
	procname = str;

	FLAGS(mlmp) |= (FLG_RT_ISMAIN | FLG_RT_MODESET);
	FLAGS1(mlmp) |= FL1_RT_USED;

	/*
	 * It's the responsibility of MAIN(crt0) to call it's _init and _fini
	 * section, therefore null out any INIT/FINI so that this object isn't
	 * collected during tsort processing.  And, if the application has no
	 * initarray or finiarray we can economize on establishing bindings.
	 */
	INIT(mlmp) = FINI(mlmp) = NULL;
	if ((INITARRAY(mlmp) == NULL) && (FINIARRAY(mlmp) == NULL))
		FLAGS1(mlmp) |= FL1_RT_NOINIFIN;

	/*
	 * Identify lddstub if necessary.
	 */
	if (lml_main.lm_flags & LML_FLG_TRC_LDDSTUB)
		FLAGS1(mlmp) |= FL1_RT_LDDSTUB;

	/*
	 * Retain our argument information for use in dlinfo.
	 */
	argsinfo.dla_argv = argv--;
	argsinfo.dla_argc = (long)*argv;
	argsinfo.dla_envp = envp;
	argsinfo.dla_auxv = auxv;

	(void) enter(0);

	/*
	 * Add our two main link-maps to the dynlm_list
	 */
	if (aplist_append(&dynlm_list, &lml_main, AL_CNT_DYNLIST) == NULL)
		return (0);

	if (aplist_append(&dynlm_list, &lml_rtld, AL_CNT_DYNLIST) == NULL)
		return (0);

	/*
	 * Reset the link-map counts for both lists.  The init count is used to
	 * track how many objects have pending init sections, this gets incre-
	 * mented each time an object is relocated.  Since ld.so.1 relocates
	 * itself, it's init count will remain zero.
	 * The object count is used to track how many objects have pending fini
	 * sections, as ld.so.1 handles its own fini we can zero its count.
	 */
	lml_main.lm_obj = 1;
	lml_rtld.lm_obj = 0;

	/*
	 * Initialize debugger information structure.  Some parts of this
	 * structure were initialized statically.
	 */
	r_debug.rtd_rdebug.r_map = (Link_map *)lml_main.lm_head;
	r_debug.rtd_rdebug.r_ldsomap = (Link_map *)lml_rtld.lm_head;
	r_debug.rtd_rdebug.r_ldbase = r_debug.rtd_rdebug.r_ldsomap->l_addr;
	r_debug.rtd_dynlmlst = &dynlm_list;

	/*
	 * Determine the dev/inode information for the executable to complete
	 * load_so() checking for those who might dlopen(a.out).
	 */
	if (rtld_stat(PATHNAME(mlmp), &status) == 0) {
		STDEV(mlmp) = status.st_dev;
		STINO(mlmp) = status.st_ino;
	}

	/*
	 * Initialize any configuration information.
	 */
	if (!(rtld_flags & RT_FL_NOCFG)) {
		if ((features = elf_config(mlmp, (aoutdyn != 0))) == -1)
			return (0);
	}

#if	defined(_ELF64)
	/*
	 * If this is a 64-bit process, determine whether this process has
	 * restricted the process address space to 32-bits.  Any dependencies
	 * that are restricted to a 32-bit address space can only be loaded if
	 * the executable has established this requirement.
	 */
	if (CAPSET(mlmp).sc_sf_1 & SF1_SUNW_ADDR32)
		rtld_flags2 |= RT_FL2_ADDR32;
#endif
	/*
	 * Establish any alternative capabilities, and validate this object
	 * if it defines it's own capabilities information.
	 */
	if (cap_alternative() == 0)
		return (0);

	if (cap_check_lmp(mlmp, &rej) == 0) {
		if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) {
			/* LINTED */
			(void) printf(MSG_INTL(ldd_warn[rej.rej_type]),
			    NAME(mlmp), rej.rej_str);
		} else {
			/* LINTED */
			eprintf(&lml_main, ERR_FATAL,
			    MSG_INTL(err_reject[rej.rej_type]),
			    NAME(mlmp), rej.rej_str);
			return (0);
		}
	}

	/*
	 * Establish the modes of the initial object.  These modes are
	 * propagated to any preloaded objects and explicit shared library
	 * dependencies.
	 *
	 * If we're generating a configuration file using crle(1), remove
	 * any RTLD_NOW use, as we don't want to trigger any relocation proc-
	 * essing during crle(1)'s first past (this would just be unnecessary
	 * overhead).  Any filters are explicitly loaded, and thus RTLD_NOW is
	 * not required to trigger filter loading.
	 *
	 * Note, RTLD_NOW may have been established during analysis of the
	 * application had the application been built -z now.
	 */
	MODE(mlmp) |= (RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD);

	if (rtld_flags & RT_FL_CONFGEN) {
		MODE(mlmp) |= RTLD_CONFGEN;
		MODE(mlmp) &= ~RTLD_NOW;
		rtld_flags2 &= ~RT_FL2_BINDNOW;
	}

	if ((MODE(mlmp) & RTLD_NOW) == 0) {
		if (rtld_flags2 & RT_FL2_BINDNOW)
			MODE(mlmp) |= RTLD_NOW;
		else
			MODE(mlmp) |= RTLD_LAZY;
	}

	/*
	 * If debugging was requested initialize things now that any cache has
	 * been established.  A user can specify LD_DEBUG=help to discover the
	 * list of debugging tokens available without running the application.
	 * However, don't allow this setting from a configuration file.
	 *
	 * Note, to prevent recursion issues caused by loading and binding the
	 * debugging libraries themselves, a local debugging descriptor is
	 * initialized.  Once the debugging setup has completed, this local
	 * descriptor is copied to the global descriptor which effectively
	 * enables diagnostic output.
	 *
	 * Ignore any debugging request if we're being monitored by a process
	 * that expects the old getpid() initialization handshake.
	 */
	if ((rpl_debug || prm_debug) && ((rtld_flags & RT_FL_DEBUGGER) == 0)) {
		Dbg_desc	_dbg_desc = {0};
		struct timeval	total = DBG_TOTALTIME;
		struct timeval	delta = DBG_DELTATIME;

		if (rpl_debug) {
			if (dbg_setup(rpl_debug, &_dbg_desc) == 0)
				return (0);
			if (_dbg_desc.d_extra & DBG_E_HELP_EXIT)
				rtldexit(&lml_main, 0);
		}
		if (prm_debug)
			(void) dbg_setup(prm_debug, &_dbg_desc);

		*dbg_desc = _dbg_desc;
		DBG_TOTALTIME = total;
		DBG_DELTATIME = delta;
	}

	/*
	 * Now that debugging is enabled generate any diagnostics from any
	 * previous events.
	 */
	if (DBG_ENABLED) {
		DBG_CALL(Dbg_cap_val(&lml_main, org_scapset, alt_scapset,
		    M_MACH));
		DBG_CALL(Dbg_file_config_dis(&lml_main, config->c_name,
		    features));

		DBG_CALL(Dbg_file_ldso(rlmp, envp, auxv,
		    LIST(rlmp)->lm_lmidstr, ALIST_OFF_DATA));

		if (THIS_IS_ELF(mlmp)) {
			DBG_CALL(Dbg_file_elf(&lml_main, PATHNAME(mlmp),
			    ADDR(mlmp), MSIZE(mlmp), LIST(mlmp)->lm_lmidstr,
			    ALIST_OFF_DATA));
		} else {
			DBG_CALL(Dbg_file_aout(&lml_main, PATHNAME(mlmp),
			    ADDR(mlmp), MSIZE(mlmp), LIST(mlmp)->lm_lmidstr,
			    ALIST_OFF_DATA));
		}
	}

	/*
	 * Enable auditing.
	 */
	if (rpl_audit || prm_audit || profile_lib) {
		int		ndx;
		const char	*aud[3];

		aud[0] = rpl_audit;
		aud[1] = prm_audit;
		aud[2] = profile_lib;

		/*
		 * Any global auditing (set using LD_AUDIT or LD_PROFILE) that
		 * can't be established is non-fatal.
		 */
		if ((auditors = calloc(1, sizeof (Audit_desc))) == NULL)
			return (0);

		for (ndx = 0; ndx < 3; ndx++) {
			if (aud[ndx]) {
				if ((auditors->ad_name =
				    strdup(aud[ndx])) == NULL)
					return (0);
				rtld_flags2 |= RT_FL2_FTL2WARN;
				(void) audit_setup(mlmp, auditors,
				    PD_FLG_EXTLOAD, NULL);
				rtld_flags2 &= ~RT_FL2_FTL2WARN;
			}
		}
		lml_main.lm_tflags |= auditors->ad_flags;
	}
	if (AUDITORS(mlmp)) {
		/*
		 * Any object required auditing (set with a DT_DEPAUDIT dynamic
		 * entry) that can't be established is fatal.
		 */
		if (FLAGS1(mlmp) & FL1_RT_GLOBAUD) {
			/*
			 * If this object requires global auditing, use the
			 * local auditing information to set the global
			 * auditing descriptor.  The effect is that a
			 * DT_DEPAUDIT act as an LD_AUDIT.
			 */
			if ((auditors == NULL) && ((auditors = calloc(1,
			    sizeof (Audit_desc))) == NULL))
				return (0);

			auditors->ad_name = AUDITORS(mlmp)->ad_name;
			if (audit_setup(mlmp, auditors, 0, NULL) == 0)
				return (0);
			lml_main.lm_tflags |= auditors->ad_flags;

			/*
			 * Clear the local auditor information.
			 */
			free((void *) AUDITORS(mlmp));
			AUDITORS(mlmp) = NULL;

		} else {
			/*
			 * Establish any local auditing.
			 */
			if (audit_setup(mlmp, AUDITORS(mlmp), 0, NULL) == 0)
				return (0);

			AFLAGS(mlmp) |= AUDITORS(mlmp)->ad_flags;
			lml_main.lm_flags |= LML_FLG_LOCAUDIT;
		}
	}

	/*
	 * Explicitly add the initial object and ld.so.1 to those objects being
	 * audited.  Note, although the ld.so.1 link-map isn't auditable,
	 * establish a cookie for ld.so.1 as this may be bound to via the
	 * dl*() family.
	 */
	if ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_MASK) {
		if (((audit_objopen(mlmp, mlmp) == 0) ||
		    (audit_objopen(mlmp, rlmp) == 0)) &&
		    (AFLAGS(mlmp) & LML_TFLG_AUD_MASK))
			return (0);
	}

	/*
	 * Map in any preloadable shared objects.  Establish the caller as the
	 * head of the main link-map list.  In the case of being exercised from
	 * lddstub, the caller gets reassigned to the first target shared object
	 * so as to provide intuitive diagnostics from ldd().
	 *
	 * Note, it is valid to preload a 4.x shared object with a 5.0
	 * executable (or visa-versa), as this functionality is required by
	 * ldd(1).
	 */
	clmp = mlmp;
	if (rpl_preload && (preload(rpl_preload, mlmp, &clmp) == 0))
		return (0);
	if (prm_preload && (preload(prm_preload, mlmp, &clmp) == 0))
		return (0);

	/*
	 * Load all dependent (needed) objects.
	 */
	if (analyze_lmc(&lml_main, ALIST_OFF_DATA, mlmp, mlmp, NULL) == NULL)
		return (0);

	/*
	 * Relocate all the dependencies we've just added.
	 *
	 * If this process has been established via crle(1), the environment
	 * variable LD_CONFGEN will have been set.  crle(1) may create this
	 * process twice.  The first time crle only needs to gather dependency
	 * information.  The second time, is to dldump() the images.
	 *
	 * If we're only gathering dependencies, relocation is unnecessary.
	 * As crle(1) may be building an arbitrary family of objects, they may
	 * not fully relocate either.  Hence the relocation phase is not carried
	 * out now, but will be called by crle(1) once all objects have been
	 * loaded.
	 */
	if ((rtld_flags & RT_FL_CONFGEN) == 0) {

		DBG_CALL(Dbg_util_nl(&lml_main, DBG_NL_STD));

		if (relocate_lmc(&lml_main, ALIST_OFF_DATA, mlmp,
		    mlmp, NULL) == 0)
			return (0);

		/*
		 * Inform the debuggers that basic process initialization is
		 * complete, and that the state of ld.so.1 (link-map lists,
		 * etc.) is stable.  This handshake enables the debugger to
		 * initialize themselves, and consequently allows the user to
		 * set break points in .init code.
		 *
		 * Most new debuggers use librtld_db to monitor activity events.
		 * Older debuggers indicated their presence by setting the
		 * DT_DEBUG entry in the dynamic executable (see elf_new_lm()).
		 * In this case, getpid() is called so that the debugger can
		 * catch the system call.  This old mechanism has some
		 * restrictions, as getpid() should not be called prior to
		 * basic process initialization being completed.  This
		 * restriction has become increasingly difficult to maintain,
		 * as the use of auditors, LD_DEBUG, and the initialization
		 * handshake with libc can result in "premature" getpid()
		 * calls.  The use of this getpid() handshake is expected to
		 * disappear at some point in the future, and there is intent
		 * to work towards that goal.
		 */
		rd_event(&lml_main, RD_DLACTIVITY, RT_CONSISTENT);
		rd_event(&lml_rtld, RD_DLACTIVITY, RT_CONSISTENT);

		if (rtld_flags & RT_FL_DEBUGGER) {
			r_debug.rtd_rdebug.r_flags |= RD_FL_ODBG;
			(void) getpid();
		}
	}

	/*
	 * Indicate preinit activity, and call any auditing routines.  These
	 * routines are called before initializing any threads via libc, or
	 * before collecting the complete set of .inits on the primary link-map.
	 * Although most libc interfaces are encapsulated in local routines
	 * within libc, they have been known to escape (ie. call a .plt).  As
	 * the appcert auditor uses preinit as a trigger to establish some
	 * external interfaces to the main link-maps libc, we need to activate
	 * this trigger before exercising any code within libc.  Additionally,
	 * I wouldn't put it past an auditor to add additional objects to the
	 * primary link-map.  Hence, we collect .inits after the audit call.
	 */
	rd_event(&lml_main, RD_PREINIT, 0);

	if (aud_activity ||
	    ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_ACTIVITY))
		audit_activity(mlmp, LA_ACT_CONSISTENT);
	if (aud_preinit ||
	    ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_PREINIT))
		audit_preinit(mlmp);

	/*
	 * If we're creating initial configuration information, we're done
	 * now that the auditing step has been called.
	 */
	if (rtld_flags & RT_FL_CONFGEN) {
		leave(LIST(mlmp), 0);
		return (mlmp);
	}

	/*
	 * Sort the .init sections of all objects we've added.  If we're
	 * tracing we only need to execute this under ldd(1) with the -i or -u
	 * options.
	 */
	lmflags = lml_main.lm_flags;
	if (((lmflags & LML_FLG_TRC_ENABLE) == 0) ||
	    (lmflags & (LML_FLG_TRC_INIT | LML_FLG_TRC_UNREF))) {
		if ((tobj = tsort(mlmp, LIST(mlmp)->lm_init,
		    RT_SORT_REV)) == (Rt_map **)S_ERROR)
			return (0);
	}

	/*
	 * If we are tracing we're done.  This is the one legitimate use of a
	 * direct call to rtldexit() rather than return, as we don't want to
	 * return and jump to the application.
	 */
	if (lmflags & LML_FLG_TRC_ENABLE) {
		unused(&lml_main);
		rtldexit(&lml_main, 0);
	}

	/*
	 * Check if this instance of the linker should have a primary link
	 * map.  This flag allows multiple copies of the -same- -version-
	 * of the linker (and libc) to run in the same address space.
	 *
	 * Without this flag we only support one copy of the linker in a
	 * process because by default the linker will always try to
	 * initialize at one primary link map  The copy of libc which is
	 * initialized on a primary link map will initialize global TLS
	 * data which can be shared with other copies of libc in the
	 * process.  The problem is that if there is more than one copy
	 * of the linker, only one copy should link libc onto a primary
	 * link map, otherwise libc will attempt to re-initialize global
	 * TLS data.  So when a copy of the linker is loaded with this
	 * flag set, it will not initialize any primary link maps since
	 * presumably another copy of the linker will do this.
	 *
	 * Note that this flag only allows multiple copies of the -same-
	 * -version- of the linker (and libc) to coexist.  This approach
	 * will not work if we are trying to load different versions of
	 * the linker and libc into the same process.  The reason for
	 * this is that the format of the global TLS data may not be
	 * the same for different versions of libc.  In this case each
	 * different version of libc must have it's own primary link map
	 * and be able to maintain it's own TLS data.  The only way this
	 * can be done is by carefully managing TLS pointers on transitions
	 * between code associated with each of the different linkers.
	 * Note that this is actually what is done for processes in lx
	 * branded zones.  Although in the lx branded zone case, the
	 * other linker and libc are actually gld and glibc.  But the
	 * same general TLS management mechanism used by the lx brand
	 * would apply to any attempts to run multiple versions of the
	 * solaris linker and libc in a single process.
	 */
	if (auxflags & AF_SUN_NOPLM)
		rtld_flags2 |= RT_FL2_NOPLM;

	/*
	 * Establish any static TLS for this primary link-map.  Note, regardless
	 * of whether TLS is available, an initial handshake occurs with libc to
	 * indicate we're processing the primary link-map.  Having identified
	 * the primary link-map, initialize threads.
	 */
	if (rt_get_extern(&lml_main, mlmp) == 0)
		return (0);

	if ((rtld_flags2 & RT_FL2_NOPLM) == 0) {
		if (tls_statmod(&lml_main, mlmp) == 0)
			return (0);
		rt_thr_init(&lml_main);
		rtld_flags2 |= RT_FL2_PLMSETUP;
	} else {
		rt_thr_init(&lml_main);
	}

	/*
	 * Fire all dependencies .init sections.  Identify any unused
	 * dependencies, and leave the runtime linker - effectively calling
	 * the dynamic executables entry point.
	 */
	call_array(PREINITARRAY(mlmp), (uint_t)PREINITARRAYSZ(mlmp), mlmp,
	    SHT_PREINIT_ARRAY);

	if (tobj)
		call_init(tobj, DBG_INIT_SORT);

	rd_event(&lml_main, RD_POSTINIT, 0);

	unused(&lml_main);

	DBG_CALL(Dbg_util_call_main(mlmp));

	rtld_flags |= (RT_FL_OPERATION | RT_FL_APPLIC);

	leave(LIST(mlmp), 0);

	return (mlmp);
}
コード例 #21
0
ファイル: setup.c プロジェクト: AlfredArouna/illumos-gate
/*
 * LD_PRELOAD objects.
 */
static int
preload(const char *str, Rt_map *mlmp, Rt_map **clmp)
{
	Alist		*palp = NULL;
	char		*objs, *ptr, *next;
	Word		lmflags = lml_main.lm_flags;
	int		lddstub;

	DBG_CALL(Dbg_util_nl(&lml_main, DBG_NL_STD));

	if ((objs = strdup(str)) == NULL)
		return (0);

	/*
	 * Determine if we've been called from lddstub.
	 */
	lddstub = (lmflags & LML_FLG_TRC_ENABLE) &&
	    (FLAGS1(*clmp) & FL1_RT_LDDSTUB);


	for (ptr = strtok_r(objs, MSG_ORIG(MSG_STR_DELIMIT), &next);
	    ptr != NULL;
	    ptr = strtok_r(NULL, MSG_ORIG(MSG_STR_DELIMIT), &next)) {
		Rt_map	*nlmp = NULL;
		uint_t	flags;

		DBG_CALL(Dbg_file_preload(&lml_main, ptr));

		/*
		 * Establish the flags for loading each object.  If we're
		 * called via lddstub, then the first preloaded object is the
		 * object being inspected by ldd(1).  This object should not be
		 * marked as an interposer, as this object is intended to act
		 * as the target object of the process.
		 */
		if (lddstub)
			flags = FLG_RT_PRELOAD;
		else
			flags = (FLG_RT_PRELOAD | FLG_RT_OBJINTPO);

		/*
		 * If this a secure application, then preload errors are
		 * reduced to warnings, as the errors are non-fatal.
		 */
		if (rtld_flags & RT_FL_SECURE)
			rtld_flags2 |= RT_FL2_FTL2WARN;
		if (expand_paths(*clmp, ptr, &palp, AL_CNT_NEEDED,
		    PD_FLG_EXTLOAD, 0) != 0)
			nlmp = load_one(&lml_main, ALIST_OFF_DATA, palp, *clmp,
			    MODE(mlmp), flags, 0, NULL);
		remove_alist(&palp, 0);
		if (rtld_flags & RT_FL_SECURE)
			rtld_flags2 &= ~RT_FL2_FTL2WARN;
		if (nlmp && (bind_one(*clmp, nlmp, BND_NEEDED) == 0))
			nlmp = NULL;

		if (lddstub && nlmp) {
			lddstub = 0;

			/*
			 * Fabricate a binding between the target shared object
			 * and lddstub so that the target object isn't called
			 * out from unused() processing.
			 */
			if (lmflags &
			    (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED)) {
				if (bind_one(*clmp, nlmp, BND_REFER) == 0)
					nlmp = NULL;
			}

			/*
			 * By identifying lddstub as the caller, several
			 * confusing ldd() diagnostics get suppressed.  These
			 * diagnostics would reveal how the target shared object
			 * was found from lddstub.  Now that the real target is
			 * loaded, identify the target as the caller so that all
			 * ldd() diagnostics are enabled for subsequent objects.
			 */
			if (nlmp)
				*clmp = nlmp;
		}

		/*
		 * If no error occurred with loading this object, indicate that
		 * this link-map list contains an interposer.
		 */
		if (nlmp == NULL) {
			if ((lmflags & LML_FLG_TRC_ENABLE) ||
			    (rtld_flags & RT_FL_SECURE))
				continue;
			else
				return (0);
		}
		if (flags & FLG_RT_OBJINTPO)
			lml_main.lm_flags |= LML_FLG_INTRPOSE;

	}

	free(palp);
	free(objs);
	return (1);
}
コード例 #22
0
ファイル: tls.c プロジェクト: AlfredArouna/illumos-gate
/*
 * Track any static TLS use, retain the TLS header, and assign a TLS module
 * identifier.
 */
int
tls_assign(Lm_list *lml, Rt_map *lmp, Phdr *phdr)
{
	ulong_t	memsz = S_ROUND(phdr->p_memsz, M_TLSSTATALIGN);
	ulong_t	filesz = phdr->p_filesz;
	ulong_t	resv = tls_static_resv;

	/*
	 * If this object explicitly references static TLS, then there are some
	 * limitations.
	 */
	if (FLAGS1(lmp) & FL1_RT_TLSSTAT) {
		/*
		 * Static TLS is only available to objects on the primary
		 * link-map list.
		 */
		if (((lml->lm_flags & LML_FLG_BASELM) == 0) ||
		    ((rtld_flags2 & RT_FL2_NOPLM) != 0)) {
			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_STATBASE),
			    NAME(lmp));
			return (0);
		}

		/*
		 * All TLS blocks that are processed before thread
		 * initialization, are registered with libc.  This
		 * initialization is carried out through a handshake with libc
		 * prior to executing any user code (ie. before the first .init
		 * sections are called).  As part of this initialization, a
		 * small backup TLS reservation is added (tls_static_resv).
		 * Only explicit static TLS references that can be satisfied by
		 * this TLS backup reservation can be satisfied.
		 */
		if (rtld_flags2 & RT_FL2_PLMSETUP) {
			/*
			 * Initialized static TLS can not be satisfied from the
			 * TLS backup reservation.
			 */
			if (filesz) {
				eprintf(lml, ERR_FATAL,
				    MSG_INTL(MSG_TLS_STATINIT), NAME(lmp));
				return (0);
			}

			/*
			 * Make sure the backup reservation is sufficient.
			 */
			if (memsz > tls_static_resv) {
				eprintf(lml, ERR_FATAL,
				    MSG_INTL(MSG_TLS_STATSIZE), NAME(lmp),
				    EC_XWORD(memsz), EC_XWORD(tls_static_resv));
				return (0);
			}

			tls_static_resv -= memsz;
		}
	}

	/*
	 * If we haven't yet initialized threads, or this static reservation can
	 * be satisfied from the TLS backup reservation, determine the total
	 * static TLS size, and assign this object a static TLS offset.
	 */
	if (((rtld_flags2 & RT_FL2_PLMSETUP) == 0) ||
	    (FLAGS1(lmp) & FL1_RT_TLSSTAT)) {
		tls_static_size += memsz;
		TLSSTATOFF(lmp) = tls_static_size;
	}

	/*
	 * Retain the PT_TLS header, obtain a new module identifier, and
	 * indicate that this link-map list contains a new TLS object.
	 */
	PTTLS(lmp) = phdr;
	TLSMODID(lmp) = tls_getmodid();

	/*
	 * Now that we have a TLS module id, generate any static TLS reservation
	 * diagnostic.
	 */
	if (resv != tls_static_resv)
		DBG_CALL(Dbg_tls_static_resv(lmp, memsz, tls_static_resv));

	return (++lml->lm_tls);
}
コード例 #23
0
ファイル: audit.c プロジェクト: AlainODea/illumos-gate
/*
 * la_objopen() caller for the head link-map.  Global auditors, or an auditor
 * started from the object that heads a link-map list (typically the dynamic
 * executable), are passed to la_objopen().  However, local auditors can
 * provide activity and preinit events, and for these events, a cookie
 * representing the head link-map list object is expected.  This routine obtains
 * these cookies from the link-map list lm_cookies element.  This element
 * ensures all clients of the same auditor use the same cookie.
 *
 * Although a local auditor will get an la_objopen() call for the object that
 * heads the link-map list of the object being audited, the auditor is not
 * permitted to request binding information for this head object.  The head
 * object has already been in existence, and bindings may have been resolved
 * with it.  This local auditor is coming into existence too late, and thus we
 * don't allow any bindings to be caught at all.
 */
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;

		/*
		 * Ensure this local auditor isn't already in existence as an
		 * auditor for the head of the link-map list.  If it is, then
		 * this auditor will have already receive preinit and activity
		 * events.
		 */
		if (AUDITORS(hlmp) && _audit_used_by_head(hlmp, almp))
			continue;

		/*
		 * Create a cookie that represents the object that heads the
		 * link-map list.  If the cookie already exists, then this
		 * auditor has already been established for another objects
		 * local auditing.  In this case, do not issue a la_objopen()
		 * or la_activity() event, as these will have already occurred.
		 */
		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++;

		/*
		 * Call the la_objopen() if available.
		 */
		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));
			}
		}

		/*
		 * Call the la_activity() if available.
		 */
		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 new head link-map cookies have been generated, then maintain
	 * any preinit and/or activity requirements.
	 */
	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);
}
コード例 #24
0
ファイル: audit.c プロジェクト: andreiw/polaris
/*
 * Given a list of one or more audit libraries, open each one and establish a
 * a descriptor representing the entry points it provides.
 */
int
audit_setup(Rt_map *clmp, Audit_desc *adp, uint_t orig)
{
	char	*ptr, *next;
	Lm_list	*clml = LIST(clmp);
	int	error = 1;

	DBG_CALL(Dbg_audit_lib(clml, adp->ad_name));

	/*
	 * Mark that we have at least one auditing link map
	 */
	rtld_flags2 |= RT_FL2_HASAUDIT;

	/*
	 * The audit definitions may be a list (which will already have been
	 * dupped) so split it into individual tokens.
	 */
	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;
		Rt_map		**tobj;
		Audit_list	*alp;

		/*
		 * Open the audit library on its own link-map.
		 */
		if ((ghp = dlmopen_intn((Lm_list *)LM_ID_NEWLM, ptr,
		    (RTLD_FIRST | RTLD_GLOBAL | RTLD_WORLD), clmp,
		    FLG_RT_AUDIT, orig, 0)) == 0) {
			error = audit_disable(ptr, clmp, 0, 0);
			continue;
		}
		lmp = ghp->gh_ownlmp;

		/*
		 * If this auditor has already been loaded, reuse it.
		 */
		if ((alp = LIST(lmp)->lm_alp) != 0) {
			if (list_append(&(adp->ad_list), alp) == 0)
				return (audit_disable(ptr, clmp, ghp, alp));

			adp->ad_cnt++;
			DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
			    alp->al_vernum));
			adp->ad_flags |= alp->al_flags;
			continue;
		}

		/*
		 * If we are not running in the environment where
		 * libc/libthread are merged, we hold on to rtld lock
		 * upon leave() function.
		 *
		 * There is a possibility that libc is not mapped in yet.
		 * We may later find out that we will be running in
		 * libc/libthread merged enviornment. Refer to:
		 *	get_lcinterface() in mutex.c.
		 */
		if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0)
			LIST(lmp)->lm_flags |= LML_FLG_HOLDLOCK;

		/*
		 * Allocate an audit list descriptor for this object and
		 * search for all known entry points.
		 */
		if ((alp = calloc(1, sizeof (Audit_list))) == 0)
			return (audit_disable(ptr, clmp, ghp, 0));

		alp->al_libname = NAME(lmp);
		alp->al_lmp = lmp;
		alp->al_ghp = ghp;

		/*
		 * All audit libraries must handshake through la_version().
		 * Determine that the symbol exists, finish initializing the
		 * object, and then call the function.
		 */
		if ((alp->al_version =
		    (uint_t(*)())audit_symget(alp, AI_LAVERSION)) == 0) {
			eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM),
			    MSG_ORIG(MSG_SYM_LAVERSION));
			error = audit_disable(ptr, clmp, ghp, alp);
			continue;
		}

		if ((tobj = tsort(lmp, LIST(lmp)->lm_init, RT_SORT_REV)) ==
		    (Rt_map **)S_ERROR)
			return (audit_disable(ptr, clmp, ghp, alp));

		rtld_flags |= RT_FL_APPLIC;
		if (tobj != (Rt_map **)NULL)
			call_init(tobj, DBG_INIT_SORT);

		alp->al_vernum = alp->al_version(LAV_CURRENT);
		rtld_flags &= ~RT_FL_APPLIC;

		if ((alp->al_vernum < LAV_VERSION1) ||
		    (alp->al_vernum > LAV_CURRENT)) {
			eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS),
			    LAV_CURRENT, alp->al_vernum);
			error = audit_disable(ptr, clmp, ghp, alp);
			continue;
		}

		if (list_append(&(adp->ad_list), alp) == 0)
			return (audit_disable(ptr, clmp, ghp, alp));

		adp->ad_cnt++;
		DBG_CALL(Dbg_audit_version(clml, alp->al_libname,
		    alp->al_vernum));

		/*
		 * Collect any remaining entry points.
		 */
		alp->al_preinit =
		    (void(*)())audit_symget(alp, AI_LAPREINIT);
		alp->al_objsearch =
		    (char *(*)())audit_symget(alp, AI_LAOBJSEARCH);
		alp->al_objopen =
		    (uint_t(*)())audit_symget(alp, AI_LAOBJOPEN);
		alp->al_objfilter =
		    (int(*)())audit_symget(alp, AI_LAOBJFILTER);
		alp->al_objclose =
		    (uint_t(*)())audit_symget(alp, AI_LAOBJCLOSE);
		alp->al_activity =
		    (void (*)())audit_symget(alp, AI_LAACTIVITY);
		alp->al_symbind =
		    (uintptr_t(*)())audit_symget(alp, AI_LASYMBIND);
		alp->al_pltenter =
		    (uintptr_t(*)())audit_symget(alp, AI_LAPLTENTER);
		alp->al_pltexit =
		    (uintptr_t(*)())audit_symget(alp, AI_LAPLTEXIT);

		/*
		 * Collect the individual object flags, and assign this audit
		 * list descriptor to its associated link-map list.
		 */
		adp->ad_flags |= alp->al_flags;
		LIST(lmp)->lm_alp = alp;
	}

	/*
	 * Free the original audit string, as this descriptor may be used again
	 * to add additional auditing.
	 */
	free(adp->ad_name);
	adp->ad_name = 0;

	return (error);
}
コード例 #25
0
ファイル: i386_elf.c プロジェクト: carmark/illumos-gate
/*
 * For SVR4 Intel compatability.  USL uses /usr/lib/libc.so.1 as the run-time
 * linker, so the interpreter's address will differ from /usr/lib/ld.so.1.
 * Further, USL has special _iob[] and _ctype[] processing that makes up for the
 * fact that these arrays do not have associated copy relocations.  So we try
 * and make up for that here.  Any relocations found will be added to the global
 * copy relocation list and will be processed in setup().
 */
static int
_elf_copy_reloc(const char *name, Rt_map *rlmp, Rt_map *dlmp)
{
	Sym		*symref, *symdef;
	caddr_t 	ref, def;
	Rt_map		*_lmp;
	Rel		rel;
	Slookup		sl;
	Sresult		sr;
	uint_t		binfo;

	/*
	 * Determine if the special symbol exists as a reference in the dynamic
	 * executable, and that an associated definition exists in libc.so.1.
	 *
	 * Initialize the symbol lookup, and symbol result, data structures.
	 */
	SLOOKUP_INIT(sl, name, rlmp, rlmp, ld_entry_cnt, 0, 0, 0, 0,
	    LKUP_FIRST);
	SRESULT_INIT(sr, name);

	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0)
		return (1);
	symref = sr.sr_sym;

	SLOOKUP_INIT(sl, name, rlmp, dlmp, ld_entry_cnt, 0, 0, 0, 0,
	    LKUP_DEFT);
	SRESULT_INIT(sr, name);

	if (lookup_sym(&sl, &sr, &binfo, NULL) == 0)
		return (1);

	_lmp = sr.sr_dmap;
	symdef = sr.sr_sym;

	if (strcmp(NAME(sr.sr_dmap), MSG_ORIG(MSG_PTH_LIBC)))
		return (1);

	/*
	 * Determine the reference and definition addresses.
	 */
	ref = (void *)(symref->st_value);
	if (!(FLAGS(rlmp) & FLG_RT_FIXED))
		ref += ADDR(rlmp);
	def = (void *)(symdef->st_value);
	if (!(FLAGS(sr.sr_dmap) & FLG_RT_FIXED))
		def += ADDR(_lmp);

	/*
	 * Set up a relocation entry for debugging and call the generic copy
	 * relocation function to provide symbol size error checking and to
	 * record the copy relocation that must be performed.
	 */
	rel.r_offset = (Addr)ref;
	rel.r_info = (Word)R_386_COPY;
	DBG_CALL(Dbg_reloc_in(LIST(rlmp), ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE,
	    &rel, NULL, 0, name));

	return (elf_copy_reloc((char *)name, symref, rlmp, (void *)ref, symdef,
	    _lmp, (void *)def));
}
コード例 #26
0
ファイル: libs.c プロジェクト: metricinc/illumos-gate
/*
 * Read the archive symbol table.  For each symbol in the table, determine
 * whether that symbol satisfies an unresolved reference, tentative reference,
 * or a reference that expects hidden or protected visibility.  If so, the
 * corresponding object from the archive is processed.  The archive symbol
 * table is searched until we go through a complete pass without satisfying any
 * unresolved symbols
 *
 * entry:
 *	name - Name of archive
 *	fd - Open file descriptor for archive
 *	adp - Archive descriptor
 *	ofl - output descriptor
 *	found - Address of variable to set to TRUE if any objects are extracted
 *	rej - Rejection descriptor to pass to ld_process_ifl().
 *
 * exit:
 *	Returns FALSE on fatal error. On success, *found will be TRUE
 *	if any object was extracted, rej will be set if any object
 *	was rejected, and TRUE is returned.
 */
static Boolean
ar_extract_bysym(const char *name, int fd, Ar_desc *adp,
    Ofl_desc *ofl, Boolean *found, Rej_desc *rej)
{
	Elf_Arsym *	arsym;
	Elf *		arelf;
	Ar_aux *	aup;
	Sym_desc *	sdp;
	const char	*arname, *arpath;
	Boolean		again = FALSE;
	uintptr_t	err;

	/*
	 * An archive without a symbol table should not reach this function,
	 * because it can only get past ld_ar_setup() in the case where
	 * the archive is first seen under the influence of '-z allextract'.
	 * That will cause the entire archive to be extracted, and any
	 * subsequent reference to the archive will be ignored by
	 * ld_process_archive().
	 */
	if (adp->ad_start == NULL) {
		assert(adp->ad_start != NULL);
		return (TRUE);
	}

	/*
	 * Loop through archive symbol table until we make a complete pass
	 * without satisfying an unresolved reference.  For each archive
	 * symbol, see if there is a symbol with the same name in ld's
	 * symbol table.  If so, and if that symbol is still unresolved or
	 * tentative, process the corresponding archive member.
	 */
	do {
		DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, again));
		DBG_CALL(Dbg_syms_ar_title(ofl->ofl_lml, name, again));
		again = FALSE;

		for (arsym = adp->ad_start, aup = adp->ad_aux; arsym->as_name;
		    ++arsym, ++aup) {
			Ar_mem		*amp;
			Sym		*sym;
			Boolean		visible = TRUE;
			Boolean		vers;
			Ifl_desc	*ifl;

			/*
			 * If the auxiliary members value indicates that this
			 * member has been processed then this symbol will have
			 * been added to the output file image already or the
			 * object was rejected in which case we don't want to
			 * process it again.
			 */
			if (aup->au_mem == FLG_ARMEM_PROC)
				continue;

			/*
			 * If the auxiliary symbol element is non-zero lookup
			 * the symbol from the internal symbol table.
			 */
			if ((sdp = aup->au_syms) == NULL) {
				if ((sdp = ld_sym_find(arsym->as_name,
				    /* LINTED */
				    (Word)arsym->as_hash, NULL, ofl)) == NULL) {
					DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
					    name, arsym));
					continue;
				}
				aup->au_syms = sdp;
			}

			/*
			 * With '-z allextract', all members will be extracted.
			 *
			 * This archive member is a candidate for extraction if
			 * the internal symbol originates from an explicit file,
			 * and represents an undefined or tentative symbol.
			 *
			 * By default, weak references do not cause archive
			 * extraction, however the -zweakextract flag overrides
			 * this default.
			 *
			 * If this symbol has already been bound to a versioned
			 * shared object, but the shared objects version is not
			 * available, then a definition of this symbol from
			 * within the archive is a better candidate.  Similarly,
			 * if this symbol has been bound to a shared object, but
			 * the original reference expected hidden or protected
			 * visibility, then a definition of this symbol from
			 * within the archive is a better candidate.
			 */
			vers = TRUE;
			ifl = sdp->sd_file;

			sym = sdp->sd_sym;

			if (sdp->sd_ref == REF_DYN_NEED) {
				uchar_t	vis;

				if (ifl->ifl_vercnt) {
					Word		vndx;
					Ver_index	*vip;

					vndx = sdp->sd_aux->sa_dverndx;
					vip = &ifl->ifl_verndx[vndx];
					if (!(vip->vi_flags & FLG_VER_AVAIL))
						vers = FALSE;
				}

				vis = ELF_ST_VISIBILITY(sym->st_other);
				visible = sym_vis[vis];
			}

			if (((ifl->ifl_flags & FLG_IF_NEEDED) == 0) ||
			    (visible && vers && (sym->st_shndx != SHN_UNDEF) &&
			    (sym->st_shndx != SHN_COMMON)) ||
			    ((ELF_ST_BIND(sym->st_info) == STB_WEAK) &&
			    (!(ofl->ofl_flags1 & FLG_OF1_WEAKEXT)))) {
				DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
				    name, arsym));
				continue;
			}

			/*
			 * Determine if we have already extracted this member,
			 * and if so reuse the Ar_mem information.
			 */
			if ((amp = aup->au_mem) != 0) {
				arelf = amp->am_elf;
				arname = amp->am_name;
				arpath = amp->am_path;
			} else {
				/*
				 * Set up a new elf descriptor for this member.
				 */
				if (elf_rand(adp->ad_elf, arsym->as_off) !=
				    arsym->as_off) {
					ld_eprintf(ofl, ERR_ELF,
					    MSG_INTL(MSG_ELF_ARMEM), name,
					    EC_WORD(arsym->as_off),
					    demangle(arsym->as_name));
					return (FALSE);
				}

				if ((arelf = elf_begin(fd, ELF_C_READ,
				    adp->ad_elf)) == NULL) {
					ld_eprintf(ofl, ERR_ELF,
					    MSG_INTL(MSG_ELF_BEGIN), name);
					return (FALSE);
				}

				/* Get member filename */
				if ((arname = ar_member_name(name, arelf,
				    ofl)) == NULL)
					return (FALSE);

				/* Construct the member's full pathname */
				if ((arpath = ar_member_path(name, arname)) ==
				    NULL)
					return (S_ERROR);

				/*
				 * Determine whether the support libraries wish
				 * to process this open. See comments in
				 * ld_process_open().
				 */
				ld_sup_open(ofl, &arpath, &arname, &fd,
				    (FLG_IF_EXTRACT | FLG_IF_NEEDED),
				    &arelf, adp->ad_elf, arsym->as_off,
				    elf_kind(arelf));
				if (arelf == NULL) {
					/* Ignore this archive member */
					aup->au_mem = FLG_ARMEM_PROC;
					continue;
				}
			}

			/*
			 * The symbol for which this archive member is being
			 * processed may provide a better alternative to the
			 * symbol that is presently known.  Two cases are
			 * covered:
			 *
			 *  i.	The present symbol represents tentative data.
			 *	The archive member may provide a data
			 *	definition symbol.
			 *  ii.	The present symbol represents a reference that
			 *	has seen a definition within a shared object
			 *	dependency, but the reference expects to be
			 *	reduced to hidden or protected visibility.
			 */
			if ((sym->st_shndx == SHN_COMMON) ||
			    (visible == FALSE)) {
				/*
				 * If we don't already have a member structure
				 * allocate one.
				 */
				if (!amp) {
					if ((amp = libld_calloc(sizeof (Ar_mem),
					    1)) == NULL)
						return (FALSE);
					amp->am_elf = arelf;
					amp->am_name = arname;
					amp->am_path = arpath;
				}
				DBG_CALL(Dbg_syms_ar_checking(ofl->ofl_lml,
				    name, arname, arsym));
				if ((err = process_member(amp, arsym->as_name,
				    sdp, ofl)) == S_ERROR)
					return (FALSE);

				/*
				 * If it turns out that we don't need this
				 * member simply initialize all other auxiliary
				 * entries that match this offset with this
				 * members address.  In this way we can resuse
				 * this information if we recurse back to this
				 * symbol.
				 */
				if (err == 0) {
					if (aup->au_mem == NULL)
						ld_ar_member(adp, arsym,
						    aup, amp);
					continue;
				}
			}

			/*
			 * Process the archive member.  Retain any error for
			 * return to the caller.
			 */
			DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml,
			    name, arname, arsym));
			switch (ar_input(fd, adp, ofl, arelf, arpath,
			    rej)) {
			case S_ERROR:
				return (FALSE);
			case 0:
				/*
				 * Mark the member as extracted so that we
				 * don't try and process it again on a rescan.
				 */
				ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
				continue;
			}

			/*
			 * Note that this archive has contributed something
			 * during this specific operation, and also signal
			 * the need to rescan the archive.
			 */
			*found = again = TRUE;

			ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
		}
	} while (again);

	return (TRUE);
}
コード例 #27
0
ファイル: tls.c プロジェクト: AlfredArouna/illumos-gate
int
tls_statmod(Lm_list *lml, Rt_map *lmp)
{
	uint_t		tlsmodndx, tlsmodcnt = lml->lm_tls;
	TLS_modinfo	**tlsmodlist, *tlsbuflist;
	Phdr		*tlsphdr;
	void		(*fptr)(TLS_modinfo **, ulong_t);

	fptr = (void (*)())lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;

	/*
	 * Allocate a buffer to report the TLS modules, the buffer consists of:
	 *
	 *	TLS_modinfo *	ptrs[tlsmodcnt + 1]
	 *	TLS_modinfo	bufs[tlsmodcnt]
	 *
	 * The ptrs are initialized to the bufs - except the last one which
	 * null terminates the array.
	 *
	 * Note, even if no TLS has yet been observed, we still supply a
	 * TLS buffer with a single null entry.  This allows us to initialize
	 * the backup TLS reservation.
	 */
	if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
	    (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == NULL)
		return (0);

	lml->lm_tls = 0;

	/*
	 * If we don't have any TLS modules - report that and return.
	 */
	if (tlsmodcnt == 0) {
		if (fptr)
			(*fptr)(tlsmodlist, tls_static_resv);
		DBG_CALL(Dbg_tls_static_block(&lml_main, 0, 0,
		    tls_static_resv));
		return (1);
	}

	/*
	 * Initialize the TLS buffer.
	 */
	tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
	    ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));

	for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
		tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];

	/*
	 * Account for the initial dtv ptr in the TLSSIZE calculation.
	 */
	tlsmodndx = 0;
	for (lmp = lml->lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
		if (THIS_IS_NOT_ELF(lmp) ||
		    (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
			continue;

		tlsphdr = PTTLS(lmp);

		tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
		tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
		tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);

		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
			tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
			    ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
			    ADDR(lmp));
		}
		tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz;
		tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz;
		tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS;
		tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp);
		tlsmodndx++;
	}

	DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist,
	    tls_static_size, tls_static_resv));
	(*fptr)(tlsmodlist, (tls_static_size + tls_static_resv));

	/*
	 * We're done with the list - clean it up.
	 */
	free(tlsmodlist);
	return (1);
}
コード例 #28
0
ファイル: audit.c プロジェクト: andreiw/polaris
/*
 * 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);
}
コード例 #29
0
ファイル: groups.c プロジェクト: AlainODea/illumos-gate
uintptr_t
ld_group_process(Is_desc *gisc, Ofl_desc *ofl)
{
	Ifl_desc	*gifl = gisc->is_file;
	Shdr		*sshdr, *gshdr = gisc->is_shdr;
	Is_desc		*isc;
	Sym		*sym;
	const char	*str;
	Group_desc	gd;
	size_t		ndx;
	int		gnu_stt_section;

	/*
	 * Confirm that the sh_link points to a valid section.
	 */
	if ((gshdr->sh_link == SHN_UNDEF) ||
	    (gshdr->sh_link >= gifl->ifl_shnum) ||
	    ((isc = gifl->ifl_isdesc[gshdr->sh_link]) == NULL)) {
		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHLINK),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx),
		    gisc->is_name, EC_XWORD(gshdr->sh_link));
		return (0);
	}
	if (gshdr->sh_entsize == 0) {
		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHENTSIZE),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name,
		    EC_XWORD(gshdr->sh_entsize));
		return (0);
	}

	/*
	 * Get the associated symbol table.  Sanity check the sh_info field
	 * (which points to the signature symbol table entry) against the size
	 * of the symbol table.
	 */
	sshdr = isc->is_shdr;
	sym = (Sym *)isc->is_indata->d_buf;

	if ((sshdr->sh_info == SHN_UNDEF) ||
	    (gshdr->sh_info >= (Word)(sshdr->sh_size / sshdr->sh_entsize)) ||
	    ((isc = gifl->ifl_isdesc[sshdr->sh_link]) == NULL)) {
		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name,
		    EC_XWORD(gshdr->sh_info));
		return (0);
	}

	sym += gshdr->sh_info;

	/*
	 * Get the symbol name from the associated string table.
	 */
	str = (char *)isc->is_indata->d_buf;
	str += sym->st_name;

	/*
	 * The GNU assembler can use section symbols as the signature symbol
	 * as described by this comment in the gold linker (found via google):
	 *
	 *	It seems that some versions of gas will create a section group
	 *	associated with a section symbol, and then fail to give a name
	 *	to the section symbol.  In such a case, use the name of the
	 *	section.
	 *
	 * In order to support such objects, we do the same.
	 */
	gnu_stt_section = ((sym->st_name == 0) || (*str == '\0')) &&
	    (ELF_ST_TYPE(sym->st_info) == STT_SECTION);
	if (gnu_stt_section)
		str = gisc->is_name;


	/*
	 * Generate a group descriptor.
	 */
	gd.gd_isc = gisc;
	gd.gd_oisc = NULL;
	gd.gd_name = str;
	gd.gd_data = gisc->is_indata->d_buf;
	gd.gd_cnt = gisc->is_indata->d_size / sizeof (Word);

	/*
	 * If this group is a COMDAT group, validate the signature symbol.
	 */
	if ((gd.gd_data[0] & GRP_COMDAT) && !gnu_stt_section &&
	    ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) ||
	    (sym->st_shndx == SHN_UNDEF))) {
		/* If section symbol, construct a printable name for it */
		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
			if (gisc->is_sym_name == NULL)
				(void) ld_stt_section_sym_name(gisc);

			if (gisc->is_sym_name != NULL)
				str = gisc->is_sym_name;
		}

		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_GRP_INVALSYM),
		    gifl->ifl_name, EC_WORD(gisc->is_scnndx),
		    gisc->is_name, str);
		return (0);
	}

	/*
	 * If the signature symbol is a name generated by the GNU compiler to
	 * refer to a header, we need sloppy relocation.
	 */
	if (is_header_gensym(str)) {
		if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0)
			ofl->ofl_flags1 |= FLG_OF1_RLXREL;
		DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, gisc, TRUE,
		    (ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0));
	}

	/*
	 * Validate the section indices within the group.  If this is a COMDAT
	 * group, mark each section as COMDAT.
	 */
	for (ndx = 1; ndx < gd.gd_cnt; ndx++) {
		Word	gndx;

		if ((gndx = gd.gd_data[ndx]) >= gifl->ifl_shnum) {
			ld_eprintf(ofl, ERR_FATAL,
			    MSG_INTL(MSG_GRP_INVALNDX), gifl->ifl_name,
			    EC_WORD(gisc->is_scnndx), gisc->is_name, ndx, gndx);
			return (0);
		}

		if (gd.gd_data[0] & GRP_COMDAT)
			gifl->ifl_isdesc[gndx]->is_flags |= FLG_IS_COMDAT;
	}

	/*
	 * If this is a COMDAT group, determine whether this group has already
	 * been encountered, or whether this is the first instance of the group.
	 */
	if ((gd.gd_data[0] & GRP_COMDAT) &&
	    (gpavl_loaded(ofl, &gd) == S_ERROR))
		return (S_ERROR);

	/*
	 * Associate the group descriptor with this input file.
	 */
	if (alist_append(&(gifl->ifl_groups), &gd, sizeof (Group_desc),
	    AL_CNT_IFL_GROUPS) == NULL)
		return (S_ERROR);

	return (1);
}
コード例 #30
0
ファイル: move.c プロジェクト: AlfredArouna/illumos-gate
/*
 * Move data.  Apply sparse initialization to data in zeroed bss.
 */
int
move_data(Rt_map *lmp, APlist **textrel)
{
	Lm_list		*lml = LIST(lmp);
	Move		*mv = MOVETAB(lmp);
	ulong_t		num, mvnum = MOVESZ(lmp) / MOVEENT(lmp);
	int		moves;

	/*
	 * If these records are against the executable, and the executable was
	 * built prior to Solaris 8, keep track of the move record symbol.  See
	 * comment in analyze.c:lookup_sym_interpose() in regards Solaris 8
	 * objects and DT_FLAGS.
	 */
	moves = (lmp == lml->lm_head) && ((FLAGS1(lmp) & FL1_RT_DTFLAGS) == 0);

	DBG_CALL(Dbg_move_data(lmp));
	for (num = 0; num < mvnum; num++, mv++) {
		mmapobj_result_t	*mpp;
		Addr			addr, taddr;
		Half 			rep, repno, stride;
		Sym			*sym;

		if ((sym = (Sym *)SYMTAB(lmp) + ELF_M_SYM(mv->m_info)) == 0)
			continue;

		stride = mv->m_stride + 1;
		addr = sym->st_value;

		/*
		 * Determine the move data target, and verify the address is
		 * writable.
		 */
		if ((FLAGS(lmp) & FLG_RT_FIXED) == 0)
			addr += ADDR(lmp);
		taddr = addr + mv->m_poffset;

		if ((mpp = find_segment((caddr_t)taddr, lmp)) == NULL) {
			elf_move_bad(lml, lmp, sym, num, taddr);
			continue;
		}
		if (((mpp->mr_prot & PROT_WRITE) == 0) &&
		    ((set_prot(lmp, mpp, 1) == 0) ||
		    (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL)))
			return (0);

		DBG_CALL(Dbg_move_entry2(lml, mv, sym->st_name,
		    (const char *)(sym->st_name + STRTAB(lmp))));

		for (rep = 0, repno = 0; rep < mv->m_repeat; rep++) {
			DBG_CALL(Dbg_move_expand(lml, mv, taddr));

			switch (ELF_M_SIZE(mv->m_info)) {
			case 1:
				*((char *)taddr) = (char)mv->m_value;
				taddr += stride;
				repno++;
				break;
			case 2:
				/* LINTED */
				*((Half *)taddr) = (Half)mv->m_value;
				taddr += 2 * stride;
				repno++;
				break;
			case 4:
				/* LINTED */
				*((Word *)taddr) = (Word)mv->m_value;
				taddr += 4 * stride;
				repno++;
				break;
			case 8:
				/* LINTED */
				*((unsigned long long *)taddr) = mv->m_value;
				taddr += 8 * stride;
				repno++;
				break;
			default:
				eprintf(lml, ERR_NONE, MSG_INTL(MSG_MOVE_ERR1));
				break;
			}
		}

		/*
		 * If any move records have been applied to this symbol, retain
		 * the symbol address if required for backward compatibility
		 * copy relocation processing.
		 */
		if (moves && repno &&
		    (aplist_append(&alp, (void *)addr, AL_CNT_MOVES) == NULL))
			return (0);
	}

	/*
	 * Binaries built in the early 1990's prior to Solaris 8, using the ild
	 * incremental linker are known to have zero filled move sections
	 * (presumably place holders for new, incoming move sections).  If no
	 * move records have been processed, remove the move identifier to
	 * optimize the amount of backward compatibility copy relocation
	 * processing that is needed.
	 */
	if (moves && (alp == NULL))
		FLAGS(lmp) &= ~FLG_RT_MOVE;

	return (1);
}