Home | History | Annotate | Download | only in common
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1698  ab196087  * Common Development and Distribution License (the "License").
      6  1698  ab196087  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20  6150       rie  *
     21     0    stevel  *	Copyright (c) 1988 AT&T
     22     0    stevel  *	  All Rights Reserved
     23     0    stevel  *
     24     0    stevel  *
     25  9131       Rod  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     26  3731       rie  * Use is subject to license terms.
     27     0    stevel  */
     28     0    stevel 
     29     0    stevel /*
     30     0    stevel  * Print the list of shared objects required by a dynamic executable or shared
     31     0    stevel  * object.
     32     0    stevel  *
     33  6150       rie  * usage is: ldd [-d | -r] [-c] [-e envar] [-i] [-f] [-L] [-l] [-p] [-s]
     34  4947       rie  *		[-U | -u] [-v] [-w] file(s)
     35     0    stevel  *
     36     0    stevel  * ldd opens the file and verifies the information in the elf header.
     37     0    stevel  * If the file is a dynamic executable, we set up some environment variables
     38     0    stevel  * and exec(2) the file.  If the file is a shared object, we preload the
     39     0    stevel  * file with a dynamic executable stub. The runtime linker (ld.so.1) actually
     40     0    stevel  * provides the diagnostic output, according to the environment variables set.
     41     0    stevel  *
     42     0    stevel  * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_[AE].
     43     0    stevel  * The runtime linker will print the pathnames of all dynamic objects it
     44     0    stevel  * loads, and then exit.  Note that we distiguish between ELF and AOUT objects
     45     0    stevel  * when setting this environment variable - AOUT executables cause the mapping
     46     0    stevel  * of sbcp, the dependencies of which the user isn't interested in.
     47     0    stevel  *
     48     0    stevel  * If -d or -r is specified, we also set LD_WARN=1; the runtime linker will
     49     0    stevel  * perform its normal relocations and issue warning messages for unresolved
     50     0    stevel  * references. It will then exit.
     51     0    stevel  * If -r is specified, we set LD_BIND_NOW=1, so that the runtime linker
     52     0    stevel  * will perform all relocations, otherwise (under -d) the runtime linker
     53     0    stevel  * will not perform PLT (function) type relocations.
     54     0    stevel  *
     55     0    stevel  * If -c is specified we also set LD_NOCONFIG=1, thus disabling any
     56     0    stevel  * configuration file use.
     57     0    stevel  *
     58     0    stevel  * If -e is specified the associated environment variable is set for the
     59     0    stevel  * child process that will produce ldd's diagnostics.
     60     0    stevel  *
     61     0    stevel  * If -i is specified, we set LD_INIT=1. The order of inititialization
     62     0    stevel  * sections to be executed is printed. We also set LD_WARN=1.
     63     0    stevel  *
     64     0    stevel  * If -f is specified, we will run ldd as root on executables that have
     65     0    stevel  * an unsercure runtime linker that does not live under the "/usr/lib"
     66     0    stevel  * directory.  By default we will not let this happen.
     67     0    stevel  *
     68     0    stevel  * If -l is specified it generates a warning for any auxiliary filter not found.
     69     0    stevel  * Prior to 2.8 this forced any filters to load (all) their filtees.  This is
     70     0    stevel  * now the default, however missing auxiliary filters don't generate any error
     71     0    stevel  * diagniostic.  See also -L.
     72     0    stevel  *
     73     0    stevel  * If -L is specified we revert to lazy loading, thus any filtee or lazy
     74     0    stevel  * dependency loading is deferred until relocations cause loading.  Without
     75     0    stevel  * this option we set LD_LOADFLTR=1, thus forcing any filters to load (all)
     76     0    stevel  * their filtees, and LD_NOLAZYLOAD=1 thus forcing immediate processing of
     77     0    stevel  * any lazy loaded dependencies.
     78     0    stevel  *
     79     0    stevel  * If -s is specified we also set LD_TRACE_SEARCH_PATH=1, thus enabling
     80     0    stevel  * the runtime linker to indicate the search algorithm used.
     81     0    stevel  *
     82     0    stevel  * If -v is specified we also set LD_VERBOSE=1, thus enabling the runtime
     83     0    stevel  * linker to indicate all object dependencies (not just the first object
     84     0    stevel  * loaded) together with any versionig requirements.
     85     0    stevel  *
     86     0    stevel  * If -U or -u is specified unused dependencies are detected.  -u causes
     87     0    stevel  * LD_UNUSED=1 to be set, which causes dependencies that are unused within the
     88     0    stevel  * process to be detected.  -U causes LD_UNREF=1 to be set, which causes
     89     0    stevel  * unreferenced objects, and unreferenced cyclic dependencies to be detected.
     90     0    stevel  * These options assert that at least -d is set as relocation references are
     91     0    stevel  * what determine an objects use.
     92  4947       rie  *
     93  4947       rie  * If -w is specified, no unresolved weak references are allowed.  -w causes
     94  4947       rie  * LD_NOUNRESWEAK=1 to be set.  By default, an unresolved weak reference is
     95  4947       rie  * allowed, and a "0" is written to the relocation offset.  The -w option
     96  4947       rie  * disables this default.  Any weak references that can not be resolved result
     97  6150       rie  * in relocation error messages.  This option has no use without -r or -d.
     98  6150       rie  *
     99  6150       rie  * If the -p option is specified, no unresolved PARENT or EXTERN references are
    100  6150       rie  * allowed.  -p causes LD_NOPAREXT=1 to be set.  By default, PARENT and EXTERN
    101  6150       rie  * references, which have been explicitly assigned via a mapfile when a shared
    102  6150       rie  * object was built, imply that a caller will provide the symbols, and hence
    103  6150       rie  * these are not reported as relocation errors.  Note, the -p option is asserted
    104  6150       rie  * by default when either the -r or -d options are used to inspect a dynamic
    105  6150       rie  * executable.  This option has no use with a shared object without -r or -d.
    106     0    stevel  */
    107     0    stevel #include	<fcntl.h>
    108     0    stevel #include	<stdio.h>
    109     0    stevel #include	<string.h>
    110  1698  ab196087 #include	<_libelf.h>
    111     0    stevel #include	<stdlib.h>
    112     0    stevel #include	<unistd.h>
    113     0    stevel #include	<wait.h>
    114     0    stevel #include	<locale.h>
    115     0    stevel #include	<errno.h>
    116     0    stevel #include	<signal.h>
    117     0    stevel #include	"machdep.h"
    118     0    stevel #include	"sgs.h"
    119     0    stevel #include	"conv.h"
    120     0    stevel #include	"a.out.h"
    121     0    stevel #include	"msg.h"
    122     0    stevel 
    123     0    stevel static int	elf_check(int, char *, char *, Elf *, int);
    124     0    stevel static int	aout_check(int, char *, char *, int, int);
    125     0    stevel static int	run(int, char *, char *, const char *, int);
    126     0    stevel 
    127     0    stevel 
    128     0    stevel /*
    129  4947       rie  * Define all environment variable strings.  The character following the "="
    130  4947       rie  * will be written to, to disable or enable the associated feature.
    131     0    stevel  */
    132     0    stevel static char	bind[] =	"LD_BIND_NOW= ",
    133     0    stevel 		load_elf[] =	"LD_TRACE_LOADED_OBJECTS_E= ",
    134     0    stevel 		load_aout[] =	"LD_TRACE_LOADED_OBJECTS_A= ",
    135     0    stevel 		path[] =	"LD_TRACE_SEARCH_PATHS= ",
    136     0    stevel 		verb[] =	"LD_VERBOSE= ",
    137     0    stevel 		warn[] =	"LD_WARN= ",
    138     0    stevel 		conf[] =	"LD_NOCONFIG= ",
    139     0    stevel 		fltr[] =	"LD_LOADFLTR= ",
    140     0    stevel 		lazy[] =	"LD_NOLAZYLOAD=1",
    141     0    stevel 		init[] =	"LD_INIT= ",
    142     0    stevel 		uref[] =	"LD_UNREF= ",
    143  4947       rie 		used[] =	"LD_UNUSED= ",
    144  6150       rie 		weak[] =	"LD_NOUNRESWEAK= ",
    145  6150       rie 		nope[] =	"LD_NOPAREXT= ";
    146     0    stevel static char	*load;
    147     0    stevel 
    148     0    stevel static const char	*prefile_32, *prefile_64, *prefile;
    149  9131       Rod static APlist		*eopts = NULL;
    150     0    stevel 
    151     0    stevel int
    152  6223  ab196087 main(int argc, char **argv, char **envp)
    153     0    stevel {
    154     0    stevel 	char	*str, *cname = argv[0];
    155     0    stevel 
    156     0    stevel 	Elf	*elf;
    157     0    stevel 	int	cflag = 0, dflag = 0, fflag = 0, iflag = 0, Lflag = 0;
    158     0    stevel 	int	lflag = 0, rflag = 0, sflag = 0, Uflag = 0, uflag = 0;
    159  6150       rie 	int	pflag = 0, vflag = 0, wflag = 0, nfile, var, error = 0;
    160     0    stevel 
    161  9131       Rod 	Aliste	idx;
    162  6223  ab196087 
    163  6223  ab196087 	/*
    164  6223  ab196087 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
    165  6223  ab196087 	 * the binary.  If successful, conv_check_native() won't return.
    166  6223  ab196087 	 *
    167  6223  ab196087 	 * This is done to ensure that ldd can handle objects >2GB.
    168  6223  ab196087 	 * ldd uses libelf, which is not large file capable. The
    169  6223  ab196087 	 * 64-bit ldd can handle any sized object.
    170  6223  ab196087 	 */
    171  6223  ab196087 	(void) conv_check_native(argv, envp);
    172     0    stevel 
    173     0    stevel 	/*
    174     0    stevel 	 * Establish locale.
    175     0    stevel 	 */
    176     0    stevel 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
    177     0    stevel 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
    178     0    stevel 
    179     0    stevel 	/*
    180     0    stevel 	 * verify command line syntax and process arguments
    181     0    stevel 	 */
    182     0    stevel 	opterr = 0;				/* disable getopt error mesg */
    183     0    stevel 
    184     0    stevel 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_GETOPT))) != EOF) {
    185     0    stevel 		switch (var) {
    186     0    stevel 		case 'c' :			/* enable config search */
    187     0    stevel 			cflag = 1;
    188     0    stevel 			break;
    189     0    stevel 		case 'd' :			/* perform data relocations */
    190     0    stevel 			dflag = 1;
    191     0    stevel 			if (rflag)
    192     0    stevel 				error++;
    193     0    stevel 			break;
    194     0    stevel 		case 'e' :
    195  9131       Rod 			if (aplist_append(&eopts, optarg, 10) == NULL) {
    196     0    stevel 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
    197     0    stevel 				    cname);
    198     0    stevel 				exit(1);
    199     0    stevel 			}
    200     0    stevel 			break;
    201     0    stevel 		case 'f' :
    202     0    stevel 			fflag = 1;
    203     0    stevel 			break;
    204     0    stevel 		case 'L' :
    205     0    stevel 			Lflag = 1;
    206     0    stevel 			break;
    207     0    stevel 		case 'l' :
    208     0    stevel 			lflag = 1;
    209     0    stevel 			break;
    210     0    stevel 		case 'i' :			/* print the order of .init */
    211     0    stevel 			iflag = 1;
    212     0    stevel 			break;
    213  6150       rie 		case 'p' :
    214  6150       rie 			pflag = 1;		/* expose unreferenced */
    215  6150       rie 			break;			/*	parent or externals */
    216     0    stevel 		case 'r' :			/* perform all relocations */
    217     0    stevel 			rflag = 1;
    218     0    stevel 			if (dflag)
    219     0    stevel 				error++;
    220     0    stevel 			break;
    221     0    stevel 		case 's' :			/* enable search path output */
    222     0    stevel 			sflag = 1;
    223     0    stevel 			break;
    224     0    stevel 		case 'U' :			/* list unreferenced */
    225     0    stevel 			Uflag = 1;		/*	dependencies */
    226     0    stevel 			if (uflag)
    227     0    stevel 				error++;
    228     0    stevel 			break;
    229     0    stevel 		case 'u' :			/* list unused dependencies */
    230     0    stevel 			uflag = 1;
    231     0    stevel 			if (Uflag)
    232     0    stevel 				error++;
    233     0    stevel 			break;
    234     0    stevel 		case 'v' :			/* enable verbose output */
    235     0    stevel 			vflag = 1;
    236  4947       rie 			break;
    237  6150       rie 		case 'w' :			/* expose unresolved weak */
    238  4947       rie 			wflag = 1;		/*	references */
    239     0    stevel 			break;
    240     0    stevel 		default :
    241     0    stevel 			error++;
    242     0    stevel 			break;
    243     0    stevel 		}
    244     0    stevel 		if (error)
    245     0    stevel 			break;
    246     0    stevel 	}
    247     0    stevel 	if (error) {
    248     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), cname);
    249     0    stevel 		exit(1);
    250     0    stevel 	}
    251     0    stevel 
    252     0    stevel 	/*
    253     0    stevel 	 * Determine if any of the LD_PRELOAD family is already set in the
    254     0    stevel 	 * environment, if so we'll continue to analyze each object with the
    255     0    stevel 	 * appropriate setting.
    256     0    stevel 	 */
    257     0    stevel 	if (((prefile_32 = getenv(MSG_ORIG(MSG_LD_PRELOAD_32))) == NULL) ||
    258     0    stevel 	    (*prefile_32 == '\0')) {
    259     0    stevel 		prefile_32 = MSG_ORIG(MSG_STR_EMPTY);
    260     0    stevel 	}
    261     0    stevel 	if (((prefile_64 = getenv(MSG_ORIG(MSG_LD_PRELOAD_64))) == NULL) ||
    262     0    stevel 	    (*prefile_64 == '\0')) {
    263     0    stevel 		prefile_64 = MSG_ORIG(MSG_STR_EMPTY);
    264     0    stevel 	}
    265     0    stevel 	if (((prefile = getenv(MSG_ORIG(MSG_LD_PRELOAD))) == NULL) ||
    266     0    stevel 	    (*prefile == '\0')) {
    267     0    stevel 		prefile = MSG_ORIG(MSG_STR_EMPTY);
    268     0    stevel 	}
    269     0    stevel 
    270     0    stevel 	/*
    271     0    stevel 	 * Determine if any environment requests are for the LD_PRELOAD family,
    272     0    stevel 	 * and if so override any environment settings we've established above.
    273     0    stevel 	 */
    274  9131       Rod 	for (APLIST_TRAVERSE(eopts, idx, str)) {
    275     0    stevel 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_32),
    276     0    stevel 		    MSG_LD_PRELOAD_32_SIZE)) == 0) {
    277     0    stevel 			str += MSG_LD_PRELOAD_32_SIZE;
    278     0    stevel 			if ((*str++ == '=') && (*str != '\0'))
    279     0    stevel 				prefile_32 = str;
    280     0    stevel 			continue;
    281     0    stevel 		}
    282     0    stevel 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_64),
    283     0    stevel 		    MSG_LD_PRELOAD_64_SIZE)) == 0) {
    284     0    stevel 			str += MSG_LD_PRELOAD_64_SIZE;
    285     0    stevel 			if ((*str++ == '=') && (*str != '\0'))
    286     0    stevel 				prefile_64 = str;
    287     0    stevel 			continue;
    288     0    stevel 		}
    289     0    stevel 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD),
    290     0    stevel 		    MSG_LD_PRELOAD_SIZE)) == 0) {
    291     0    stevel 			str += MSG_LD_PRELOAD_SIZE;
    292     0    stevel 			if ((*str++ == '=') && (*str != '\0'))
    293     0    stevel 				prefile = str;
    294     0    stevel 			continue;
    295     0    stevel 		}
    296     0    stevel 	}
    297     0    stevel 
    298     0    stevel 	/*
    299     0    stevel 	 * Set the appropriate relocation environment variables (Note unsetting
    300     0    stevel 	 * the environment variables is done just in case the user already
    301     0    stevel 	 * has these in their environment ... sort of thing the test folks
    302     0    stevel 	 * would do :-)
    303     0    stevel 	 */
    304  4947       rie 	warn[sizeof (warn) - 2] = (dflag || rflag || Uflag || uflag) ? '1' :
    305     0    stevel 	    '\0';
    306  4947       rie 	bind[sizeof (bind) - 2] = (rflag) ? '1' : '\0';
    307  4947       rie 	path[sizeof (path) - 2] = (sflag) ? '1' : '\0';
    308  4947       rie 	verb[sizeof (verb) - 2] = (vflag) ? '1' : '\0';
    309  4947       rie 	fltr[sizeof (fltr) - 2] = (Lflag) ? '\0' : (lflag) ? '2' : '1';
    310  4947       rie 	init[sizeof (init) - 2] = (iflag) ? '1' : '\0';
    311  4947       rie 	conf[sizeof (conf) - 2] = (cflag) ? '1' : '\0';
    312  4947       rie 	lazy[sizeof (lazy) - 2] = (Lflag) ? '\0' : '1';
    313  4947       rie 	uref[sizeof (uref) - 2] = (Uflag) ? '1' : '\0';
    314  4947       rie 	used[sizeof (used) - 2] = (uflag) ? '1' : '\0';
    315  4947       rie 	weak[sizeof (weak) - 2] = (wflag) ? '1' : '\0';
    316  6150       rie 	nope[sizeof (nope) - 2] = (pflag) ? '1' : '\0';
    317     0    stevel 
    318     0    stevel 	/*
    319     0    stevel 	 * coordinate libelf's version information
    320     0    stevel 	 */
    321     0    stevel 	if (elf_version(EV_CURRENT) == EV_NONE) {
    322     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIBELF), cname,
    323     0    stevel 		    EV_CURRENT);
    324     0    stevel 		exit(1);
    325     0    stevel 	}
    326     0    stevel 
    327     0    stevel 	/*
    328     0    stevel 	 * Loop through remaining arguments.  Note that from here on there
    329     0    stevel 	 * are no exit conditions so that we can process a list of files,
    330     0    stevel 	 * any error condition is retained for a final exit status.
    331     0    stevel 	 */
    332     0    stevel 	nfile = argc - optind;
    333     0    stevel 	for (; optind < argc; optind++) {
    334     0    stevel 		char	*fname = argv[optind];
    335     0    stevel 
    336     0    stevel 		/*
    337     0    stevel 		 * Open file (do this before checking access so that we can
    338     0    stevel 		 * provide the user with better diagnostics).
    339     0    stevel 		 */
    340     0    stevel 		if ((var = open(fname, O_RDONLY)) == -1) {
    341     0    stevel 			int	err = errno;
    342     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), cname,
    343     0    stevel 			    fname, strerror(err));
    344     0    stevel 			error = 1;
    345     0    stevel 			continue;
    346     0    stevel 		}
    347     0    stevel 
    348     0    stevel 		/*
    349     0    stevel 		 * Get the files elf descriptor and process it as an elf or
    350     0    stevel 		 * a.out (4.x) file.
    351     0    stevel 		 */
    352     0    stevel 		elf = elf_begin(var, ELF_C_READ, (Elf *)0);
    353     0    stevel 		switch (elf_kind(elf)) {
    354     0    stevel 		case ELF_K_AR :
    355     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO),
    356     0    stevel 			    cname, fname);
    357     0    stevel 			error = 1;
    358     0    stevel 			break;
    359     0    stevel 		case ELF_K_COFF:
    360     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN),
    361     0    stevel 			    cname, fname);
    362     0    stevel 			error = 1;
    363     0    stevel 			break;
    364     0    stevel 		case ELF_K_ELF:
    365     0    stevel 			if (elf_check(nfile, fname, cname, elf, fflag) != NULL)
    366     0    stevel 				error = 1;
    367     0    stevel 			break;
    368     0    stevel 		default:
    369     0    stevel 			/*
    370     0    stevel 			 * This is either an unknown file or an aout format
    371     0    stevel 			 */
    372     0    stevel 			if (aout_check(nfile, fname, cname, var, fflag) != NULL)
    373     0    stevel 				error = 1;
    374     0    stevel 			break;
    375     0    stevel 		}
    376     0    stevel 		(void) elf_end(elf);
    377     0    stevel 		(void) close(var);
    378     0    stevel 	}
    379     0    stevel 	return (error);
    380     0    stevel }
    381     0    stevel 
    382     0    stevel 
    383     0    stevel 
    384     0    stevel static int
    385     0    stevel is_runnable(GElf_Ehdr *ehdr)
    386     0    stevel {
    387  6223  ab196087 	if ((ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
    388     0    stevel 	    (ehdr->e_ident[EI_DATA] == M_DATA))
    389     0    stevel 		return (ELFCLASS32);
    390     0    stevel 
    391  3731       rie #if	defined(__sparc)
    392     0    stevel 	if ((ehdr->e_machine == EM_SPARCV9) &&
    393     0    stevel 	    (ehdr->e_ident[EI_DATA] == M_DATA) &&
    394     0    stevel 	    (conv_sys_eclass() == ELFCLASS64))
    395     0    stevel 		return (ELFCLASS64);
    396  3731       rie #elif	defined(__x86)
    397     0    stevel 	if ((ehdr->e_machine == EM_AMD64) &&
    398     0    stevel 	    (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) &&
    399     0    stevel 	    (conv_sys_eclass() == ELFCLASS64))
    400     0    stevel 		return (ELFCLASS64);
    401     0    stevel #endif
    402     0    stevel 
    403     0    stevel 	return (ELFCLASSNONE);
    404     0    stevel }
    405     0    stevel 
    406     0    stevel 
    407     0    stevel static int
    408     0    stevel elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
    409     0    stevel {
    410     0    stevel 	GElf_Ehdr 	ehdr;
    411     0    stevel 	GElf_Phdr 	phdr;
    412     0    stevel 	int		dynamic = 0, interp = 0, cnt, class;
    413     0    stevel 
    414     0    stevel 	/*
    415     0    stevel 	 * verify information in file header
    416     0    stevel 	 */
    417     0    stevel 	if (gelf_getehdr(elf, &ehdr) == NULL) {
    418     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR),
    419  4947       rie 		    cname, fname, elf_errmsg(-1));
    420     0    stevel 		return (1);
    421     0    stevel 	}
    422     0    stevel 
    423     0    stevel 	/*
    424     0    stevel 	 * check class and encoding
    425     0    stevel 	 */
    426     0    stevel 	if ((class = is_runnable(&ehdr)) == ELFCLASSNONE) {
    427     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_CLASSDATA),
    428  4947       rie 		    cname, fname);
    429     0    stevel 		return (1);
    430     0    stevel 	}
    431     0    stevel 
    432     0    stevel 	/*
    433     0    stevel 	 * check type
    434     0    stevel 	 */
    435     0    stevel 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN) &&
    436     0    stevel 	    (ehdr.e_type != ET_REL)) {
    437     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_BADMAGIC),
    438  4947       rie 		    cname, fname);
    439     0    stevel 		return (1);
    440     0    stevel 	}
    441     0    stevel 	if ((class == ELFCLASS32) && (ehdr.e_machine != M_MACH)) {
    442     0    stevel 		if (ehdr.e_machine != M_MACHPLUS) {
    443     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHTYPE),
    444  4947       rie 			    cname, fname);
    445     0    stevel 			return (1);
    446     0    stevel 		}
    447     0    stevel 		if ((ehdr.e_flags & M_FLAGSPLUS) == 0) {
    448     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHFLAGS),
    449  4947       rie 			    cname, fname);
    450     0    stevel 			return (1);
    451     0    stevel 		}
    452     0    stevel 	}
    453     0    stevel 
    454     0    stevel 	/*
    455     0    stevel 	 * Check that the file is executable.  Dynamic executables must be
    456     0    stevel 	 * executable to be exec'ed.  Shared objects need not be executable to
    457     0    stevel 	 * be mapped with a dynamic executable, however, by convention they're
    458     0    stevel 	 * supposed to be executable.
    459     0    stevel 	 */
    460     0    stevel 	if (access(fname, X_OK) != 0) {
    461     0    stevel 		if (ehdr.e_type == ET_EXEC) {
    462     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_1),
    463  4947       rie 			    cname, fname);
    464     0    stevel 			return (1);
    465     0    stevel 		}
    466     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_2), cname,
    467     0    stevel 		    fname);
    468     0    stevel 	}
    469     0    stevel 
    470     0    stevel 	/*
    471     0    stevel 	 * Determine whether we have a dynamic section or interpretor.
    472     0    stevel 	 */
    473     0    stevel 	for (cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) {
    474     0    stevel 		if (dynamic && interp)
    475     0    stevel 			break;
    476     0    stevel 
    477     0    stevel 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
    478     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETPHDR),
    479  4947       rie 			    cname, fname, elf_errmsg(-1));
    480     0    stevel 			return (1);
    481     0    stevel 		}
    482     0    stevel 
    483     0    stevel 		if (phdr.p_type == PT_DYNAMIC) {
    484     0    stevel 			dynamic = 1;
    485     0    stevel 			continue;
    486     0    stevel 		}
    487     0    stevel 
    488     0    stevel 		if (phdr.p_type != PT_INTERP)
    489     0    stevel 			continue;
    490     0    stevel 
    491     0    stevel 		interp = 1;
    492     0    stevel 
    493     0    stevel 		/*
    494     0    stevel 		 * If fflag is not set, and euid == root, and the interpreter
    495     0    stevel 		 * does not live under /lib, /usr/lib or /etc/lib then don't
    496     0    stevel 		 * allow ldd to execute the image.  This prevents someone
    497     0    stevel 		 * creating a `trojan horse' by substituting their own
    498     0    stevel 		 * interpreter that could preform privileged operations
    499     0    stevel 		 * when ldd is against it.
    500     0    stevel 		 */
    501     0    stevel 		if ((fflag == 0) && (geteuid() == 0) &&
    502     0    stevel 		    (strcmp(fname, conv_lddstub(class)) != 0)) {
    503     0    stevel 			char	*interpreter;
    504     0    stevel 
    505     0    stevel 			/*
    506     0    stevel 			 * Does the interpreter live under a trusted directory.
    507     0    stevel 			 */
    508     0    stevel 			interpreter = elf_getident(elf, 0) + phdr.p_offset;
    509     0    stevel 
    510     0    stevel 			if ((strncmp(interpreter, MSG_ORIG(MSG_PTH_USRLIB),
    511     0    stevel 			    MSG_PTH_USRLIB_SIZE) != 0) &&
    512     0    stevel 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_LIB),
    513     0    stevel 			    MSG_PTH_LIB_SIZE) != 0) &&
    514     0    stevel 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_ETCLIB),
    515     0    stevel 			    MSG_PTH_ETCLIB_SIZE) != 0)) {
    516     0    stevel 				(void) fprintf(stderr, MSG_INTL(MSG_USP_ELFINS),
    517  4947       rie 				    cname, fname, interpreter);
    518     0    stevel 				return (1);
    519     0    stevel 			}
    520     0    stevel 		}
    521     0    stevel 	}
    522     0    stevel 
    523     0    stevel 	/*
    524     0    stevel 	 * Catch the case of a static executable (ie, an ET_EXEC that has a set
    525     0    stevel 	 * of program headers but no PT_DYNAMIC).
    526     0    stevel 	 */
    527     0    stevel 	if (ehdr.e_phnum && !dynamic) {
    528     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
    529     0    stevel 		    fname);
    530     0    stevel 		return (1);
    531     0    stevel 	}
    532     0    stevel 
    533  1698  ab196087 	/*
    534  1698  ab196087 	 * If there is a dynamic section, then check for the DF_1_NOHDR
    535  1698  ab196087 	 * flag, and bail if it is present. Those objects are created using
    536  1698  ab196087 	 * the ?N mapfile option: The ELF header and program headers are
    537  1698  ab196087 	 * not mapped as part of the first segment, and virtual addresses
    538  1698  ab196087 	 * are computed without them. If ldd tries to interpret such
    539  1698  ab196087 	 * a file, it will become confused and generate bad output or
    540  1698  ab196087 	 * crash. Such objects are always special purpose files (like an OS
    541  1698  ab196087 	 * kernel) --- files for which the ldd operation doesn't make sense.
    542  1698  ab196087 	 */
    543  1698  ab196087 	if (dynamic && (_gelf_getdyndtflags_1(elf) & DF_1_NOHDR)) {
    544  1698  ab196087 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOHDR), cname,
    545  1698  ab196087 		    fname);
    546  1698  ab196087 		return (1);
    547  1698  ab196087 	}
    548  1698  ab196087 
    549     0    stevel 	load = load_elf;
    550     0    stevel 
    551     0    stevel 	/*
    552     0    stevel 	 * Run the required program (shared and relocatable objects require the
    553     0    stevel 	 * use of lddstub).
    554     0    stevel 	 */
    555     0    stevel 	if ((ehdr.e_type == ET_EXEC) && interp)
    556     0    stevel 		return (run(nfile, cname, fname, (const char *)fname, class));
    557     0    stevel 	else
    558     0    stevel 		return (run(nfile, cname, fname, conv_lddstub(class), class));
    559     0    stevel }
    560     0    stevel 
    561     0    stevel static int
    562     0    stevel aout_check(int nfile, char *fname, char *cname, int fd, int fflag)
    563     0    stevel {
    564  6223  ab196087 	struct exec32	aout;
    565     0    stevel 	int		err;
    566     0    stevel 
    567     0    stevel 	if (lseek(fd, 0, SEEK_SET) != 0) {
    568     0    stevel 		err = errno;
    569     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname,
    570     0    stevel 		    strerror(err));
    571     0    stevel 		return (1);
    572     0    stevel 	}
    573  6223  ab196087 	if (read(fd, (char *)&aout, sizeof (aout)) != sizeof (aout)) {
    574     0    stevel 		err = errno;
    575     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname,
    576     0    stevel 		    strerror(err));
    577     0    stevel 		return (1);
    578     0    stevel 	}
    579     0    stevel 	if (aout.a_machtype != M_SPARC) {
    580     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname);
    581     0    stevel 		return (1);
    582     0    stevel 	}
    583     0    stevel 	if (N_BADMAG(aout) || !aout.a_dynamic) {
    584     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
    585     0    stevel 		    fname);
    586     0    stevel 		return (1);
    587     0    stevel 	}
    588     0    stevel 	if (!fflag && (geteuid() == 0)) {
    589     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname);
    590     0    stevel 		return (1);
    591     0    stevel 	}
    592     0    stevel 
    593     0    stevel 	/*
    594     0    stevel 	 * Run the required program.
    595     0    stevel 	 */
    596  6223  ab196087 	if ((aout.a_magic == ZMAGIC) && (aout.a_entry <= sizeof (aout))) {
    597     0    stevel 		load = load_elf;
    598     0    stevel 		return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32),
    599     0    stevel 		    ELFCLASS32));
    600     0    stevel 	} else {
    601     0    stevel 		load = load_aout;
    602     0    stevel 		return (run(nfile, cname, fname, (const char *)fname,
    603     0    stevel 		    ELFCLASS32));
    604     0    stevel 	}
    605     0    stevel }
    606     0    stevel 
    607     0    stevel 
    608     0    stevel /*
    609     0    stevel  * Run the required program, setting the preload and trace environment
    610     0    stevel  * variables accordingly.
    611     0    stevel  */
    612     0    stevel static int
    613     0    stevel run(int nfile, char *cname, char *fname, const char *ename, int class)
    614     0    stevel {
    615     0    stevel 	const char	*preload = 0;
    616     0    stevel 	int		pid, status;
    617     0    stevel 
    618     0    stevel 	if ((pid = fork()) == -1) {
    619     0    stevel 		int	err = errno;
    620     0    stevel 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), cname,
    621     0    stevel 		    strerror(err));
    622     0    stevel 		return (1);
    623     0    stevel 	}
    624     0    stevel 
    625     0    stevel 	if (pid) {				/* parent */
    626     0    stevel 		while (wait(&status) != pid)
    627     0    stevel 			;
    628     0    stevel 		if (WIFSIGNALED(status) && ((WSIGMASK & status) != SIGPIPE)) {
    629     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
    630     0    stevel 			    fname);
    631     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_SIG),
    632     0    stevel 			    (WSIGMASK & status), ((status & WCOREFLG) ?
    633     0    stevel 			    MSG_INTL(MSG_SYS_EXEC_CORE) :
    634     0    stevel 			    MSG_ORIG(MSG_STR_EMPTY)));
    635     0    stevel 			status = 1;
    636     0    stevel 		} else if (WHIBYTE(status)) {
    637     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
    638     0    stevel 			    fname);
    639     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_STAT),
    640     0    stevel 			    WHIBYTE(status));
    641     0    stevel 			status = 1;
    642     0    stevel 		}
    643     0    stevel 	} else {				/* child */
    644  9131       Rod 		Aliste	idx;
    645  9131       Rod 		char	*str;
    646  9131       Rod 		size_t	size;
    647     0    stevel 
    648     0    stevel 		/*
    649     0    stevel 		 * When using ldd(1) to analyze a shared object we preload the
    650     0    stevel 		 * shared object with lddstub.  Any additional preload
    651     0    stevel 		 * requirements are added after the object being analyzed, this
    652     0    stevel 		 * allows us to skip the first object but produce diagnostics
    653     0    stevel 		 * for each other preloaded object.
    654     0    stevel 		 */
    655     0    stevel 		if (fname != ename) {
    656     0    stevel 			char		*str;
    657     0    stevel 			const char	*files = prefile;
    658     0    stevel 			const char	*format = MSG_ORIG(MSG_STR_FMT1);
    659     0    stevel 
    660     0    stevel 			for (str = fname; *str; str++)
    661     0    stevel 				if (*str == '/') {
    662     0    stevel 					format = MSG_ORIG(MSG_STR_FMT2);
    663     0    stevel 					break;
    664     0    stevel 			}
    665     0    stevel 
    666     0    stevel 			preload = MSG_ORIG(MSG_LD_PRELOAD);
    667     0    stevel 
    668     0    stevel 			/*
    669     0    stevel 			 * Determine which preload files and preload environment
    670     0    stevel 			 * variable to use.
    671     0    stevel 			 */
    672     0    stevel 			if (class == ELFCLASS64) {
    673     0    stevel 				if (prefile_64 != MSG_ORIG(MSG_STR_EMPTY)) {
    674     0    stevel 					files = prefile_64;
    675     0    stevel 					preload = MSG_ORIG(MSG_LD_PRELOAD_64);
    676     0    stevel 				}
    677     0    stevel 			} else {
    678     0    stevel 				if (prefile_32 != MSG_ORIG(MSG_STR_EMPTY)) {
    679     0    stevel 					files = prefile_32;
    680     0    stevel 					preload = MSG_ORIG(MSG_LD_PRELOAD_32);
    681     0    stevel 				}
    682     0    stevel 			}
    683     0    stevel 
    684     0    stevel 			if ((str = (char *)malloc(strlen(preload) +
    685     0    stevel 			    strlen(fname) + strlen(files) + 5)) == 0) {
    686     0    stevel 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
    687     0    stevel 				    cname);
    688     0    stevel 				exit(1);
    689     0    stevel 			}
    690     0    stevel 
    691     0    stevel 			(void) sprintf(str, format, preload, fname, files);
    692     0    stevel 			if (putenv(str) != 0) {
    693     0    stevel 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
    694     0    stevel 				    cname);
    695     0    stevel 				exit(1);
    696     0    stevel 			}
    697  4947       rie 
    698  4947       rie 			/*
    699  4947       rie 			 * The pointer "load" has be assigned to load_elf[] or
    700  4947       rie 			 * load_aout[].  Use the size of load_elf[] as the size
    701  4947       rie 			 * of load_aout[] is the same.
    702  4947       rie 			 */
    703  4947       rie 			load[sizeof (load_elf) - 2] = '2';
    704     0    stevel 		} else
    705  4947       rie 			load[sizeof (load_elf) - 2] = '1';
    706     0    stevel 
    707     0    stevel 
    708     0    stevel 		/*
    709     0    stevel 		 * Establish new environment variables to affect the child
    710     0    stevel 		 * process.
    711     0    stevel 		 */
    712     0    stevel 		if ((putenv(warn) != 0) || (putenv(bind) != 0) ||
    713     0    stevel 		    (putenv(path) != 0) || (putenv(verb) != 0) ||
    714     0    stevel 		    (putenv(fltr) != 0) || (putenv(conf) != 0) ||
    715     0    stevel 		    (putenv(init) != 0) || (putenv(lazy) != 0) ||
    716     0    stevel 		    (putenv(uref) != 0) || (putenv(used) != 0) ||
    717  6150       rie 		    (putenv(weak) != 0) || (putenv(load) != 0) ||
    718  6150       rie 		    (putenv(nope) != 0)) {
    719     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED), cname);
    720     0    stevel 			exit(1);
    721     0    stevel 		}
    722     0    stevel 
    723     0    stevel 		/*
    724     0    stevel 		 * Establish explicit environment requires (but don't override
    725     0    stevel 		 * any preload request established to process a shared object).
    726     0    stevel 		 */
    727     0    stevel 		size = 0;
    728  9131       Rod 		for (APLIST_TRAVERSE(eopts, idx, str)) {
    729     0    stevel 			if (preload) {
    730     0    stevel 				if (size == 0)
    731     0    stevel 					size = strlen(preload);
    732     0    stevel 				if ((strncmp(preload, str, size) == 0) &&
    733     0    stevel 				    (str[size] == '=')) {
    734     0    stevel 					continue;
    735     0    stevel 				}
    736     0    stevel 			}
    737     0    stevel 			if (putenv(str) != 0) {
    738     0    stevel 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
    739     0    stevel 				    cname);
    740     0    stevel 				exit(1);
    741     0    stevel 			}
    742     0    stevel 		}
    743     0    stevel 
    744     0    stevel 		/*
    745     0    stevel 		 * Execute the object and let ld.so.1 do the rest.
    746     0    stevel 		 */
    747     0    stevel 		if (nfile > 1)
    748     0    stevel 			(void) printf(MSG_ORIG(MSG_STR_FMT3), fname);
    749     0    stevel 		(void) fflush(stdout);
    750     0    stevel 		if ((execl(ename, ename, (char *)0)) == -1) {
    751     0    stevel 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
    752     0    stevel 			    fname);
    753     0    stevel 			perror(ename);
    754     0    stevel 			_exit(0);
    755     0    stevel 			/* NOTREACHED */
    756     0    stevel 		}
    757     0    stevel 	}
    758     0    stevel 	return (status);
    759     0    stevel }
    760     0    stevel 
    761     0    stevel const char *
    762     0    stevel _ldd_msg(Msg mid)
    763     0    stevel {
    764     0    stevel 	return (gettext(MSG_ORIG(mid)));
    765     0    stevel }
    766