xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/elf.c (revision 0904e7ec)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
227257d1b4Sraf /*
237257d1b4Sraf  *	Copyright (c) 1988 AT&T
247257d1b4Sraf  *	  All Rights Reserved
25f441771bSRod Evans  *
26f441771bSRod Evans  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
277257d1b4Sraf  */
28b533f56bSRobert Mustacchi /*
29b533f56bSRobert Mustacchi  * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
30b533f56bSRobert Mustacchi  */
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Object file dependent support for ELF objects.
347c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate #include	<stdio.h>
377c478bd9Sstevel@tonic-gate #include	<sys/procfs.h>
387c478bd9Sstevel@tonic-gate #include	<sys/mman.h>
397c478bd9Sstevel@tonic-gate #include	<sys/debug.h>
407c478bd9Sstevel@tonic-gate #include	<string.h>
417c478bd9Sstevel@tonic-gate #include	<limits.h>
427c478bd9Sstevel@tonic-gate #include	<dlfcn.h>
435aefb655Srie #include	<debug.h>
445aefb655Srie #include	<conv.h>
457c478bd9Sstevel@tonic-gate #include	"_rtld.h"
467c478bd9Sstevel@tonic-gate #include	"_audit.h"
477c478bd9Sstevel@tonic-gate #include	"_elf.h"
48f441771bSRod Evans #include	"_inline_gen.h"
49f441771bSRod Evans #include	"_inline_reloc.h"
507c478bd9Sstevel@tonic-gate #include	"msg.h"
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Default and secure dependency search paths.
547c478bd9Sstevel@tonic-gate  */
5556deab07SRod Evans static Spath_defn _elf_def_dirs[] = {
567c478bd9Sstevel@tonic-gate #if	defined(_ELF64)
5756deab07SRod Evans 	{ MSG_ORIG(MSG_PTH_LIB_64),		MSG_PTH_LIB_64_SIZE },
5856deab07SRod Evans 	{ MSG_ORIG(MSG_PTH_USRLIB_64),		MSG_PTH_USRLIB_64_SIZE },
597c478bd9Sstevel@tonic-gate #else
6056deab07SRod Evans 	{ MSG_ORIG(MSG_PTH_LIB),		MSG_PTH_LIB_SIZE },
627c478bd9Sstevel@tonic-gate #endif
6356deab07SRod Evans 	{ 0, 0 }
647c478bd9Sstevel@tonic-gate };
6656deab07SRod Evans static Spath_defn _elf_sec_dirs[] = {
677c478bd9Sstevel@tonic-gate #if	defined(_ELF64)
6856deab07SRod Evans 	{ MSG_ORIG(MSG_PTH_LIBSE_64),		MSG_PTH_LIBSE_64_SIZE },
707c478bd9Sstevel@tonic-gate #else
737c478bd9Sstevel@tonic-gate #endif
7456deab07SRod Evans 	{ 0, 0 }
757c478bd9Sstevel@tonic-gate };
7756deab07SRod Evans Alist	*elf_def_dirs = NULL;
7856deab07SRod Evans Alist	*elf_sec_dirs = NULL;
7956deab07SRod Evans 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * Defines for local functions.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate static void	elf_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int);
8456deab07SRod Evans static Addr	elf_entry_point(void);
8556deab07SRod Evans static int	elf_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t);
8656deab07SRod Evans static Alist	**elf_get_def_dirs(void);
8756deab07SRod Evans static Alist	**elf_get_sec_dirs(void);
8856deab07SRod Evans static char	*elf_get_so(const char *, const char *, size_t, size_t);
899aa23310Srie static int	elf_needed(Lm_list *, Aliste, Rt_map *, int *);
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * Functions and data accessed through indirect pointers.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate Fct elf_fct = {
9556deab07SRod Evans 	elf_verify,
9656deab07SRod Evans 	elf_new_lmp,
9756deab07SRod Evans 	elf_entry_point,
987c478bd9Sstevel@tonic-gate 	elf_needed,
997c478bd9Sstevel@tonic-gate 	lookup_sym,
1007c478bd9Sstevel@tonic-gate 	elf_reloc,
10156deab07SRod Evans 	elf_get_def_dirs,
10256deab07SRod Evans 	elf_get_sec_dirs,
1037c478bd9Sstevel@tonic-gate 	elf_fix_name,
1047c478bd9Sstevel@tonic-gate 	elf_get_so,
1057c478bd9Sstevel@tonic-gate 	elf_dladdr,
10656deab07SRod Evans 	dlsym_handle
1077c478bd9Sstevel@tonic-gate };
10956deab07SRod Evans /*
11056deab07SRod Evans  * Default and secure dependency search paths.
11156deab07SRod Evans  */
11256deab07SRod Evans static Alist **
elf_get_def_dirs()11356deab07SRod Evans elf_get_def_dirs()
11456deab07SRod Evans {
11556deab07SRod Evans 	if (elf_def_dirs == NULL)
11656deab07SRod Evans 		set_dirs(&elf_def_dirs, _elf_def_dirs, LA_SER_DEFAULT);
11756deab07SRod Evans 	return (&elf_def_dirs);
11856deab07SRod Evans }
11956deab07SRod Evans 
12056deab07SRod Evans static Alist **
elf_get_sec_dirs()12156deab07SRod Evans elf_get_sec_dirs()
12256deab07SRod Evans {
12356deab07SRod Evans 	if (elf_sec_dirs == NULL)
12456deab07SRod Evans 		set_dirs(&elf_sec_dirs, _elf_sec_dirs, LA_SER_SECURE);
12556deab07SRod Evans 	return (&elf_sec_dirs);
12656deab07SRod Evans }
1287c478bd9Sstevel@tonic-gate /*
129*0904e7ecSRichard Lowe  * For a.out we have actual work to do here, on ELF we just perform path
130*0904e7ecSRichard Lowe  * expansion.
1317c478bd9Sstevel@tonic-gate  */
13256deab07SRod Evans static int
elf_fix_name(const char * name,Rt_map * clmp,Alist ** alpp,Aliste alni,uint_t orig)13356deab07SRod Evans elf_fix_name(const char *name, Rt_map *clmp, Alist **alpp, Aliste alni,
13456deab07SRod Evans     uint_t orig)
1357c478bd9Sstevel@tonic-gate {
13656deab07SRod Evans 	return (expand_paths(clmp, name, alpp, alni, orig, 0));
13756deab07SRod Evans }
13856deab07SRod Evans 
13956deab07SRod Evans /*
14008278a5eSRod Evans  * Determine whether this object requires capabilities.
14156deab07SRod Evans  */
14208278a5eSRod Evans inline static int
elf_cap_check(Fdesc * fdp,Ehdr * ehdr,Rej_desc * rej)14356deab07SRod Evans elf_cap_check(Fdesc *fdp, Ehdr *ehdr, Rej_desc *rej)
14456deab07SRod Evans {
14556deab07SRod Evans 	Phdr	*phdr;
14608278a5eSRod Evans 	Cap	*cap = NULL;
14708278a5eSRod Evans 	Dyn	*dyn = NULL;
14808278a5eSRod Evans 	char	*str = NULL;
14908278a5eSRod Evans 	Addr	base;
150f441771bSRod Evans 	uint_t	cnt, dyncnt;
15156deab07SRod Evans 
15208278a5eSRod Evans 	/*
15308278a5eSRod Evans 	 * If this is a shared object, the base address of the shared object is
15408278a5eSRod Evans 	 * added to all address values defined within the object.  Otherwise, if
15508278a5eSRod Evans 	 * this is an executable, all object addresses are used as is.
15608278a5eSRod Evans 	 */
15708278a5eSRod Evans 	if (ehdr->e_type == ET_EXEC)
15808278a5eSRod Evans 		base = 0;
15908278a5eSRod Evans 	else
16008278a5eSRod Evans 		base = (Addr)ehdr;
16108278a5eSRod Evans 
16256deab07SRod Evans 	/* LINTED */
16356deab07SRod Evans 	phdr = (Phdr *)((char *)ehdr + ehdr->e_phoff);
16456deab07SRod Evans 	for (cnt = 0; cnt < ehdr->e_phnum; cnt++, phdr++) {
16508278a5eSRod Evans 		if (phdr->p_type == PT_DYNAMIC) {
16608278a5eSRod Evans 			/* LINTED */
16708278a5eSRod Evans 			dyn = (Dyn *)((uintptr_t)phdr->p_vaddr + base);
168f441771bSRod Evans 			dyncnt = phdr->p_filesz / sizeof (Dyn);
16908278a5eSRod Evans 		} else if (phdr->p_type == PT_SUNWCAP) {
17008278a5eSRod Evans 			/* LINTED */
17108278a5eSRod Evans 			cap = (Cap *)((uintptr_t)phdr->p_vaddr + base);
17208278a5eSRod Evans 		}
17308278a5eSRod Evans 	}
17456deab07SRod Evans 
17508278a5eSRod Evans 	if (cap) {
17608278a5eSRod Evans 		/*
17708278a5eSRod Evans 		 * From the .dynamic section, determine the associated string
17808278a5eSRod Evans 		 * table.  Required for CA_SUNW_MACH and CA_SUNW_PLAT
17908278a5eSRod Evans 		 * processing.
18008278a5eSRod Evans 		 */
181f441771bSRod Evans 		while (dyn && dyncnt) {
18208278a5eSRod Evans 			if (dyn->d_tag == DT_NULL) {
18308278a5eSRod Evans 				break;
18408278a5eSRod Evans 			} else if (dyn->d_tag == DT_STRTAB) {
18508278a5eSRod Evans 				str = (char *)(dyn->d_un.d_ptr + base);
18608278a5eSRod Evans 				break;
18756deab07SRod Evans 			}
188f441771bSRod Evans 			dyn++, dyncnt--;
18956deab07SRod Evans 		}
19056deab07SRod Evans 	}
19108278a5eSRod Evans 
19208278a5eSRod Evans 	/*
19308278a5eSRod Evans 	 * Establish any alternative capabilities, and validate this object
19408278a5eSRod Evans 	 * if it defines it's own capabilities information.
19508278a5eSRod Evans 	 */
19608278a5eSRod Evans 	return (cap_check_fdesc(fdp, cap, str, rej));
1977c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * Determine if we have been given an ELF file and if so determine if the file
2017c478bd9Sstevel@tonic-gate  * is compatible.  Returns 1 if true, else 0 and sets the reject descriptor
2027c478bd9Sstevel@tonic-gate  * with associated error information.
2037c478bd9Sstevel@tonic-gate  */
20456deab07SRod Evans Fct *
elf_verify(caddr_t addr,size_t size,Fdesc * fdp,const char * name,Rej_desc * rej)20556deab07SRod Evans elf_verify(caddr_t addr, size_t size, Fdesc *fdp, const char *name,
20656deab07SRod Evans     Rej_desc *rej)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	Ehdr	*ehdr;
20956deab07SRod Evans 	char	*caddr = (char *)addr;
2117c478bd9Sstevel@tonic-gate 	/*
2127c478bd9Sstevel@tonic-gate 	 * Determine if we're an elf file.  If not simply return, we don't set
2137c478bd9Sstevel@tonic-gate 	 * any rejection information as this test allows use to scroll through
2147c478bd9Sstevel@tonic-gate 	 * the objects we support (ELF, AOUT).
2157c478bd9Sstevel@tonic-gate 	 */
21656deab07SRod Evans 	if (size < sizeof (Ehdr) ||
21756deab07SRod Evans 	    caddr[EI_MAG0] != ELFMAG0 ||
21856deab07SRod Evans 	    caddr[EI_MAG1] != ELFMAG1 ||
21956deab07SRod Evans 	    caddr[EI_MAG2] != ELFMAG2 ||
22056deab07SRod Evans 	    caddr[EI_MAG3] != ELFMAG3) {
22156deab07SRod Evans 		return (NULL);
2227c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 	/*
2257c478bd9Sstevel@tonic-gate 	 * Check class and encoding.
2267c478bd9Sstevel@tonic-gate 	 */
2277c478bd9Sstevel@tonic-gate 	/* LINTED */
22856deab07SRod Evans 	ehdr = (Ehdr *)addr;
2297c478bd9Sstevel@tonic-gate 	if (ehdr->e_ident[EI_CLASS] != M_CLASS) {
2307c478bd9Sstevel@tonic-gate 		rej->rej_type = SGS_REJ_CLASS;
2317c478bd9Sstevel@tonic-gate 		rej->rej_info = (uint_t)ehdr->e_ident[EI_CLASS];
23256deab07SRod Evans 		return (NULL);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 	if (ehdr->e_ident[EI_DATA] != M_DATA) {
2357c478bd9Sstevel@tonic-gate 		rej->rej_type = SGS_REJ_DATA;
2367c478bd9Sstevel@tonic-gate 		rej->rej_info = (uint_t)ehdr->e_ident[EI_DATA];
23756deab07SRod Evans 		return (NULL);
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 	if ((ehdr->e_type != ET_REL) && (ehdr->e_type != ET_EXEC) &&
2407c478bd9Sstevel@tonic-gate 	    (ehdr->e_type != ET_DYN)) {
2417c478bd9Sstevel@tonic-gate 		rej->rej_type = SGS_REJ_TYPE;
2427c478bd9Sstevel@tonic-gate 		rej->rej_info = (uint_t)ehdr->e_type;
24356deab07SRod Evans 		return (NULL);
2447c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 	/*
24756deab07SRod Evans 	 * Verify ELF version.
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	if (ehdr->e_version > EV_CURRENT) {
2507c478bd9Sstevel@tonic-gate 		rej->rej_type = SGS_REJ_VERSION;
2517c478bd9Sstevel@tonic-gate 		rej->rej_info = (uint_t)ehdr->e_version;
25256deab07SRod Evans 		return (NULL);
2537c478bd9Sstevel@tonic-gate 	}
25456deab07SRod Evans 
25556deab07SRod Evans 	/*
25656deab07SRod Evans 	 * Verify machine specific flags.
25756deab07SRod Evans 	 */
25856deab07SRod Evans 	if (elf_mach_flags_check(rej, ehdr) == 0)
25956deab07SRod Evans 		return (NULL);
26056deab07SRod Evans 
26156deab07SRod Evans 	/*
26208278a5eSRod Evans 	 * Verify any capability requirements.  Note, if this object is a shared
26308278a5eSRod Evans 	 * object that is explicitly defined on the ldd(1) command line, and it
26408278a5eSRod Evans 	 * contains an incompatible capabilities requirement, then inform the
26508278a5eSRod Evans 	 * user, but continue processing.
26656deab07SRod Evans 	 */
26756deab07SRod Evans 	if (elf_cap_check(fdp, ehdr, rej) == 0) {
26856deab07SRod Evans 		Rt_map	*lmp = lml_main.lm_head;
26956deab07SRod Evans 
270dde769a2SRod Evans 		if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
271dde769a2SRod Evans 		    (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
27208278a5eSRod Evans 			/* LINTED */
27308278a5eSRod Evans 			(void) printf(MSG_INTL(ldd_warn[rej->rej_type]), name,
27408278a5eSRod Evans 			    rej->rej_str);
27556deab07SRod Evans 			return (&elf_fct);
27656deab07SRod Evans 		}
27756deab07SRod Evans 		return (NULL);
27856deab07SRod Evans 	}
27956deab07SRod Evans 	return (&elf_fct);
2807c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * The runtime linker employs lazy loading to provide the libraries needed for
2847c478bd9Sstevel@tonic-gate  * debugging, preloading .o's and dldump().  As these are seldom used, the
2857c478bd9Sstevel@tonic-gate  * standard startup of ld.so.1 doesn't initialize all the information necessary
2867c478bd9Sstevel@tonic-gate  * to perform plt relocation on ld.so.1's link-map.  The first time lazy loading
2877c478bd9Sstevel@tonic-gate  * is called we get here to perform these initializations:
2887c478bd9Sstevel@tonic-gate  *
289f441771bSRod Evans  *  -	elf_needed() is called to establish any ld.so.1 dependencies.  These
290f441771bSRod Evans  *	dependencies should all be lazy loaded, so this routine is typically a
29167d74cc3SToomas Soome  *	no-op.  However, we call elf_needed() for completeness, in case any
292f441771bSRod Evans  *	NEEDED initialization is required.
2937c478bd9Sstevel@tonic-gate  *
2942017c965SRod Evans  *  -	For intel, ld.so.1's JMPSLOT relocations need relative updates. These
2957c478bd9Sstevel@tonic-gate  *	are by default skipped thus delaying all relative relocation processing
29667d74cc3SToomas Soome  *	on every invocation of ld.so.1.
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate int
elf_rtld_load()2997c478bd9Sstevel@tonic-gate elf_rtld_load()
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	Lm_list	*lml = &lml_rtld;
3027c478bd9Sstevel@tonic-gate 	Rt_map	*lmp = lml->lm_head;
3047c478bd9Sstevel@tonic-gate 	if (lml->lm_flags & LML_FLG_PLTREL)
3057c478bd9Sstevel@tonic-gate 		return (1);
3079aa23310Srie 	if (elf_needed(lml, ALIST_OFF_DATA, lmp, NULL) == 0)
3087c478bd9Sstevel@tonic-gate 		return (0);
31002ca3e02Srie #if	defined(__i386)
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * This is a kludge to give ld.so.1 a performance benefit on i386.
3137c478bd9Sstevel@tonic-gate 	 * It's based around two factors.
3147c478bd9Sstevel@tonic-gate 	 *
3152017c965SRod Evans 	 *  -	JMPSLOT relocations (PLT's) actually need a relative relocation
3167c478bd9Sstevel@tonic-gate 	 *	applied to the GOT entry so that they can find PLT0.
3177c478bd9Sstevel@tonic-gate 	 *
3182017c965SRod Evans 	 *  -	ld.so.1 does not exercise *any* PLT's before it has made a call
3197c478bd9Sstevel@tonic-gate 	 *	to elf_lazy_load().  This is because all dynamic dependencies
32067d74cc3SToomas Soome 	 *	are recorded as lazy dependencies.
3217c478bd9Sstevel@tonic-gate 	 */
32256deab07SRod Evans 	(void) elf_reloc_relative_count((ulong_t)JMPREL(lmp),
3237c478bd9Sstevel@tonic-gate 	    (ulong_t)(PLTRELSZ(lmp) / RELENT(lmp)), (ulong_t)RELENT(lmp),
324f441771bSRod Evans 	    (ulong_t)ADDR(lmp), lmp, NULL, 0);
3257c478bd9Sstevel@tonic-gate #endif
3267c478bd9Sstevel@tonic-gate 	lml->lm_flags |= LML_FLG_PLTREL;
3277c478bd9Sstevel@tonic-gate 	return (1);
3287c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * Lazy load an object.
3327c478bd9Sstevel@tonic-gate  */
3337c478bd9Sstevel@tonic-gate Rt_map *
elf_lazy_load(Rt_map * clmp,Slookup * slp,uint_t ndx,const char * sym,uint_t flags,Grp_hdl ** hdl,int * in_nfavl)3349aa23310Srie elf_lazy_load(Rt_map *clmp, Slookup *slp, uint_t ndx, const char *sym,
3352017c965SRod Evans     uint_t flags, Grp_hdl **hdl, int *in_nfavl)
3367c478bd9Sstevel@tonic-gate {
33756deab07SRod Evans 	Alist		*palp = NULL;
338dde769a2SRod Evans 	Rt_map		*nlmp;
33975e7992aSrie 	Dyninfo		*dip = &DYNINFO(clmp)[ndx], *pdip;
3407c478bd9Sstevel@tonic-gate 	const char	*name;
3417c478bd9Sstevel@tonic-gate 	Lm_list		*lml = LIST(clmp);
3427c478bd9Sstevel@tonic-gate 	Aliste		lmco;
3447c478bd9Sstevel@tonic-gate 	/*
345f441771bSRod Evans 	 * If this dependency should be ignored, or has already been processed,
346f441771bSRod Evans 	 * we're done.
3477c478bd9Sstevel@tonic-gate 	 */
34856deab07SRod Evans 	if (((nlmp = (Rt_map *)dip->di_info) != NULL) ||
349f441771bSRod Evans 	    (dip->di_flags & (FLG_DI_IGNORE | FLG_DI_LDD_DONE)))
3507c478bd9Sstevel@tonic-gate 		return (nlmp);
3527c478bd9Sstevel@tonic-gate 	/*
35375e7992aSrie 	 * If we're running under ldd(1), indicate that this dependency has been
35475e7992aSrie 	 * processed (see test above).  It doesn't matter whether the object is
35575e7992aSrie 	 * successfully loaded or not, this flag simply ensures that we don't
35675e7992aSrie 	 * repeatedly attempt to load an object that has already failed to load.
35775e7992aSrie 	 * To do so would create multiple failure diagnostics for the same
35875e7992aSrie 	 * object under ldd(1).
35975e7992aSrie 	 */
36075e7992aSrie 	if (lml->lm_flags & LML_FLG_TRC_ENABLE)
36175e7992aSrie 		dip->di_flags |= FLG_DI_LDD_DONE;
36375e7992aSrie 	/*
36475e7992aSrie 	 * Determine the initial dependency name.
3657c478bd9Sstevel@tonic-gate 	 */
366f441771bSRod Evans 	name = dip->di_name;
3675aefb655Srie 	DBG_CALL(Dbg_file_lazyload(clmp, name, sym));
36975e7992aSrie 	/*
37075e7992aSrie 	 * If this object needs to establish its own group, make sure a handle
37175e7992aSrie 	 * is created.
37275e7992aSrie 	 */
3737c478bd9Sstevel@tonic-gate 	if (dip->di_flags & FLG_DI_GROUP)
3742017c965SRod Evans 		flags |= (FLG_RT_SETGROUP | FLG_RT_PUBHDL);
37675e7992aSrie 	/*
37775e7992aSrie 	 * Lazy dependencies are identified as DT_NEEDED entries with a
37875e7992aSrie 	 * DF_P1_LAZYLOAD flag in the previous DT_POSFLAG_1 element.  The
37975e7992aSrie 	 * dynamic information element that corresponds to the DT_POSFLAG_1
38075e7992aSrie 	 * entry is free, and thus used to store the present entrance
38175e7992aSrie 	 * identifier.  This identifier is used to prevent multiple attempts to
38275e7992aSrie 	 * load a failed lazy loadable dependency within the same runtime linker
38375e7992aSrie 	 * operation.  However, future attempts to reload this dependency are
38475e7992aSrie 	 * still possible.
38575e7992aSrie 	 */
38675e7992aSrie 	if (ndx && (pdip = dip - 1) && (pdip->di_flags & FLG_DI_POSFLAG1))
38775e7992aSrie 		pdip->di_info = (void *)slp->sl_id;
3897c478bd9Sstevel@tonic-gate 	/*
3907c478bd9Sstevel@tonic-gate 	 * Expand the requested name if necessary.
3917c478bd9Sstevel@tonic-gate 	 */
39256deab07SRod Evans 	if (elf_fix_name(name, clmp, &palp, AL_CNT_NEEDED, 0) == 0)
39356deab07SRod Evans 		return (NULL);
3957c478bd9Sstevel@tonic-gate 	/*
396dde769a2SRod Evans 	 * Establish a link-map control list for this request.
3977c478bd9Sstevel@tonic-gate 	 */
39867d74cc3SToomas Soome 	if ((lmco = create_cntl(lml, 0)) == 0) {
3992020b2b6SRod Evans 		remove_alist(&palp, 1);
400dde769a2SRod Evans 		return (NULL);
401dde769a2SRod Evans 	}
4037c478bd9Sstevel@tonic-gate 	/*
4047c478bd9Sstevel@tonic-gate 	 * Load the associated object.
4057c478bd9Sstevel@tonic-gate 	 */
4067c478bd9Sstevel@tonic-gate 	dip->di_info = nlmp =
4072017c965SRod Evans 	    load_one(lml, lmco, palp, clmp, MODE(clmp), flags, hdl, in_nfavl);
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * Remove any expanded pathname infrastructure.  Reduce the pending lazy
4117c478bd9Sstevel@tonic-gate 	 * dependency count of the caller, together with the link-map lists
4127c478bd9Sstevel@tonic-gate 	 * count of objects that still have lazy dependencies pending.
4137c478bd9Sstevel@tonic-gate 	 */
4142020b2b6SRod Evans 	remove_alist(&palp, 1);
4157c478bd9Sstevel@tonic-gate 	if (--LAZY(clmp) == 0)
4167c478bd9Sstevel@tonic-gate 		LIST(clmp)->lm_lazy--;
4187c478bd9Sstevel@tonic-gate 	/*
41902ca3e02Srie 	 * Finish processing the objects associated with this request, and
42002ca3e02Srie 	 * create an association between the caller and this dependency.
4217c478bd9Sstevel@tonic-gate 	 */
42275e7992aSrie 	if (nlmp && ((bind_one(clmp, nlmp, BND_NEEDED) == 0) ||
4232020b2b6SRod Evans 	    ((nlmp = analyze_lmc(lml, lmco, nlmp, clmp, in_nfavl)) == NULL) ||
4249aa23310Srie 	    (relocate_lmc(lml, lmco, clmp, nlmp, in_nfavl) == 0)))
42556deab07SRod Evans 		dip->di_info = nlmp = NULL;
4277c478bd9Sstevel@tonic-gate 	/*
42802ca3e02Srie 	 * If this lazyload has failed, and we've created a new link-map
42902ca3e02Srie 	 * control list to which this request has added objects, then remove
43002ca3e02Srie 	 * all the objects that have been associated to this request.
4317c478bd9Sstevel@tonic-gate 	 */
432481bba9eSRod Evans 	if ((nlmp == NULL) && (lmco != ALIST_OFF_DATA))
433481bba9eSRod Evans 		remove_lmc(lml, clmp, lmco, name);
4357c478bd9Sstevel@tonic-gate 	/*
436dde769a2SRod Evans 	 * Remove any temporary link-map control list.
4377c478bd9Sstevel@tonic-gate 	 */
438481bba9eSRod Evans 	if (lmco != ALIST_OFF_DATA)
4397c478bd9Sstevel@tonic-gate 		remove_cntl(lml, lmco);
44175e7992aSrie 	/*
44275e7992aSrie 	 * If this lazy loading failed, record the fact, and bump the lazy
44375e7992aSrie 	 * counts.
44475e7992aSrie 	 */
44556deab07SRod Evans 	if (nlmp == NULL) {
44675e7992aSrie 		dip->di_flags |= FLG_DI_LAZYFAIL;
44775e7992aSrie 		if (LAZY(clmp)++ == 0)
44875e7992aSrie 			LIST(clmp)->lm_lazy++;
44975e7992aSrie 	}
4517c478bd9Sstevel@tonic-gate 	return (nlmp);
4527c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * Return the entry point of the ELF executable.
4567c478bd9Sstevel@tonic-gate  */
45756deab07SRod Evans static Addr
elf_entry_point(void)45856deab07SRod Evans elf_entry_point(void)
4597c478bd9Sstevel@tonic-gate {
46056deab07SRod Evans 	Rt_map	*lmp = lml_main.lm_head;
46156deab07SRod Evans 	Ehdr	*ehdr = (Ehdr *)ADDR(lmp);
46256deab07SRod Evans 	Addr	addr = (Addr)(ehdr->e_entry);
46456deab07SRod Evans 	if ((FLAGS(lmp) & FLG_RT_FIXED) == 0)
46556deab07SRod Evans 		addr += ADDR(lmp);
46756deab07SRod Evans 	return (addr);
4687c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate /*
4717c478bd9Sstevel@tonic-gate  * Determine if a dependency requires a particular version and if so verify
4727c478bd9Sstevel@tonic-gate  * that the version exists in the dependency.
4737c478bd9Sstevel@tonic-gate  */
47456deab07SRod Evans int
elf_verify_vers(const char * name,Rt_map * clmp,Rt_map * nlmp)4757c478bd9Sstevel@tonic-gate elf_verify_vers(const char *name, Rt_map *clmp, Rt_map *nlmp)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	Verneed		*vnd = VERNEED(clmp);
4787c478bd9Sstevel@tonic-gate 	int		_num, num = VERNEEDNUM(clmp);
4797c478bd9Sstevel@tonic-gate 	char		*cstrs = (char *)STRTAB(clmp);
4807c478bd9Sstevel@tonic-gate 	Lm_list		*lml = LIST(clmp);
4827c478bd9Sstevel@tonic-gate 	/*
4837c478bd9Sstevel@tonic-gate 	 * Traverse the callers version needed information and determine if any
4847c478bd9Sstevel@tonic-gate 	 * specific versions are required from the dependency.
4857c478bd9Sstevel@tonic-gate 	 */
4865aefb655Srie 	DBG_CALL(Dbg_ver_need_title(LIST(clmp), NAME(clmp)));
4877c478bd9Sstevel@tonic-gate 	for (_num = 1; _num <= num; _num++,
4887c478bd9Sstevel@tonic-gate 	    vnd = (Verneed *)((Xword)vnd + vnd->vn_next)) {
4897c478bd9Sstevel@tonic-gate 		Half		cnt = vnd->vn_cnt;
4907c478bd9Sstevel@tonic-gate 		Vernaux		*vnap;
4917c478bd9Sstevel@tonic-gate 		char		*nstrs, *need;
4937c478bd9Sstevel@tonic-gate 		/*
4947c478bd9Sstevel@tonic-gate 		 * Determine if a needed entry matches this dependency.
4957c478bd9Sstevel@tonic-gate 		 */
4967c478bd9Sstevel@tonic-gate 		need = (char *)(cstrs + vnd->vn_file);
4977c478bd9Sstevel@tonic-gate 		if (strcmp(name, need) != 0)
4987c478bd9Sstevel@tonic-gate 			continue;
5007c478bd9Sstevel@tonic-gate 		if ((lml->lm_flags & LML_FLG_TRC_VERBOSE) &&
5017c478bd9Sstevel@tonic-gate 		    ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0))
5027c478bd9Sstevel@tonic-gate 			(void) printf(MSG_INTL(MSG_LDD_VER_FIND), name);
5047c478bd9Sstevel@tonic-gate 		/*
5057c478bd9Sstevel@tonic-gate 		 * Validate that each version required actually exists in the
5067c478bd9Sstevel@tonic-gate 		 * dependency.
5077c478bd9Sstevel@tonic-gate 		 */
5087c478bd9Sstevel@tonic-gate 		nstrs = (char *)STRTAB(nlmp);
5107c478bd9Sstevel@tonic-gate 		for (vnap = (Vernaux *)((Xword)vnd + vnd->vn_aux); cnt;
5117c478bd9Sstevel@tonic-gate 		    cnt--, vnap = (Vernaux *)((Xword)vnap + vnap->vna_next)) {
5127c478bd9Sstevel@tonic-gate 			char		*version, *define;
5137c478bd9Sstevel@tonic-gate 			Verdef		*vdf = VERDEF(nlmp);
5147c478bd9Sstevel@tonic-gate 			ulong_t		_num, num = VERDEFNUM(nlmp);
5157c478bd9Sstevel@tonic-gate 			int		found = 0;
517090a8d9eSAli Bahrami 			/*
518090a8d9eSAli Bahrami 			 * Skip validation of versions that are marked
519090a8d9eSAli Bahrami 			 * INFO. This optimization is used for versions
520090a8d9eSAli Bahrami 			 * that are inherited by another version. Verification
521090a8d9eSAli Bahrami 			 * of the inheriting version is sufficient.
522090a8d9eSAli Bahrami 			 *
523090a8d9eSAli Bahrami 			 * Such versions are recorded in the object for the
524090a8d9eSAli Bahrami 			 * benefit of VERSYM entries that refer to them. This
52508278a5eSRod Evans 			 * provides a purely diagnostic benefit.
526090a8d9eSAli Bahrami 			 */
527090a8d9eSAli Bahrami 			if (vnap->vna_flags & VER_FLG_INFO)
528090a8d9eSAli Bahrami 				continue;
529090a8d9eSAli Bahrami 
5307c478bd9Sstevel@tonic-gate 			version = (char *)(cstrs + vnap->vna_name);
5315aefb655Srie 			DBG_CALL(Dbg_ver_need_entry(lml, 0, need, version));
5337c478bd9Sstevel@tonic-gate 			for (_num = 1; _num <= num; _num++,
5347c478bd9Sstevel@tonic-gate 			    vdf = (Verdef *)((Xword)vdf + vdf->vd_next)) {
5357c478bd9Sstevel@tonic-gate 				Verdaux		*vdap;
5377c478bd9Sstevel@tonic-gate 				if (vnap->vna_hash != vdf->vd_hash)
5387c478bd9Sstevel@tonic-gate 					continue;
5407c478bd9Sstevel@tonic-gate 				vdap = (Verdaux *)((Xword)vdf + vdf->vd_aux);
5417c478bd9Sstevel@tonic-gate 				define = (char *)(nstrs + vdap->vda_name);
5427c478bd9Sstevel@tonic-gate 				if (strcmp(version, define) != 0)
5437c478bd9Sstevel@tonic-gate 					continue;
5457c478bd9Sstevel@tonic-gate 				found++;
5467c478bd9Sstevel@tonic-gate 				break;
5477c478bd9Sstevel@tonic-gate 			}
5497c478bd9Sstevel@tonic-gate 			/*
5507c478bd9Sstevel@tonic-gate 			 * If we're being traced print out any matched version
5517c478bd9Sstevel@tonic-gate 			 * when the verbose (-v) option is in effect.  Always
5527c478bd9Sstevel@tonic-gate 			 * print any unmatched versions.
5537c478bd9Sstevel@tonic-gate 			 */
5547c478bd9Sstevel@tonic-gate 			if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
555a953e2b1Srie 				/* BEGIN CSTYLED */
5567c478bd9Sstevel@tonic-gate 				if (found) {
5577c478bd9Sstevel@tonic-gate 				    if (!(lml->lm_flags & LML_FLG_TRC_VERBOSE))
5587c478bd9Sstevel@tonic-gate 					continue;
5607c478bd9Sstevel@tonic-gate 				    (void) printf(MSG_ORIG(MSG_LDD_VER_FOUND),
5617c478bd9Sstevel@tonic-gate 					need, version, NAME(nlmp));
5627c478bd9Sstevel@tonic-gate 				} else {
5637c478bd9Sstevel@tonic-gate 				    if (rtld_flags & RT_FL_SILENCERR)
5647c478bd9Sstevel@tonic-gate 					continue;
5667c478bd9Sstevel@tonic-gate 				    (void) printf(MSG_INTL(MSG_LDD_VER_NFOUND),
5677c478bd9Sstevel@tonic-gate 					need, version);
5687c478bd9Sstevel@tonic-gate 				}
569a953e2b1Srie 				/* END CSTYLED */
5707c478bd9Sstevel@tonic-gate 				continue;
5717c478bd9Sstevel@tonic-gate 			}
5737c478bd9Sstevel@tonic-gate 			/*
5747c478bd9Sstevel@tonic-gate 			 * If the version hasn't been found then this is a
5757c478bd9Sstevel@tonic-gate 			 * candidate for a fatal error condition.  Weak
5767c478bd9Sstevel@tonic-gate 			 * version definition requirements are silently
5777c478bd9Sstevel@tonic-gate 			 * ignored.  Also, if the image inspected for a version
5787c478bd9Sstevel@tonic-gate 			 * definition has no versioning recorded at all then
5797c478bd9Sstevel@tonic-gate 			 * silently ignore this (this provides better backward
5807c478bd9Sstevel@tonic-gate 			 * compatibility to old images created prior to
5817c478bd9Sstevel@tonic-gate 			 * versioning being available).  Both of these skipped
5827c478bd9Sstevel@tonic-gate 			 * diagnostics are available under tracing (see above).
5837c478bd9Sstevel@tonic-gate 			 */
5847c478bd9Sstevel@tonic-gate 			if ((found == 0) && (num != 0) &&
5857c478bd9Sstevel@tonic-gate 			    (!(vnap->vna_flags & VER_FLG_WEAK))) {
5865aefb655Srie 				eprintf(lml, ERR_FATAL,
5875aefb655Srie 				    MSG_INTL(MSG_VER_NFOUND), need, version,
5885aefb655Srie 				    NAME(clmp));
5897c478bd9Sstevel@tonic-gate 				return (0);
5907c478bd9Sstevel@tonic-gate 			}
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 	}
59320272c2eSAli Bahrami 	DBG_CALL(Dbg_ver_need_done(lml));
5947c478bd9Sstevel@tonic-gate 	return (1);
5957c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate  * Search through the dynamic section for DT_NEEDED entries and perform one
5997c478bd9Sstevel@tonic-gate  * of two functions.  If only the first argument is specified then load the
6007c478bd9Sstevel@tonic-gate  * defined shared object, otherwise add the link map representing the defined
6017c478bd9Sstevel@tonic-gate  * link map the the dlopen list.
6027c478bd9Sstevel@tonic-gate  */
6037c478bd9Sstevel@tonic-gate static int
elf_needed(Lm_list * lml,Aliste lmco,Rt_map * clmp,int * in_nfavl)6049aa23310Srie elf_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl)
6057c478bd9Sstevel@tonic-gate {
60656deab07SRod Evans 	Alist		*palp = NULL;
607f441771bSRod Evans 	Dyn		*dyn;
608f441771bSRod Evans 	Dyninfo		*dip;
6097c478bd9Sstevel@tonic-gate 	Word		lmflags = lml->lm_flags;
6117c478bd9Sstevel@tonic-gate 	/*
612f441771bSRod Evans 	 * A DYNINFO() structure is created during link-map generation that
613f441771bSRod Evans 	 * parallels the DYN() information, and defines any flags that
614f441771bSRod Evans 	 * influence a dependencies loading.
6157c478bd9Sstevel@tonic-gate 	 */
616f441771bSRod Evans 	for (dyn = DYN(clmp), dip = DYNINFO(clmp);
617f441771bSRod Evans 	    !(dip->di_flags & FLG_DI_IGNORE); dyn++, dip++) {
618f441771bSRod Evans 		uint_t		flags = 0, silent = 0;
619f441771bSRod Evans 		const char	*name = dip->di_name;
620f441771bSRod Evans 		Rt_map		*nlmp = NULL;
622f441771bSRod Evans 		if ((dip->di_flags & FLG_DI_NEEDED) == 0)
623f441771bSRod Evans 			continue;
625f441771bSRod Evans 		/*
626f441771bSRod Evans 		 * Skip any deferred dependencies, unless ldd(1) has forced
627f441771bSRod Evans 		 * their processing.  By default, deferred dependencies are
628f441771bSRod Evans 		 * only processed when an explicit binding to an individual
629f441771bSRod Evans 		 * deferred reference is made.
630f441771bSRod Evans 		 */
631f441771bSRod Evans 		if ((dip->di_flags & FLG_DI_DEFERRED) &&
632f441771bSRod Evans 		    ((rtld_flags & RT_FL_DEFERRED) == 0))
6337c478bd9Sstevel@tonic-gate 			continue;
635f441771bSRod Evans 		/*
636f441771bSRod Evans 		 * NOTE, libc.so.1 can't be lazy loaded.  Although a lazy
637f441771bSRod Evans 		 * position flag won't be produced when a RTLDINFO .dynamic
638f441771bSRod Evans 		 * entry is found (introduced with the UPM in Solaris 10), it
639f441771bSRod Evans 		 * was possible to mark libc for lazy loading on previous
640f441771bSRod Evans 		 * releases.  To reduce the overhead of testing for this
641f441771bSRod Evans 		 * occurrence, only carry out this check for the first object
642f441771bSRod Evans 		 * on the link-map list (there aren't many applications built
643f441771bSRod Evans 		 * without libc).
644f441771bSRod Evans 		 */
645f441771bSRod Evans 		if ((dip->di_flags & FLG_DI_LAZY) && (lml->lm_head == clmp) &&
646f441771bSRod Evans 		    (strcmp(name, MSG_ORIG(MSG_FIL_LIBC)) == 0))
647f441771bSRod Evans 			dip->di_flags &= ~FLG_DI_LAZY;
649f441771bSRod Evans 		/*
650f441771bSRod Evans 		 * Don't bring in lazy loaded objects yet unless we've been
651f441771bSRod Evans 		 * asked to attempt to load all available objects (crle(1) sets
652f441771bSRod Evans 		 * LD_FLAGS=loadavail).  Even under RTLD_NOW we don't process
653f441771bSRod Evans 		 * this - RTLD_NOW will cause relocation processing which in
654f441771bSRod Evans 		 * turn might trigger lazy loading, but its possible that the
655f441771bSRod Evans 		 * object has a lazy loaded file with no bindings (i.e., it
656f441771bSRod Evans 		 * should never have been a dependency in the first place).
657f441771bSRod Evans 		 */
658f441771bSRod Evans 		if (dip->di_flags & FLG_DI_LAZY) {
659f441771bSRod Evans 			if ((lmflags & LML_FLG_LOADAVAIL) == 0) {
660f441771bSRod Evans 				LAZY(clmp)++;
661f441771bSRod Evans 				continue;
662f441771bSRod Evans 			}
6647c478bd9Sstevel@tonic-gate 			/*
665f441771bSRod Evans 			 * Silence any error messages - see description under
666f441771bSRod Evans 			 * elf_lookup_filtee().
6677c478bd9Sstevel@tonic-gate 			 */
668f441771bSRod Evans 			if ((rtld_flags & RT_FL_SILENCERR) == 0) {
669f441771bSRod Evans 				rtld_flags |= RT_FL_SILENCERR;
670f441771bSRod Evans 				silent = 1;
6717c478bd9Sstevel@tonic-gate 			}
6727c478bd9Sstevel@tonic-gate 		}
6745aefb655Srie 		DBG_CALL(Dbg_file_needed(clmp, name));
67675e7992aSrie 		/*
67775e7992aSrie 		 * If we're running under ldd(1), indicate that this dependency
67875e7992aSrie 		 * has been processed.  It doesn't matter whether the object is
67975e7992aSrie 		 * successfully loaded or not, this flag simply ensures that we
68075e7992aSrie 		 * don't repeatedly attempt to load an object that has already
68175e7992aSrie 		 * failed to load.  To do so would create multiple failure
68275e7992aSrie 		 * diagnostics for the same object under ldd(1).
68375e7992aSrie 		 */
6847c478bd9Sstevel@tonic-gate 		if (lml->lm_flags & LML_FLG_TRC_ENABLE)
68575e7992aSrie 			dip->di_flags |= FLG_DI_LDD_DONE;
687f441771bSRod Evans 		/*
688f441771bSRod Evans 		 * Identify any group permission requirements.
689f441771bSRod Evans 		 */
690f441771bSRod Evans 		if (dip->di_flags & FLG_DI_GROUP)
691f441771bSRod Evans 			flags = (FLG_RT_SETGROUP | FLG_RT_PUBHDL);
692f441771bSRod Evans 
6937c478bd9Sstevel@tonic-gate 		/*
6947c478bd9Sstevel@tonic-gate 		 * Establish the objects name, load it and establish a binding
6957c478bd9Sstevel@tonic-gate 		 * with the caller.
6967c478bd9Sstevel@tonic-gate 		 */
69756deab07SRod Evans 		if ((elf_fix_name(name, clmp, &palp, AL_CNT_NEEDED, 0) == 0) ||
69856deab07SRod Evans 		    ((nlmp = load_one(lml, lmco, palp, clmp, MODE(clmp),
69956deab07SRod Evans 		    flags, 0, in_nfavl)) == NULL) ||
70056deab07SRod Evans 		    (bind_one(clmp, nlmp, BND_NEEDED) == 0))
701481bba9eSRod Evans 			nlmp = NULL;
7037c478bd9Sstevel@tonic-gate 		/*
7047c478bd9Sstevel@tonic-gate 		 * Clean up any infrastructure, including the removal of the
7057c478bd9Sstevel@tonic-gate 		 * error suppression state, if it had been previously set in
7067c478bd9Sstevel@tonic-gate 		 * this routine.
7077c478bd9Sstevel@tonic-gate 		 */
7082020b2b6SRod Evans 		remove_alist(&palp, 0);
70956deab07SRod Evans 
7107c478bd9Sstevel@tonic-gate 		if (silent)
7117c478bd9Sstevel@tonic-gate 			rtld_flags &= ~RT_FL_SILENCERR;
713481bba9eSRod Evans 		if ((dip->di_info = (void *)nlmp) == NULL) {
7147c478bd9Sstevel@tonic-gate 			/*
7157c478bd9Sstevel@tonic-gate 			 * If the object could not be mapped, continue if error
7167c478bd9Sstevel@tonic-gate 			 * suppression is established or we're here with ldd(1).
7177c478bd9Sstevel@tonic-gate 			 */
7187c478bd9Sstevel@tonic-gate 			if ((MODE(clmp) & RTLD_CONFGEN) || (lmflags &
7197c478bd9Sstevel@tonic-gate 			    (LML_FLG_LOADAVAIL | LML_FLG_TRC_ENABLE)))
7207c478bd9Sstevel@tonic-gate 				continue;
72156deab07SRod Evans 			else {
7222020b2b6SRod Evans 				remove_alist(&palp, 1);
7237c478bd9Sstevel@tonic-gate 				return (0);
72456deab07SRod Evans 			}
7257c478bd9Sstevel@tonic-gate 		}
7267c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 	if (LAZY(clmp))
7297c478bd9Sstevel@tonic-gate 		lml->lm_lazy++;
7312020b2b6SRod Evans 	remove_alist(&palp, 1);
7327c478bd9Sstevel@tonic-gate 	return (1);
7337c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate  * A null symbol interpretor.  Used if a filter has no associated filtees.
7377c478bd9Sstevel@tonic-gate  */
7387c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
73908278a5eSRod Evans static int
elf_null_find_sym(Slookup * slp,Sresult * srp,uint_t * binfo,int * in_nfavl)74008278a5eSRod Evans elf_null_find_sym(Slookup *slp, Sresult *srp, uint_t *binfo, int *in_nfavl)
7417c478bd9Sstevel@tonic-gate {
74208278a5eSRod Evans 	return (0);
7437c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate /*
7467c478bd9Sstevel@tonic-gate  * Disable filtee use.
7477c478bd9Sstevel@tonic-gate  */
7487c478bd9Sstevel@tonic-gate static void
elf_disable_filtee(Rt_map * lmp,Dyninfo * dip)7499a411307Srie elf_disable_filtee(Rt_map *lmp, Dyninfo *dip)
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate 	if ((dip->di_flags & FLG_DI_SYMFLTR) == 0) {
7527c478bd9Sstevel@tonic-gate 		/*
75356deab07SRod Evans 		 * If this is an object filter, null out the reference name.
7547c478bd9Sstevel@tonic-gate 		 */
7557c478bd9Sstevel@tonic-gate 		if (OBJFLTRNDX(lmp) != FLTR_DISABLED) {
75637ffaf83SRod Evans 			REFNAME(lmp) = NULL;
7577c478bd9Sstevel@tonic-gate 			OBJFLTRNDX(lmp) = FLTR_DISABLED;
7597c478bd9Sstevel@tonic-gate 			/*
7607c478bd9Sstevel@tonic-gate 			 * Indicate that this filtee is no longer available.
7617c478bd9Sstevel@tonic-gate 			 */
7627c478bd9Sstevel@tonic-gate 			if (dip->di_flags & FLG_DI_STDFLTR)
7637c478bd9Sstevel@tonic-gate 				SYMINTP(lmp) = elf_null_find_sym;
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 	} else if (dip->di_flags & FLG_DI_STDFLTR) {
7677c478bd9Sstevel@tonic-gate 		/*
7687c478bd9Sstevel@tonic-gate 		 * Indicate that this standard filtee is no longer available.
7697c478bd9Sstevel@tonic-gate 		 */
7707c478bd9Sstevel@tonic-gate 		if (SYMSFLTRCNT(lmp))
7717c478bd9Sstevel@tonic-gate 			SYMSFLTRCNT(lmp)--;
7727c478bd9Sstevel@tonic-gate 	} else {
7737c478bd9Sstevel@tonic-gate 		/*
7747c478bd9Sstevel@tonic-gate 		 * Indicate that this auxiliary filtee is no longer available.
7757c478bd9Sstevel@tonic-gate 		 */
7767c478bd9Sstevel@tonic-gate 		if (SYMAFLTRCNT(lmp))
7777c478bd9Sstevel@tonic-gate 			SYMAFLTRCNT(lmp)--;
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 	dip->di_flags &= ~MSK_DI_FILTER;
7807c478bd9Sstevel@tonic-gate }
7827c478bd9Sstevel@tonic-gate /*
7837c478bd9Sstevel@tonic-gate  * Find symbol interpreter - filters.
7847c478bd9Sstevel@tonic-gate  * This function is called when the symbols from a shared object should
7857c478bd9Sstevel@tonic-gate  * be resolved from the shared objects filtees instead of from within itself.
7867c478bd9Sstevel@tonic-gate  *
7877c478bd9Sstevel@tonic-gate  * A symbol name of 0 is used to trigger filtee loading.
7887c478bd9Sstevel@tonic-gate  */
78908278a5eSRod Evans static int
_elf_lookup_filtee(Slookup * slp,Sresult * srp,uint_t * binfo,uint_t ndx,int * in_nfavl)79008278a5eSRod Evans _elf_lookup_filtee(Slookup *slp, Sresult *srp, uint_t *binfo, uint_t ndx,
7919aa23310Srie     int *in_nfavl)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate 	const char	*name = slp->sl_name, *filtees;
7947c478bd9Sstevel@tonic-gate 	Rt_map		*clmp = slp->sl_cmap;
7957c478bd9Sstevel@tonic-gate 	Rt_map		*ilmp = slp->sl_imap;
79656deab07SRod Evans 	Pdesc		*pdp;
7977c478bd9Sstevel@tonic-gate 	int		any;
7987c478bd9Sstevel@tonic-gate 	Dyninfo		*dip = &DYNINFO(ilmp)[ndx];
7997c478bd9Sstevel@tonic-gate 	Lm_list		*lml = LIST(ilmp);
80056deab07SRod Evans 	Aliste		idx;
8027c478bd9Sstevel@tonic-gate 	/*
8037c478bd9Sstevel@tonic-gate 	 * Indicate that the filter has been used.  If a binding already exists
8047c478bd9Sstevel@tonic-gate 	 * to the caller, indicate that this object is referenced.  This insures
8057c478bd9Sstevel@tonic-gate 	 * we don't generate false unreferenced diagnostics from ldd -u/U or
8067c478bd9Sstevel@tonic-gate 	 * debugging.  Don't create a binding regardless, as this filter may
8077c478bd9Sstevel@tonic-gate 	 * have been dlopen()'ed.
8087c478bd9Sstevel@tonic-gate 	 */
8097c478bd9Sstevel@tonic-gate 	if (name && (ilmp != clmp)) {
8107c478bd9Sstevel@tonic-gate 		Word	tracing = (LIST(clmp)->lm_flags &
8117c478bd9Sstevel@tonic-gate 		    (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED));
8135aefb655Srie 		if (tracing || DBG_ENABLED) {
81467d74cc3SToomas Soome 			Bnd_desc	*bdp;
815cce0e03bSab 			Aliste		idx;
8177c478bd9Sstevel@tonic-gate 			FLAGS1(ilmp) |= FL1_RT_USED;
8195aefb655Srie 			if ((tracing & LML_FLG_TRC_UNREF) || DBG_ENABLED) {
820cce0e03bSab 				for (APLIST_TRAVERSE(CALLERS(ilmp), idx, bdp)) {
8217c478bd9Sstevel@tonic-gate 					if (bdp->b_caller == clmp) {
8227c478bd9Sstevel@tonic-gate 						bdp->b_flags |= BND_REFER;
8237c478bd9Sstevel@tonic-gate 						break;
8247c478bd9Sstevel@tonic-gate 					}
8257c478bd9Sstevel@tonic-gate 				}
8267c478bd9Sstevel@tonic-gate 			}
8277c478bd9Sstevel@tonic-gate 		}
8287c478bd9Sstevel@tonic-gate 	}
8307c478bd9Sstevel@tonic-gate 	/*
8317c478bd9Sstevel@tonic-gate 	 * If this is the first call to process this filter, establish the
8327c478bd9Sstevel@tonic-gate 	 * filtee list.  If a configuration file exists, determine if any
8337c478bd9Sstevel@tonic-gate 	 * filtee associations for this filter, and its filtee reference, are
8347c478bd9Sstevel@tonic-gate 	 * defined.  Otherwise, process the filtee reference.  Any token
8357c478bd9Sstevel@tonic-gate 	 * expansion is also completed at this point (i.e., $PLATFORM).
8367c478bd9Sstevel@tonic-gate 	 */
837f441771bSRod Evans 	filtees = dip->di_name;
838481bba9eSRod Evans 	if (dip->di_info == NULL) {
83908278a5eSRod Evans 		if (rtld_flags2 & RT_FL2_FLTCFG) {
84056deab07SRod Evans 			elf_config_flt(lml, PATHNAME(ilmp), filtees,
84156deab07SRod Evans 			    (Alist **)&dip->di_info, AL_CNT_FILTEES);
84208278a5eSRod Evans 		}
843481bba9eSRod Evans 		if (dip->di_info == NULL) {
8445aefb655Srie 			DBG_CALL(Dbg_file_filter(lml, NAME(ilmp), filtees, 0));
8457c478bd9Sstevel@tonic-gate 			if ((lml->lm_flags &
8467c478bd9Sstevel@tonic-gate 			    (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH)) &&
8477c478bd9Sstevel@tonic-gate 			    ((FLAGS1(ilmp) & FL1_RT_LDDSTUB) == 0))
8487c478bd9Sstevel@tonic-gate 				(void) printf(MSG_INTL(MSG_LDD_FIL_FILTER),
8497c478bd9Sstevel@tonic-gate 				    NAME(ilmp), filtees);
85156deab07SRod Evans 			if (expand_paths(ilmp, filtees, (Alist **)&dip->di_info,
85256deab07SRod Evans 			    AL_CNT_FILTEES, 0, 0) == 0) {
8537c478bd9Sstevel@tonic-gate 				elf_disable_filtee(ilmp, dip);
85408278a5eSRod Evans 				return (0);
8557c478bd9Sstevel@tonic-gate 			}
8567c478bd9Sstevel@tonic-gate 		}
8577c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 	/*
8607c478bd9Sstevel@tonic-gate 	 * Traverse the filtee list, dlopen()'ing any objects specified and
8617c478bd9Sstevel@tonic-gate 	 * using their group handle to lookup the symbol.
8627c478bd9Sstevel@tonic-gate 	 */
86356deab07SRod Evans 	any = 0;
86456deab07SRod Evans 	for (ALIST_TRAVERSE((Alist *)dip->di_info, idx, pdp)) {
8657c478bd9Sstevel@tonic-gate 		int	mode;
8667c478bd9Sstevel@tonic-gate 		Grp_hdl	*ghp;
867481bba9eSRod Evans 		Rt_map	*nlmp = NULL;
86956deab07SRod Evans 		if (pdp->pd_plen == 0)
8707c478bd9Sstevel@tonic-gate 			continue;
8727c478bd9Sstevel@tonic-gate 		/*
8737c478bd9Sstevel@tonic-gate 		 * Establish the mode of the filtee from the filter.  As filtees
8747c478bd9Sstevel@tonic-gate 		 * are loaded via a dlopen(), make sure that RTLD_GROUP is set
8757c478bd9Sstevel@tonic-gate 		 * and the filtees aren't global.  It would be nice to have
8767c478bd9Sstevel@tonic-gate 		 * RTLD_FIRST used here also, but as filters got out long before
8777c478bd9Sstevel@tonic-gate 		 * RTLD_FIRST was introduced it's a little too late now.
8787c478bd9Sstevel@tonic-gate 		 */
8797c478bd9Sstevel@tonic-gate 		mode = MODE(ilmp) | RTLD_GROUP;
8807c478bd9Sstevel@tonic-gate 		mode &= ~RTLD_GLOBAL;
8827c478bd9Sstevel@tonic-gate 		/*
8837c478bd9Sstevel@tonic-gate 		 * Insure that any auxiliary filter can locate symbols from its
8847c478bd9Sstevel@tonic-gate 		 * caller.
8857c478bd9Sstevel@tonic-gate 		 */
8867c478bd9Sstevel@tonic-gate 		if (dip->di_flags & FLG_DI_AUXFLTR)
8877c478bd9Sstevel@tonic-gate 			mode |= RTLD_PARENT;
8897c478bd9Sstevel@tonic-gate 		/*
89008278a5eSRod Evans 		 * Process any capability directory.  Establish a new link-map
89108278a5eSRod Evans 		 * control list from which to analyze any newly added objects.
8927c478bd9Sstevel@tonic-gate 		 */
89308278a5eSRod Evans 		if ((pdp->pd_info == NULL) && (pdp->pd_flags & PD_TKN_CAP)) {
89456deab07SRod Evans 			const char	*dir = pdp->pd_pname;
89556deab07SRod Evans 			Aliste		lmco;
897dde769a2SRod Evans 			/*
898dde769a2SRod Evans 			 * Establish a link-map control list for this request.
899dde769a2SRod Evans 			 */
90067d74cc3SToomas Soome 			if ((lmco = create_cntl(lml, 0)) == 0)
90167d74cc3SToomas Soome 				return (0);
90356deab07SRod Evans 			/*
90408278a5eSRod Evans 			 * Determine the capability filtees.  If none can be
90508278a5eSRod Evans 			 * found, provide suitable diagnostics.
90656deab07SRod Evans 			 */
90708278a5eSRod Evans 			DBG_CALL(Dbg_cap_filter(lml, dir, ilmp));
90808278a5eSRod Evans 			if (cap_filtees((Alist **)&dip->di_info, idx, dir,
9092020b2b6SRod Evans 			    lmco, ilmp, clmp, filtees, mode,
91008278a5eSRod Evans 			    (FLG_RT_PUBHDL | FLG_RT_CAP), in_nfavl) == 0) {
91156deab07SRod Evans 				if ((lml->lm_flags & LML_FLG_TRC_ENABLE) &&
91256deab07SRod Evans 				    (dip->di_flags & FLG_DI_AUXFLTR) &&
91356deab07SRod Evans 				    (rtld_flags & RT_FL_WARNFLTR)) {
91456deab07SRod Evans 					(void) printf(
91508278a5eSRod Evans 					    MSG_INTL(MSG_LDD_CAP_NFOUND), dir);
91656deab07SRod Evans 				}
91708278a5eSRod Evans 				DBG_CALL(Dbg_cap_filter(lml, dir, 0));
91856deab07SRod Evans 			}
91956deab07SRod Evans 
92056deab07SRod Evans 			/*
92108278a5eSRod Evans 			 * Re-establish the originating path name descriptor,
92208278a5eSRod Evans 			 * as the expansion of capabilities filtees may have
92308278a5eSRod Evans 			 * re-allocated the controlling Alist.  Mark this
92456deab07SRod Evans 			 * original pathname descriptor as unused so that the
92556deab07SRod Evans 			 * descriptor isn't revisited for processing.  Any real
92608278a5eSRod Evans 			 * capabilities filtees have been added as new pathname
92708278a5eSRod Evans 			 * descriptors following this descriptor.
92856deab07SRod Evans 			 */
92956deab07SRod Evans 			pdp = alist_item((Alist *)dip->di_info, idx);
93008278a5eSRod Evans 			pdp->pd_flags &= ~PD_TKN_CAP;
93156deab07SRod Evans 			pdp->pd_plen = 0;
93311a2bb38Srie 			/*
93408278a5eSRod Evans 			 * Now that any capability objects have been processed,
93508278a5eSRod Evans 			 * remove any temporary link-map control list.
93611a2bb38Srie 			 */
937481bba9eSRod Evans 			if (lmco != ALIST_OFF_DATA)
93811a2bb38Srie 				remove_cntl(lml, lmco);
9397c478bd9Sstevel@tonic-gate 		}
94156deab07SRod Evans 		if (pdp->pd_plen == 0)
9427c478bd9Sstevel@tonic-gate 			continue;
9447c478bd9Sstevel@tonic-gate 		/*
9457c478bd9Sstevel@tonic-gate 		 * Process an individual filtee.
9467c478bd9Sstevel@tonic-gate 		 */
947481bba9eSRod Evans 		if (pdp->pd_info == NULL) {
94856deab07SRod Evans 			const char	*filtee = pdp->pd_pname;
9497c478bd9Sstevel@tonic-gate 			int		audit = 0;
9515aefb655Srie 			DBG_CALL(Dbg_file_filtee(lml, NAME(ilmp), filtee, 0));
953481bba9eSRod Evans 			ghp = NULL;
9557c478bd9Sstevel@tonic-gate 			/*
9567c478bd9Sstevel@tonic-gate 			 * Determine if the reference link map is already
9577c478bd9Sstevel@tonic-gate 			 * loaded.  As an optimization compare the filtee with
9587c478bd9Sstevel@tonic-gate 			 * our interpretor.  The most common filter is
9597c478bd9Sstevel@tonic-gate 			 * libdl.so.1, which is a filter on ld.so.1.
9607c478bd9Sstevel@tonic-gate 			 */
9617c478bd9Sstevel@tonic-gate #if	defined(_ELF64)
9627c478bd9Sstevel@tonic-gate 			if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD_64)) == 0) {
9637c478bd9Sstevel@tonic-gate #else
9647c478bd9Sstevel@tonic-gate 			if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD)) == 0) {
9657c478bd9Sstevel@tonic-gate #endif
9662017c965SRod Evans 				uint_t	hflags, rdflags, cdflags;
9672017c965SRod Evans 
9682017c965SRod Evans 				/*
9692017c965SRod Evans 				 * Establish any flags for the handle (Grp_hdl).
9702017c965SRod Evans 				 *
9712017c965SRod Evans 				 *  -	This is a special, public, ld.so.1
9722017c965SRod Evans 				 *	handle.
9732017c965SRod Evans 				 *  -	Only the first object on this handle
9742017c965SRod Evans 				 *	can supply symbols.
9752017c965SRod Evans 				 *  -	This handle provides a filtee.
9762017c965SRod Evans 				 *
9772017c965SRod Evans 				 * Essentially, this handle allows a caller to
9782017c965SRod Evans 				 * reference the dl*() family of interfaces from
9792017c965SRod Evans 				 * ld.so.1.
9802017c965SRod Evans 				 */
9812017c965SRod Evans 				hflags = (GPH_PUBLIC | GPH_LDSO |
9822017c965SRod Evans 				    GPH_FIRST | GPH_FILTEE);
9832017c965SRod Evans 
9842017c965SRod Evans 				/*
9852017c965SRod Evans 				 * Establish the flags for the referenced
9862017c965SRod Evans 				 * dependency descriptor (Grp_desc).
9872017c965SRod Evans 				 *
9882017c965SRod Evans 				 *  -	ld.so.1 is available for dlsym().
9892017c965SRod Evans 				 *  -	ld.so.1 is available to relocate
9902017c965SRod Evans 				 *	against.
9912017c965SRod Evans 				 *  -	There's no need to add an dependencies
99267d74cc3SToomas Soome 				 *	to this handle.
9932017c965SRod Evans 				 */
9942017c965SRod Evans 				rdflags = (GPD_DLSYM | GPD_RELOC);
9952017c965SRod Evans 
9967c478bd9Sstevel@tonic-gate 				/*
9972017c965SRod Evans 				 * Establish the flags for this callers