Mercurial > illumos > illumos-gate
changeset 12650:160f1ef36195
6961755 ld.so.1's -e arguments should take precedence over environment variables.
6748925 moe returns wrong hwcap library in some circumstances
author | Rod Evans <Rod.Evans@Sun.COM> |
---|---|
date | Fri, 18 Jun 2010 13:01:44 -0700 |
parents | 87a8e25df5cf |
children | a33209c74758 |
files | usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/liblddbg/common/cap.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/liblddbg/common/llib-llddbg usr/src/cmd/sgs/liblddbg/common/mapfile-vers usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/rtld/common/_rtld.h usr/src/cmd/sgs/rtld/common/cap.c usr/src/cmd/sgs/rtld/common/rtld.msg usr/src/cmd/sgs/rtld/common/setup.c usr/src/cmd/sgs/rtld/common/util.c |
diffstat | 11 files changed, 481 insertions(+), 322 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/sgs/include/debug.h Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/include/debug.h Fri Jun 18 13:01:44 2010 -0700 @@ -295,6 +295,7 @@ #define Dbg_cap_candidate Dbg64_cap_candidate #define Dbg_cap_filter Dbg64_cap_filter #define Dbg_cap_id Dbg64_cap_id +#define Dbg_cap_identical Dbg64_cap_identical #define Dbg_cap_mapfile_title Dbg64_cap_mapfile_title #define Dbg_cap_post_title Dbg64_cap_post_title #define Dbg_cap_sec_title Dbg64_cap_sec_title @@ -527,6 +528,7 @@ #define Dbg_cap_candidate Dbg32_cap_candidate #define Dbg_cap_filter Dbg32_cap_filter #define Dbg_cap_id Dbg32_cap_id +#define Dbg_cap_identical Dbg32_cap_identical #define Dbg_cap_mapfile_title Dbg32_cap_mapfile_title #define Dbg_cap_post_title Dbg32_cap_post_title #define Dbg_cap_sec_title Dbg32_cap_sec_title @@ -789,6 +791,7 @@ extern void Dbg_cap_candidate(Lm_list *, const char *); extern void Dbg_cap_filter(Lm_list *, const char *, Rt_map *); extern void Dbg_cap_id(Lm_list *, Lineno, const char *, const char *); +extern void Dbg_cap_identical(Lm_list *, const char *, const char *); extern void Dbg_cap_mapfile_title(Lm_list *, Lineno); extern void Dbg_cap_post_title(Lm_list *, int *); extern void Dbg_cap_sec_title(Lm_list *, const char *);
--- a/usr/src/cmd/sgs/liblddbg/common/cap.c Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/cap.c Fri Jun 18 13:01:44 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <stdio.h> @@ -54,6 +53,15 @@ } void +Dbg_cap_identical(Lm_list *lml, const char *file1, const char *file2) +{ + if (DBG_NOTCLASS(DBG_C_CAP | DBG_C_FILES)) + return; + + dbg_print(lml, MSG_INTL(MSG_CAP_IDENTICAL), file1, file2); +} + +void Dbg_cap_val(Lm_list *lml, Syscapset *sys, Syscapset *alt, Half mach) { Conv_cap_val_buf_t cap_val_buf;
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Fri Jun 18 13:01:44 2010 -0700 @@ -1183,6 +1183,9 @@ @ MSG_CAP_FILTER_1 "dir=%s; capability directory filtered by %s" @ MSG_CAP_FILTER_2 "dir=%s; no capability objects found" +@ MSG_CAP_IDENTICAL "obj=%s and obj=%s: have identical capabilities: both \ + objects ignored" + @ MSG_ELF_HEADER "ELF Header" # Capabilities entries.
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg Fri Jun 18 13:01:44 2010 -0700 @@ -78,6 +78,8 @@ void Dbg64_cap_filter(Lm_list *, const char *, Rt_map *); void Dbg32_cap_id(Lm_list *, Lineno, const char *, const char *); void Dbg64_cap_id(Lm_list *, Lineno, const char *, const char *); +void Dbg32_cap_identical(Lm_list *, const char *, const char *); +void Dbg64_cap_identical(Lm_list *, const char *, const char *); void Dbg32_cap_mapfile_title(Lm_list *, Lineno); void Dbg64_cap_mapfile_title(Lm_list *, Lineno); void Dbg32_cap_post_title(Lm_list *, int *);
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers Fri Jun 18 13:01:44 2010 -0700 @@ -40,7 +40,7 @@ # MAPFILE HEADER END # -SUNWprivate_4.80 { +SUNWprivate_4.81 { global: dbg_desc = NODIRECT; # interposed - ld.so.1(1) dbg_print = NODIRECT; # interposed - ld(1) and ld.so.1(1) @@ -88,6 +88,8 @@ Dbg64_cap_filter; Dbg32_cap_id; Dbg64_cap_id; + Dbg32_cap_identical; + Dbg64_cap_identical; Dbg32_cap_mapfile_title; Dbg64_cap_mapfile_title; Dbg32_cap_post_title;
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README Fri Jun 18 13:01:44 2010 -0700 @@ -1592,3 +1592,6 @@ 6954032 Support library with ld_open and -z allextract in snv_139 do not mix 6949596 wrong section alignment generated in joint compilation with shared library +6961755 ld.so.1's -e arguments should take precedence over environment + variables. (D) +6748925 moe returns wrong hwcap library in some circumstances
--- a/usr/src/cmd/sgs/rtld/common/_rtld.h Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/rtld/common/_rtld.h Fri Jun 18 13:01:44 2010 -0700 @@ -161,6 +161,7 @@ #define AL_CNT_PENDING 2 /* pending tsort list (INITFIRST) */ #define AL_CNT_PLTPAD 10 /* plt padding */ #define AL_CNT_AUDITORS 2 /* auditing list */ +#define AL_CNT_ENVIRON 20 /* environment list (enough for ldd) */ /* * Size of buffer for building error messages. @@ -226,6 +227,7 @@ */ struct fdesc { Rt_map *fd_lmp; /* existing link-map pointer */ + Lm_list *fd_lml; /* callers link-map list */ Fct *fd_ftp; /* file functions pointer */ const char *fd_oname; /* original file name */ const char *fd_odir; /* original directory name */ @@ -233,11 +235,11 @@ const char *fd_pname; /* new path (resolved) name */ dev_t fd_dev; /* file device number */ rtld_ino_t fd_ino; /* file inode number */ - uint_t fd_flags; avl_index_t fd_avlwhere; /* avl tree insertion index */ Syscapset fd_scapset; /* capabilities */ mmapobj_result_t *fd_mapp; /* mapping pointer */ uint_t fd_mapn; /* mapping number */ + uint_t fd_flags; }; #define FLG_FD_ALTER 0x0001 /* file is an alternate */ @@ -247,6 +249,7 @@ /* checked */ #define FLG_FD_ALTCAP 0x0010 /* alternative system capabilities */ /* should be used */ +#define FLG_FD_IGNORE 0x0020 /* descriptor should be ignored */ /* * File descriptor availability flag. @@ -274,9 +277,10 @@ #define RT_FL_NOVERSION 0x00000020 /* disable version checking */ #define RT_FL_SECURE 0x00000040 /* setuid/segid flag */ #define RT_FL_APPLIC 0x00000080 /* are we executing user code */ - +#define RT_FL_NOENVIRON 0x00000100 /* don't process environment */ + /* variables (ld.so.1 -e) */ #define RT_FL_CONFGEN 0x00000200 /* don't relocate initiating object */ - /* set by crle(1). */ + /* set by crle(1) */ #define RT_FL_CONFAPP 0x00000400 /* application specific configuration */ /* cache required */ #define RT_FL_DEBUGGER 0x00000800 /* a debugger is monitoring us */ @@ -720,8 +724,9 @@ extern void platform_name(Syscapset *); extern int pnavl_recorded(avl_tree_t **, const char *, uint_t, avl_index_t *); +extern int procenv_user(APlist *, Word *, Word *, int); extern void rd_event(Lm_list *, rd_event_e, r_state_e); -extern int readenv_user(const char **, Word *, Word *, int); +extern int readenv_user(const char **, APlist **); extern int readenv_config(Rtc_env *, Addr, int); extern void rejection_inherit(Rej_desc *, Rej_desc *); extern int relocate_lmc(Lm_list *, Aliste, Rt_map *, Rt_map *,
--- a/usr/src/cmd/sgs/rtld/common/cap.c Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/rtld/common/cap.c Fri Jun 18 13:01:44 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -43,16 +42,17 @@ * qsort(3c) capability comparison function. */ static int -compare(const void *fdp_a, const void *fdp_b) +compare(const void *vp_a, const void *vp_b) { + Fdesc *fdp_a = (Fdesc *)vp_a, *fdp_b = (Fdesc *)vp_b; char *strcap_a, *strcap_b; Xword hwcap_a, hwcap_b; /* * First, investigate any platform capability. */ - strcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_plat; - strcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_plat; + strcap_a = fdp_a->fd_scapset.sc_plat; + strcap_b = fdp_b->fd_scapset.sc_plat; if (strcap_a && (strcap_b == NULL)) return (-1); @@ -62,8 +62,8 @@ /* * Second, investigate any machine capability. */ - strcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_mach; - strcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_mach; + strcap_a = fdp_a->fd_scapset.sc_mach; + strcap_b = fdp_b->fd_scapset.sc_mach; if (strcap_a && (strcap_b == NULL)) return (-1); @@ -73,8 +73,8 @@ /* * Third, investigate any CA_SUNW_HW_2 hardware capabilities. */ - hwcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_hw_2; - hwcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_hw_2; + hwcap_a = fdp_a->fd_scapset.sc_hw_2; + hwcap_b = fdp_b->fd_scapset.sc_hw_2; if (hwcap_a > hwcap_b) return (-1); @@ -84,14 +84,29 @@ /* * Finally, investigate any CA_SUNW_HW_1 hardware capabilities. */ - hwcap_a = ((Fdesc *)fdp_a)->fd_scapset.sc_hw_1; - hwcap_b = ((Fdesc *)fdp_b)->fd_scapset.sc_hw_1; + hwcap_a = fdp_a->fd_scapset.sc_hw_1; + hwcap_b = fdp_b->fd_scapset.sc_hw_1; if (hwcap_a > hwcap_b) return (-1); if (hwcap_a < hwcap_b) return (1); + /* + * Normally, a capabilities directory contains one or more capabilities + * files, each with different capabilities. The role of ld.so.1 is to + * select the best candidate from these variants. However, we've come + * across cases where files containing the same capabilities have been + * placed in the same capabilities directory. As we can't tell which + * file is the best, we select neither, and diagnose this suspicious + * scenario. + */ + DBG_CALL(Dbg_cap_identical(fdp_a->fd_lml, fdp_a->fd_nname, + fdp_b->fd_nname)); + + fdp_a->fd_flags |= FLG_FD_IGNORE; + fdp_b->fd_flags |= FLG_FD_IGNORE; + return (0); } @@ -442,7 +457,8 @@ * (soname), however try all of the names that this file is * known by. */ - if ((file = strrchr(fdp->fd_oname, '/')) != NULL) + if (fdp->fd_oname && + ((file = strrchr(fdp->fd_oname, '/')) != NULL)) file++; else file = NULL; @@ -504,6 +520,8 @@ DIR *dir; struct dirent *dirent; Alist *fdalp = NULL; + Aliste idx; + Fdesc *fdp; int error = 0; /* @@ -579,6 +597,7 @@ */ if (fd.fd_lmp) fd.fd_scapset = CAPSET(fd.fd_lmp); + fd.fd_lml = lml; /* * Duplicate the original name, as this may be required for @@ -612,6 +631,21 @@ */ qsort(fdalp->al_data, fdalp->al_nitems, fdalp->al_size, compare); + /* + * If any objects were found to have the same capabilities, then these + * objects must be rejected, as we can't tell which object is more + * appropriate. + */ + for (ALIST_TRAVERSE(fdalp, idx, fdp)) { + if (fdp->fd_flags & FLG_FD_IGNORE) + alist_delete(fdalp, &idx); + } + + if (fdalp->al_nitems == 0) { + free_fd(fdalp); + return (0); + } + *fdalpp = fdalp; return (1); }
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/rtld/common/rtld.msg Fri Jun 18 13:01:44 2010 -0700 @@ -296,6 +296,7 @@ @ MSG_STR_NL "\n" @ MSG_STR_SLASH "/" @ MSG_STR_DELIMIT ": " +@ MSG_STR_ONE "1" @ MSG_CAP_DELIMIT "," @@ -378,6 +379,7 @@ @ MSG_LD_NODIRCONFIG "NODIRCONFIG" @ MSG_LD_NODIRECT "NODIRECT" @ MSG_LD_NOENVCONFIG "NOENVCONFIG" +@ MSG_LD_NOENVIRON "NOENVIRON" @ MSG_LD_NOFLTCONFIG "NOFLTCONFIG" @ MSG_LD_NOLAZY "NOLAZYLOAD" @ MSG_LD_NOOBJALTER "NOOBJALTER"
--- a/usr/src/cmd/sgs/rtld/common/setup.c Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/rtld/common/setup.c Fri Jun 18 13:01:44 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -204,6 +203,7 @@ mmapobj_result_t *mpp; Fdesc fdr = { 0 }, fdm = { 0 }; Rej_desc rej = { 0 }; + APlist *ealp = NULL; /* * Now that ld.so has relocated itself, initialize our own 'environ' so @@ -344,25 +344,68 @@ security(uid, euid, gid, egid, auxflags); /* - * Look for environment strings (allows things like LD_NOAUDIT to be - * established, although debugging isn't enabled until later). + * Make an initial pass of environment variables to pick off those + * related to locale processing. At the same time, collect and save + * any LD_XXXX variables for later processing. Note that this later + * processing will be skipped if ld.so.1 is invoked from the command + * line with -e LD_NOENVIRON. + */ + if (envp && (readenv_user((const char **)envp, &ealp) == 1)) + return (0); + + /* + * If ld.so.1 has been invoked directly, process its arguments. */ - if ((readenv_user((const char **)envp, &(lml_main.lm_flags), - &(lml_main.lm_tflags), (aoutdyn != 0))) == 1) - return (0); + if (ldsoexec) { + /* + * Process any arguments that are specific to ld.so.1, and + * reorganize the process stack to effectively remove ld.so.1 + * from the stack. Reinitialize the environment pointer, as + * this pointer may have been shifted after skipping ld.so.1's + * arguments. + */ + if (rtld_getopt(argv, &envp, &auxv, &(lml_main.lm_flags), + &(lml_main.lm_tflags), (aoutdyn != 0)) == 1) { + eprintf(&lml_main, ERR_NONE, MSG_INTL(MSG_USG_BADOPT)); + return (0); + } + _environ = envp; + + /* + * Open the object that ld.so.1 is to execute. + */ + argvname = execname = argv[0]; + + if ((fd = open(argvname, O_RDONLY)) == -1) { + int err = errno; + eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), + argvname, strerror(err)); + return (0); + } + } + + /* + * Having processed any ld.so.1 command line options, return to process + * any LD_XXXX environment variables. + */ + if (ealp) { + if (((rtld_flags & RT_FL_NOENVIRON) == 0) && + (procenv_user(ealp, &(lml_main.lm_flags), + &(lml_main.lm_tflags), (aoutdyn != 0)) == 1)) + return (0); + free(ealp); + } /* * Initialize a hardware capability descriptor for use in comparing * each loaded object. The aux vector must provide AF_SUN_HWCAPVERIFY, * as prior to this setting any hardware capabilities that were found - * could not be relied upon. Set any alternative system capabilities. + * could not be relied upon. */ if (auxflags & AF_SUN_HWCAPVERIFY) { rtld_flags2 |= RT_FL2_HWCAP; org_scapset->sc_hw_1 = (Xword)hwcap_1; } - if (cap_alternative() == 0) - return (0); /* * Create a mapping descriptor for ld.so.1. We can determine our @@ -406,36 +449,6 @@ ldso_plt_init(rlmp); /* - * If ld.so.1 has been invoked directly, process its arguments. - */ - if (ldsoexec) { - /* - * Process any arguments that are specific to ld.so.1, and - * reorganize the process stack to effectively remove ld.so.1 - * from it. Reinitialize the environment pointer, as this may - * have been shifted after skipping ld.so.1's arguments. - */ - if (rtld_getopt(argv, &envp, &auxv, &(lml_main.lm_flags), - &(lml_main.lm_tflags), (aoutdyn != 0)) == 1) { - eprintf(&lml_main, ERR_NONE, MSG_INTL(MSG_USG_BADOPT)); - return (0); - } - _environ = envp; - - /* - * Open the object that ld.so.1 is to execute. - */ - argvname = execname = argv[0]; - - if ((fd = open(argvname, O_RDONLY)) == -1) { - int err = errno; - eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), - argvname, strerror(err)); - return (0); - } - } - - /* * Map in the file, if exec has not already done so, or if the file * was passed as an argument to an explicit execution of ld.so.1 from * the command line. @@ -446,6 +459,7 @@ * the file descriptor. */ (void) rtld_fstat(fd, &status); + fdm.fd_oname = argvname; fdm.fd_ftp = map_obj(&lml_main, &fdm, status.st_size, argvname, fd, &rej); (void) close(fd); @@ -724,34 +738,6 @@ return (0); procname = str; -#if defined(_ELF64) - /* - * If this is a 64-bit process, determine whether this process has - * restricted the process address space to 32-bits. Any dependencies - * that are restricted to a 32-bit address space can only be loaded if - * the executable has established this requirement. - */ - if (CAPSET(mlmp).sc_sf_1 & SF1_SUNW_ADDR32) - rtld_flags2 |= RT_FL2_ADDR32; -#endif - /* - * Establish any alternative capabilities, and validate this object - * if it defines it's own capabilities information. - */ - if (cap_check_lmp(mlmp, &rej) == 0) { - if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) { - /* LINTED */ - (void) printf(MSG_INTL(ldd_warn[rej.rej_type]), - NAME(mlmp), rej.rej_str); - } else { - /* LINTED */ - eprintf(&lml_main, ERR_FATAL, - MSG_INTL(err_reject[rej.rej_type]), - NAME(mlmp), rej.rej_str); - return (0); - } - } - FLAGS(mlmp) |= (FLG_RT_ISMAIN | FLG_RT_MODESET); FLAGS1(mlmp) |= FL1_RT_USED; @@ -825,9 +811,37 @@ if (!(rtld_flags & RT_FL_NOCFG)) { if ((features = elf_config(mlmp, (aoutdyn != 0))) == -1) return (0); + } - if (cap_alternative() == 0) +#if defined(_ELF64) + /* + * If this is a 64-bit process, determine whether this process has + * restricted the process address space to 32-bits. Any dependencies + * that are restricted to a 32-bit address space can only be loaded if + * the executable has established this requirement. + */ + if (CAPSET(mlmp).sc_sf_1 & SF1_SUNW_ADDR32) + rtld_flags2 |= RT_FL2_ADDR32; +#endif + /* + * Establish any alternative capabilities, and validate this object + * if it defines it's own capabilities information. + */ + if (cap_alternative() == 0) + return (0); + + if (cap_check_lmp(mlmp, &rej) == 0) { + if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) { + /* LINTED */ + (void) printf(MSG_INTL(ldd_warn[rej.rej_type]), + NAME(mlmp), rej.rej_str); + } else { + /* LINTED */ + eprintf(&lml_main, ERR_FATAL, + MSG_INTL(err_reject[rej.rej_type]), + NAME(mlmp), rej.rej_str); return (0); + } } /*
--- a/usr/src/cmd/sgs/rtld/common/util.c Fri Jun 18 11:22:27 2010 -0700 +++ b/usr/src/cmd/sgs/rtld/common/util.c Fri Jun 18 13:01:44 2010 -0700 @@ -52,8 +52,6 @@ #include "_elf.h" #include "msg.h" -static int ld_flags_env(const char *, Word *, Word *, uint_t, int); - /* * Null function used as place where a debugger can set a breakpoint. */ @@ -281,62 +279,6 @@ #endif /* - * The only command line argument recognized is -e, followed by a runtime - * linker environment variable. - */ -int -rtld_getopt(char **argv, char ***envp, auxv_t **auxv, Word *lmflags, - Word *lmtflags, int aout) -{ - int ndx; - - for (ndx = 1; argv[ndx]; ndx++) { - char *str; - - if (argv[ndx][0] != '-') - break; - - if (argv[ndx][1] == '\0') { - ndx++; - break; - } - - if (argv[ndx][1] != 'e') - return (1); - - if (argv[ndx][2] == '\0') { - ndx++; - if (argv[ndx] == NULL) - return (1); - str = argv[ndx]; - } else - str = &argv[ndx][2]; - - /* - * If the environment variable starts with LD_, strip the LD_. - * Otherwise, take things as is. - */ - if ((str[0] == 'L') && (str[1] == 'D') && (str[2] == '_') && - (str[3] != '\0')) - str += 3; - if (ld_flags_env(str, lmflags, lmtflags, 0, aout) == 1) - return (1); - } - - /* - * Make sure an object file has been specified. - */ - if (argv[ndx] == NULL) - return (1); - - /* - * Having gotten the arguments, clean ourselves off of the stack. - */ - stack_cleanup(argv, envp, auxv, ndx); - return (0); -} - -/* * Compare function for PathNode AVL tree. */ static int @@ -748,7 +690,6 @@ } } - /* * Execute any .init sections. These are passed to us in an lmp array which * (by default) will have been sorted. @@ -1018,7 +959,6 @@ leave(&lml_main, 0); } - /* * This routine is called to complete any runtime linker activity which may have * resulted in objects being loaded. This is called from all user entry points @@ -1399,24 +1339,30 @@ * Environment variables can be defined without a value (ie. LD_XXXX=) so as to * override any replaceable environment variables from a configuration file. */ -static u_longlong_t rplgen; /* replaceable generic */ +static u_longlong_t rplgen = 0; /* replaceable generic */ /* variables */ -static u_longlong_t rplisa; /* replaceable ISA specific */ +static u_longlong_t rplisa = 0; /* replaceable ISA specific */ + /* variables */ +static u_longlong_t prmgen = 0; /* permanent generic */ /* variables */ -static u_longlong_t prmgen; /* permanent generic */ +static u_longlong_t prmisa = 0; /* permanent ISA specific */ /* variables */ -static u_longlong_t prmisa; /* permanent ISA specific */ +static u_longlong_t cmdgen = 0; /* command line (-e) generic */ /* variables */ +static u_longlong_t cmdisa = 0; /* command line (-e) ISA */ + /* specific variables */ /* * Classify an environment variables type. */ -#define ENV_TYP_IGNORE 0x1 /* ignore - variable is for */ +#define ENV_TYP_IGNORE 0x01 /* ignore - variable is for */ /* the wrong ISA */ -#define ENV_TYP_ISA 0x2 /* variable is ISA specific */ -#define ENV_TYP_CONFIG 0x4 /* variable obtained from a */ +#define ENV_TYP_ISA 0x02 /* variable is ISA specific */ +#define ENV_TYP_CONFIG 0x04 /* variable obtained from a */ /* config file */ -#define ENV_TYP_PERMANT 0x8 /* variable is permanent */ +#define ENV_TYP_PERMANT 0x08 /* variable is permanent */ +#define ENV_TYP_CMDLINE 0x10 /* variable provide with -e */ +#define ENV_TYP_NULL 0x20 /* variable is null */ /* * Identify all environment variables. @@ -1466,6 +1412,7 @@ #define ENV_FLG_PLATCAP 0x0040000000000ULL #define ENV_FLG_CAP_FILES 0x0080000000000ULL #define ENV_FLG_DEFERRED 0x0100000000000ULL +#define ENV_FLG_NOENVIRON 0x0200000000000ULL #define SEL_REPLACE 0x0001 #define SEL_PERMANT 0x0002 @@ -1779,6 +1726,14 @@ select |= SEL_ACT_LML; val = LML_FLG_TRC_NOPAREXT; variable = ENV_FLG_NOPAREXT; + } else if ((len == MSG_LD_NOENVIRON_SIZE) && (strncmp(s1, + MSG_ORIG(MSG_LD_NOENVIRON), MSG_LD_NOENVIRON_SIZE) == 0)) { + /* + * LD_NOENVIRON can only be set with ld.so.1 -e. + */ + select |= SEL_ACT_RT; + val = RT_FL_NOENVIRON; + variable = ENV_FLG_NOENVIRON; } } /* @@ -1929,6 +1884,22 @@ return; /* + * If this variable has already been set via the command line, then + * ignore this variable. The command line, -e, takes precedence. + */ + if (env_flags & ENV_TYP_ISA) { + if (cmdisa & variable) + return; + if (env_flags & ENV_TYP_CMDLINE) + cmdisa |= variable; + } else { + if (cmdgen & variable) + return; + if (env_flags & ENV_TYP_CMDLINE) + cmdgen |= variable; + } + + /* * Mark the appropriate variables. */ if (env_flags & ENV_TYP_ISA) { @@ -1968,7 +1939,10 @@ else rtld_flags2 &= ~val; } else if (select & SEL_ACT_STR) { - *str = s2; + if (env_flags & ENV_TYP_NULL) + *str = NULL; + else + *str = s2; } else if (select & SEL_ACT_LML) { if (s2) *lmflags |= val; @@ -1983,7 +1957,10 @@ /* * variable is either ENV_FLG_FLAGS or ENV_FLG_LIBPATH */ - *str = s2; + if (env_flags & ENV_TYP_NULL) + *str = NULL; + else + *str = s2; if ((select & SEL_REPLACE) && (env_flags & ENV_TYP_CONFIG)) { if (s2) { if (variable == ENV_FLG_FLAGS) @@ -2109,13 +2086,14 @@ return (0); } - /* * Process an LD_FLAGS environment variable. The value can be a comma * separated set of tokens, which are sent (in upper case) into the generic * LD_XXXX environment variable engine. For example: * + * LD_FLAGS=bind_now= -> LD_BIND_NOW= * LD_FLAGS=bind_now -> LD_BIND_NOW=1 + * LD_FLAGS=library_path= -> LD_LIBRARY_PATH= * LD_FLAGS=library_path=/foo:. -> LD_LIBRARY_PATH=/foo:. * LD_FLAGS=debug=files:detail -> LD_DEBUG=files:detail * or @@ -2141,7 +2119,7 @@ (void) strcpy(nstr, str); for (sstr = nstr; sstr; sstr++, len--) { - int flags; + int flags = 0; if ((*sstr != '\0') && (*sstr != ',')) { if (estr == NULL) { @@ -2161,129 +2139,34 @@ } *sstr = '\0'; - if (estr) { - nlen = estr - nstr; - if ((*++estr == '\0') || (*estr == ',')) - estr = NULL; - } else - nlen = sstr - nstr; - - /* - * Fabricate a boolean definition for any unqualified variable. - * Thus LD_FLAGS=bind_now is represented as BIND_NOW=(null). - * The value is sufficient to assert any boolean variables, plus - * the term "(null)" is specifically chosen in case someone - * mistakenly supplies something like LD_FLAGS=library_path. - */ - if (estr == NULL) - estr = (char *)MSG_INTL(MSG_STR_NULL); /* - * Determine whether the environment variable is 32- or 64-bit - * specific. The length, len, will reflect the architecture - * neutral portion of the string. + * Have we discovered an "=" string. */ - if ((flags = ld_arch_env(nstr, &nlen)) != ENV_TYP_IGNORE) { - ld_generic_env(nstr, nlen, estr, lmflags, - lmtflags, (env_flags | flags), aout); - } - if (len == 0) - return (0); - - nstr = sstr + 1; - estr = NULL; - } - return (0); -} - - -/* - * Process a single environment string. Only strings starting with `LD_' are - * reserved for our use. By convention, all strings should be of the form - * `LD_XXXX=', if the string is followed by a non-null value the appropriate - * functionality is enabled. Also pick off applicable locale variables. - */ -#define LOC_LANG 1 -#define LOC_MESG 2 -#define LOC_ALL 3 - -static void -ld_str_env(const char *s1, Word *lmflags, Word *lmtflags, uint_t env_flags, - int aout) -{ - const char *s2; - static size_t loc = 0; - - if (*s1++ != 'L') - return; - - /* - * See if we have any locale environment settings. These environment - * variables have a precedence, LC_ALL is higher than LC_MESSAGES which - * is higher than LANG. - */ - s2 = s1; - if ((*s2++ == 'C') && (*s2++ == '_') && (*s2 != '\0')) { - if (strncmp(s2, MSG_ORIG(MSG_LC_ALL), MSG_LC_ALL_SIZE) == 0) { - s2 += MSG_LC_ALL_SIZE; - if ((*s2 != '\0') && (loc < LOC_ALL)) { - glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2; - loc = LOC_ALL; - } - } else if (strncmp(s2, MSG_ORIG(MSG_LC_MESSAGES), - MSG_LC_MESSAGES_SIZE) == 0) { - s2 += MSG_LC_MESSAGES_SIZE; - if ((*s2 != '\0') && (loc < LOC_MESG)) { - glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2; - loc = LOC_MESG; - } - } - return; - } - - s2 = s1; - if ((*s2++ == 'A') && (*s2++ == 'N') && (*s2++ == 'G') && - (*s2++ == '=') && (*s2 != '\0') && (loc < LOC_LANG)) { - glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2; - loc = LOC_LANG; - return; - } - - /* - * Pick off any LD_XXXX environment variables. - */ - if ((*s1++ == 'D') && (*s1++ == '_') && (*s1 != '\0')) { - size_t len; - int flags; - - /* - * In a branded process we must ignore all LD_XXXX env vars - * because they are intended for the brand's linker. - * To affect the Solaris linker, use LD_BRAND_XXXX instead. - */ - if (rtld_flags2 & RT_FL2_BRANDED) { - if (strncmp(s1, MSG_ORIG(MSG_LD_BRAND_PREFIX), - MSG_LD_BRAND_PREFIX_SIZE) != 0) - return; - s1 += MSG_LD_BRAND_PREFIX_SIZE; - } - - /* - * Environment variables with no value (ie. LD_XXXX=) typically - * have no impact, however if environment variables are defined - * within a configuration file, these null user settings can be - * used to disable any configuration replaceable definitions. - */ - if ((s2 = strchr(s1, '=')) == NULL) { - len = strlen(s1); - s2 = NULL; - } else if (*++s2 == '\0') { - len = strlen(s1) - 1; - s2 = NULL; + if (estr) { + nlen = estr - nstr; + + /* + * If this is an unqualified "=", then this variable + * is intended to ensure a feature is disabled. + */ + if ((*++estr == '\0') || (*estr == ',')) + estr = NULL; } else { - len = s2 - s1 - 1; - while (conv_strproc_isspace(*s2)) - s2++; + nlen = sstr - nstr; + + /* + * If there is no "=" found, fabricate a boolean + * definition for any unqualified variable. Thus, + * LD_FLAGS=bind_now is represented as BIND_NOW=1. + * The value "1" is sufficient to assert any boolean + * variables. Setting of ENV_TYP_NULL ensures any + * string usage is reset to a NULL string, thus + * LD_FLAGS=library_path is equivalent to + * LIBRARY_PATH='\0'. + */ + flags |= ENV_TYP_NULL; + estr = (char *)MSG_ORIG(MSG_STR_ONE); } /* @@ -2291,35 +2174,244 @@ * specific. The length, len, will reflect the architecture * neutral portion of the string. */ - if ((flags = ld_arch_env(s1, &len)) == ENV_TYP_IGNORE) + if ((flags |= ld_arch_env(nstr, &nlen)) != ENV_TYP_IGNORE) { + ld_generic_env(nstr, nlen, estr, lmflags, + lmtflags, (env_flags | flags), aout); + } + if (len == 0) + break; + + nstr = sstr + 1; + estr = NULL; + } + + return (0); +} + +/* + * Variant of getopt(), intended for use when ld.so.1 is invoked directly + * from the command line. The only command line option allowed is -e followed + * by a runtime linker environment variable. + */ +int +rtld_getopt(char **argv, char ***envp, auxv_t **auxv, Word *lmflags, + Word *lmtflags, int aout) +{ + int ndx; + + for (ndx = 1; argv[ndx]; ndx++) { + char *str; + + if (argv[ndx][0] != '-') + break; + + if (argv[ndx][1] == '\0') { + ndx++; + break; + } + + if (argv[ndx][1] != 'e') + return (1); + + if (argv[ndx][2] == '\0') { + ndx++; + if (argv[ndx] == NULL) + return (1); + str = argv[ndx]; + } else + str = &argv[ndx][2]; + + /* + * If the environment variable starts with LD_, strip the LD_. + * Otherwise, take things as is. Indicate that this variable + * originates from the command line, as these variables take + * precedence over any environment variables, or configuration + * file variables. + */ + if ((str[0] == 'L') && (str[1] == 'D') && (str[2] == '_') && + (str[3] != '\0')) + str += 3; + if (ld_flags_env(str, lmflags, lmtflags, + ENV_TYP_CMDLINE, aout) == 1) + return (1); + } + + /* + * Make sure an object file has been specified. + */ + if (argv[ndx] == NULL) + return (1); + + /* + * Having gotten the arguments, clean ourselves off of the stack. + * This results in a process that looks as if it was executed directly + * from the application. + */ + stack_cleanup(argv, envp, auxv, ndx); + return (0); +} + +/* + * Process a single LD_XXXX string. + */ +static void +ld_str_env(const char *s1, Word *lmflags, Word *lmtflags, uint_t env_flags, + int aout) +{ + const char *s2; + size_t len; + int flags; + + /* + * In a branded process we must ignore all LD_XXXX variables because + * they are intended for the brand's linker. To affect the native + * linker, use LD_BRAND_XXXX instead. + */ + if (rtld_flags2 & RT_FL2_BRANDED) { + if (strncmp(s1, MSG_ORIG(MSG_LD_BRAND_PREFIX), + MSG_LD_BRAND_PREFIX_SIZE) != 0) return; - env_flags |= flags; - - ld_generic_env(s1, len, s2, lmflags, lmtflags, env_flags, aout); + s1 += MSG_LD_BRAND_PREFIX_SIZE; } + + /* + * Variables with no value (ie. LD_XXXX=) turn a capability off. + */ + if ((s2 = strchr(s1, '=')) == NULL) { + len = strlen(s1); + s2 = NULL; + } else if (*++s2 == '\0') { + len = strlen(s1) - 1; + s2 = NULL; + } else { + len = s2 - s1 - 1; + while (conv_strproc_isspace(*s2)) + s2++; + } + + /* + * Determine whether the environment variable is 32-bit or 64-bit + * specific. The length, len, will reflect the architecture neutral + * portion of the string. + */ + if ((flags = ld_arch_env(s1, &len)) == ENV_TYP_IGNORE) + return; + env_flags |= flags; + + ld_generic_env(s1, len, s2, lmflags, lmtflags, env_flags, aout); } /* * Internal getenv routine. Called immediately after ld.so.1 initializes - * itself. + * itself to process any locale specific environment variables, and collect + * any LD_XXXX variables for later processing. + */ +#define LOC_LANG 1 +#define LOC_MESG 2 +#define LOC_ALL 3 + +int +readenv_user(const char **envp, APlist **ealpp) +{ + char *locale; + const char *s1; + int loc = 0; + + for (s1 = *envp; s1; envp++, s1 = *envp) { + const char *s2; + + if (*s1++ != 'L') + continue; + + /* + * See if we have any locale environment settings. These + * environment variables have a precedence, LC_ALL is higher + * than LC_MESSAGES which is higher than LANG. + */ + s2 = s1; + if ((*s2++ == 'C') && (*s2++ == '_') && (*s2 != '\0')) { + if (strncmp(s2, MSG_ORIG(MSG_LC_ALL), + MSG_LC_ALL_SIZE) == 0) { + s2 += MSG_LC_ALL_SIZE; + if ((*s2 != '\0') && (loc < LOC_ALL)) { + glcs[CI_LCMESSAGES].lc_un.lc_ptr = + (char *)s2; + loc = LOC_ALL; + } + } else if (strncmp(s2, MSG_ORIG(MSG_LC_MESSAGES), + MSG_LC_MESSAGES_SIZE) == 0) { + s2 += MSG_LC_MESSAGES_SIZE; + if ((*s2 != '\0') && (loc < LOC_MESG)) { + glcs[CI_LCMESSAGES].lc_un.lc_ptr = + (char *)s2; + loc = LOC_MESG; + } + } + continue; + } + + s2 = s1; + if ((*s2++ == 'A') && (*s2++ == 'N') && (*s2++ == 'G') && + (*s2++ == '=') && (*s2 != '\0') && (loc < LOC_LANG)) { + glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2; + loc = LOC_LANG; + continue; + } + + /* + * Pick off any LD_XXXX environment variables. + */ + if ((*s1++ == 'D') && (*s1++ == '_') && (*s1 != '\0')) { + if (aplist_append(ealpp, s1, AL_CNT_ENVIRON) == NULL) + return (1); + } + } + + /* + * If we have a locale setting make sure it's worth processing further. + * C and POSIX locales don't need any processing. In addition, to + * ensure no one escapes the /usr/lib/locale hierarchy, don't allow + * the locale to contain a segment that leads upward in the file system + * hierarchy (i.e. no '..' segments). Given that we'll be confined to + * the /usr/lib/locale hierarchy, there is no need to extensively + * validate the mode or ownership of any message file (as libc's + * generic handling of message files does), or be concerned with + * symbolic links that might otherwise send us elsewhere. Duplicate + * the string so that new locale setting can generically cleanup any + * previous locales. + */ + if ((locale = glcs[CI_LCMESSAGES].lc_un.lc_ptr) != NULL) { + if (((*locale == 'C') && (*(locale + 1) == '\0')) || + (strcmp(locale, MSG_ORIG(MSG_TKN_POSIX)) == 0) || + (strstr(locale, MSG_ORIG(MSG_TKN_DOTDOT)) != NULL)) + glcs[CI_LCMESSAGES].lc_un.lc_ptr = NULL; + else + glcs[CI_LCMESSAGES].lc_un.lc_ptr = strdup(locale); + } + return (0); +} + +/* + * Process any LD_XXXX environment variables collected by readenv_user(). */ int -readenv_user(const char **envp, Word *lmflags, Word *lmtflags, int aout) +procenv_user(APlist *ealp, Word *lmflags, Word *lmtflags, int aout) { - char *locale; - - if (envp == NULL) - return (0); - - while (*envp != NULL) - ld_str_env(*envp++, lmflags, lmtflags, 0, aout); + Aliste idx; + const char *s1; + + for (APLIST_TRAVERSE(ealp, idx, s1)) + ld_str_env(s1, lmflags, lmtflags, 0, aout); /* * Having collected the best representation of any LD_FLAGS, process * these strings. */ - if (ld_flags_env(rpl_ldflags, lmflags, lmtflags, 0, aout) == 1) - return (1); + if (rpl_ldflags) { + if (ld_flags_env(rpl_ldflags, lmflags, lmtflags, 0, aout) == 1) + return (1); + rpl_ldflags = NULL; + } /* * Don't allow environment controlled auditing when tracing or if @@ -2345,25 +2437,6 @@ (LML_FLG_TRC_WARN | LML_FLG_TRC_LDDSTUB)) == LML_FLG_TRC_WARN) *lmflags |= LML_FLG_TRC_NOPAREXT; - /* - * If we have a locale setting make sure its worth processing further. - * C and POSIX locales don't need any processing. In addition, to - * ensure no one escapes the /usr/lib/locale hierarchy, don't allow - * the locale to contain a segment that leads upward in the file system - * hierarchy (i.e. no '..' segments). Given that we'll be confined to - * the /usr/lib/locale hierarchy, there is no need to extensively - * validate the mode or ownership of any message file (as libc's - * generic handling of message files does). Duplicate the string so - * that new locale setting can generically cleanup any previous locales. - */ - if ((locale = glcs[CI_LCMESSAGES].lc_un.lc_ptr) != NULL) { - if (((*locale == 'C') && (*(locale + 1) == '\0')) || - (strcmp(locale, MSG_ORIG(MSG_TKN_POSIX)) == 0) || - (strstr(locale, MSG_ORIG(MSG_TKN_DOTDOT)) != NULL)) - glcs[CI_LCMESSAGES].lc_un.lc_ptr = NULL; - else - glcs[CI_LCMESSAGES].lc_un.lc_ptr = strdup(locale); - } return (0); } @@ -2374,20 +2447,23 @@ int readenv_config(Rtc_env * envtbl, Addr addr, int aout) { - Word *lmflags = &(lml_main.lm_flags); - Word *lmtflags = &(lml_main.lm_tflags); + Word *lmflags = &(lml_main.lm_flags); + Word *lmtflags = &(lml_main.lm_tflags); if (envtbl == NULL) return (0); while (envtbl->env_str) { - uint_t env_flags = ENV_TYP_CONFIG; + uint_t env_flags = ENV_TYP_CONFIG; + const char *s1 = (const char *)(envtbl->env_str + addr); if (envtbl->env_flags & RTC_ENV_PERMANT) env_flags |= ENV_TYP_PERMANT; - ld_str_env((const char *)(envtbl->env_str + addr), - lmflags, lmtflags, env_flags, 0); + if ((*s1++ == 'L') && (*s1++ == 'D') && + (*s1++ == '_') && (*s1 != '\0')) + ld_str_env(s1, lmflags, lmtflags, env_flags, 0); + envtbl++; } @@ -2957,7 +3033,6 @@ lock = 0; } - #if DEBUG /* * Provide assfail() for ASSERT() statements. See <sys/debug.h> for further @@ -3522,9 +3597,17 @@ is_rtld_setuid() { rtld_stat_t status; - - if ((rtld_flags2 & RT_FL2_SETUID) || - ((rtld_stat(NAME(lml_rtld.lm_head), &status) == 0) && + const char *name; + + if (rtld_flags2 & RT_FL2_SETUID) + return (1); + + if (interp && interp->i_name) + name = interp->i_name; + else + name = NAME(lml_rtld.lm_head); + + if (((rtld_stat(name, &status) == 0) && (status.st_uid == 0) && (status.st_mode & S_ISUID))) { rtld_flags2 |= RT_FL2_SETUID; return (1);