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