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 */
2111a2bb38Srie
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 */
317257d1b4Sraf
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate * Object file dependent support for ELF objects.
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@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"
517c478bd9Sstevel@tonic-gate
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 },
6156deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIB), MSG_PTH_USRLIB_SIZE },
627c478bd9Sstevel@tonic-gate #endif
6356deab07SRod Evans { 0, 0 }
647c478bd9Sstevel@tonic-gate };
657c478bd9Sstevel@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 },
6956deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIBSE_64), MSG_PTH_USRLIBSE_64_SIZE },
707c478bd9Sstevel@tonic-gate #else
7156deab07SRod Evans { MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE },
7256deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIBSE), MSG_PTH_USRLIBSE_SIZE },
737c478bd9Sstevel@tonic-gate #endif
7456deab07SRod Evans { 0, 0 }
757c478bd9Sstevel@tonic-gate };
767c478bd9Sstevel@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 *);
907c478bd9Sstevel@tonic-gate
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 };
1087c478bd9Sstevel@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 }
1277c478bd9Sstevel@tonic-gate
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 }
1987c478bd9Sstevel@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;
2107c478bd9Sstevel@tonic-gate
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 }
2237c478bd9Sstevel@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 }
2457c478bd9Sstevel@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 }
2817c478bd9Sstevel@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;
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_PLTREL)
3057c478bd9Sstevel@tonic-gate return (1);
3067c478bd9Sstevel@tonic-gate
3079aa23310Srie if (elf_needed(lml, ALIST_OFF_DATA, lmp, NULL) == 0)
3087c478bd9Sstevel@tonic-gate return (0);
3097c478bd9Sstevel@tonic-gate
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 }
3297c478bd9Sstevel@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;
3437c478bd9Sstevel@tonic-gate
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);
3517c478bd9Sstevel@tonic-gate
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;
36275e7992aSrie
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));
3687c478bd9Sstevel@tonic-gate
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);
3757c478bd9Sstevel@tonic-gate
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;
38875e7992aSrie
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);
3947c478bd9Sstevel@tonic-gate
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 }
4027c478bd9Sstevel@tonic-gate
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);
4087c478bd9Sstevel@tonic-gate
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--;
4177c478bd9Sstevel@tonic-gate
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;
4267c478bd9Sstevel@tonic-gate
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);
4347c478bd9Sstevel@tonic-gate
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);
4407c478bd9Sstevel@tonic-gate
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 }
45075e7992aSrie
4517c478bd9Sstevel@tonic-gate return (nlmp);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@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);
4637c478bd9Sstevel@tonic-gate
46456deab07SRod Evans if ((FLAGS(lmp) & FLG_RT_FIXED) == 0)
46556deab07SRod Evans addr += ADDR(lmp);
4667c478bd9Sstevel@tonic-gate
46756deab07SRod Evans return (addr);
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@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);
4817c478bd9Sstevel@tonic-gate
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;
4927c478bd9Sstevel@tonic-gate
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;
4997c478bd9Sstevel@tonic-gate
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);
5037c478bd9Sstevel@tonic-gate
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);
5097c478bd9Sstevel@tonic-gate
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;
5167c478bd9Sstevel@tonic-gate
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));
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++,
5347c478bd9Sstevel@tonic-gate vdf = (Verdef *)((Xword)vdf + vdf->vd_next)) {
5357c478bd9Sstevel@tonic-gate Verdaux *vdap;
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate if (vnap->vna_hash != vdf->vd_hash)
5387c478bd9Sstevel@tonic-gate continue;
5397c478bd9Sstevel@tonic-gate
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;
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate found++;
5467c478bd9Sstevel@tonic-gate break;
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@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;
5597c478bd9Sstevel@tonic-gate
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;
5657c478bd9Sstevel@tonic-gate
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 }
5727c478bd9Sstevel@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 }
5967c478bd9Sstevel@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;
6107c478bd9Sstevel@tonic-gate
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;
6217c478bd9Sstevel@tonic-gate
622f441771bSRod Evans if ((dip->di_flags & FLG_DI_NEEDED) == 0)
623f441771bSRod Evans continue;
6247c478bd9Sstevel@tonic-gate
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;
6347c478bd9Sstevel@tonic-gate
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;
6487c478bd9Sstevel@tonic-gate
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 }
6637c478bd9Sstevel@tonic-gate
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 }
6737c478bd9Sstevel@tonic-gate
6745aefb655Srie DBG_CALL(Dbg_file_needed(clmp, name));
67575e7992aSrie
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;
6867c478bd9Sstevel@tonic-gate
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;
7027c478bd9Sstevel@tonic-gate
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;
71275e7992aSrie
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 }
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate if (LAZY(clmp))
7297c478bd9Sstevel@tonic-gate lml->lm_lazy++;
7307c478bd9Sstevel@tonic-gate
7312020b2b6SRod Evans remove_alist(&palp, 1);
7327c478bd9Sstevel@tonic-gate return (1);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@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 }
7447c478bd9Sstevel@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;
7587c478bd9Sstevel@tonic-gate
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;
7647c478bd9Sstevel@tonic-gate
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 }
7817c478bd9Sstevel@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;
8017c478bd9Sstevel@tonic-gate
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));
8127c478bd9Sstevel@tonic-gate
8135aefb655Srie if (tracing || DBG_ENABLED) {
81467d74cc3SToomas Soome Bnd_desc *bdp;
815cce0e03bSab Aliste idx;
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate FLAGS1(ilmp) |= FL1_RT_USED;
8187c478bd9Sstevel@tonic-gate
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 }
8297c478bd9Sstevel@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);
8507c478bd9Sstevel@tonic-gate
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 }
8587c478bd9Sstevel@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;
8687c478bd9Sstevel@tonic-gate
86956deab07SRod Evans if (pdp->pd_plen == 0)
8707c478bd9Sstevel@tonic-gate continue;
8717c478bd9Sstevel@tonic-gate
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;
8817c478bd9Sstevel@tonic-gate
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;
8887c478bd9Sstevel@tonic-gate
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;
89611a2bb38Srie
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);
9027c478bd9Sstevel@tonic-gate
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;
93211a2bb38Srie
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 }
9407c478bd9Sstevel@tonic-gate
94156deab07SRod Evans if (pdp->pd_plen == 0)
9427c478bd9Sstevel@tonic-gate continue;
9437c478bd9Sstevel@tonic-gate
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;
9507c478bd9Sstevel@tonic-gate
9515aefb655Srie DBG_CALL(Dbg_file_filtee(lml, NAME(ilmp), filtee, 0));
9527c478bd9Sstevel@tonic-gate
953481bba9eSRod Evans ghp = NULL;
9547c478bd9Sstevel@tonic-gate
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
9982017c965