ldd.c revision 1698:0cf90a9f4e74
1227825Stheraven/*
2227825Stheraven * CDDL HEADER START
3227825Stheraven *
4227825Stheraven * The contents of this file are subject to the terms of the
5227825Stheraven * Common Development and Distribution License (the "License").
6227825Stheraven * You may not use this file except in compliance with the License.
7227825Stheraven *
8227825Stheraven * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9227825Stheraven * or http://www.opensolaris.org/os/licensing.
10227825Stheraven * See the License for the specific language governing permissions
11227825Stheraven * and limitations under the License.
12227825Stheraven *
13227825Stheraven * When distributing Covered Code, include this CDDL HEADER in each
14227825Stheraven * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15227825Stheraven * If applicable, add the following below this CDDL HEADER, with the
16227825Stheraven * fields enclosed by brackets "[]" replaced with your own identifying
17227825Stheraven * information: Portions Copyright [yyyy] [name of copyright owner]
18227825Stheraven *
19227825Stheraven * CDDL HEADER END
20227825Stheraven */
21227825Stheraven/*
22227825Stheraven *	Copyright (c) 1988 AT&T
23227825Stheraven *	  All Rights Reserved
24227825Stheraven *
25227825Stheraven *
26227825Stheraven *	Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27227825Stheraven *	Use is subject to license terms.
28227825Stheraven */
29227825Stheraven#pragma ident	"%Z%%M%	%I%	%E% SMI"
30227825Stheraven
31227825Stheraven/*
32227825Stheraven * Print the list of shared objects required by a dynamic executable or shared
33227825Stheraven * object.
34227825Stheraven *
35227825Stheraven * usage is: ldd [-d | -r] [-c] [-e envar] [-i] [-f] [-L] [-l] [-s]
36227825Stheraven *		[-U | -u] [-v] file(s)
37227825Stheraven *
38227825Stheraven * ldd opens the file and verifies the information in the elf header.
39227825Stheraven * If the file is a dynamic executable, we set up some environment variables
40227825Stheraven * and exec(2) the file.  If the file is a shared object, we preload the
41227825Stheraven * file with a dynamic executable stub. The runtime linker (ld.so.1) actually
42227825Stheraven * provides the diagnostic output, according to the environment variables set.
43227825Stheraven *
44227825Stheraven * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_[AE].
45227825Stheraven * The runtime linker will print the pathnames of all dynamic objects it
46227825Stheraven * loads, and then exit.  Note that we distiguish between ELF and AOUT objects
47227825Stheraven * when setting this environment variable - AOUT executables cause the mapping
48227825Stheraven * of sbcp, the dependencies of which the user isn't interested in.
49227825Stheraven *
50227825Stheraven * If -d or -r is specified, we also set LD_WARN=1; the runtime linker will
51227825Stheraven * perform its normal relocations and issue warning messages for unresolved
52227825Stheraven * references. It will then exit.
53227825Stheraven * If -r is specified, we set LD_BIND_NOW=1, so that the runtime linker
54227825Stheraven * will perform all relocations, otherwise (under -d) the runtime linker
55227825Stheraven * will not perform PLT (function) type relocations.
56227825Stheraven *
57227825Stheraven * If -c is specified we also set LD_NOCONFIG=1, thus disabling any
58227825Stheraven * configuration file use.
59227825Stheraven *
60227825Stheraven * If -e is specified the associated environment variable is set for the
61227825Stheraven * child process that will produce ldd's diagnostics.
62227825Stheraven *
63227825Stheraven * If -i is specified, we set LD_INIT=1. The order of inititialization
64227825Stheraven * sections to be executed is printed. We also set LD_WARN=1.
65227825Stheraven *
66227825Stheraven * If -f is specified, we will run ldd as root on executables that have
67227825Stheraven * an unsercure runtime linker that does not live under the "/usr/lib"
68227825Stheraven * directory.  By default we will not let this happen.
69227825Stheraven *
70227825Stheraven * If -l is specified it generates a warning for any auxiliary filter not found.
71227825Stheraven * Prior to 2.8 this forced any filters to load (all) their filtees.  This is
72227825Stheraven * now the default, however missing auxiliary filters don't generate any error
73227825Stheraven * diagniostic.  See also -L.
74227825Stheraven *
75227825Stheraven * If -L is specified we revert to lazy loading, thus any filtee or lazy
76227825Stheraven * dependency loading is deferred until relocations cause loading.  Without
77227825Stheraven * this option we set LD_LOADFLTR=1, thus forcing any filters to load (all)
78227825Stheraven * their filtees, and LD_NOLAZYLOAD=1 thus forcing immediate processing of
79227825Stheraven * any lazy loaded dependencies.
80227825Stheraven *
81227825Stheraven * If -s is specified we also set LD_TRACE_SEARCH_PATH=1, thus enabling
82227825Stheraven * the runtime linker to indicate the search algorithm used.
83227825Stheraven *
84227825Stheraven * If -v is specified we also set LD_VERBOSE=1, thus enabling the runtime
85227825Stheraven * linker to indicate all object dependencies (not just the first object
86227825Stheraven * loaded) together with any versionig requirements.
87227825Stheraven *
88227825Stheraven * If -U or -u is specified unused dependencies are detected.  -u causes
89227825Stheraven * LD_UNUSED=1 to be set, which causes dependencies that are unused within the
90227825Stheraven * process to be detected.  -U causes LD_UNREF=1 to be set, which causes
91227825Stheraven * unreferenced objects, and unreferenced cyclic dependencies to be detected.
92227825Stheraven * These options assert that at least -d is set as relocation references are
93227825Stheraven * what determine an objects use.
94227825Stheraven */
95227825Stheraven#include	<fcntl.h>
96227825Stheraven#include	<stdio.h>
97227825Stheraven#include	<string.h>
98227825Stheraven#include	<_libelf.h>
99227825Stheraven#include	<stdlib.h>
100227825Stheraven#include	<unistd.h>
101227825Stheraven#include	<wait.h>
102227825Stheraven#include	<locale.h>
103227825Stheraven#include	<errno.h>
104227825Stheraven#include	<signal.h>
105227825Stheraven#include	"machdep.h"
106227825Stheraven#include	"sgs.h"
107227825Stheraven#include	"conv.h"
108227825Stheraven#include	"a.out.h"
109227825Stheraven#include	"msg.h"
110227825Stheraven
111227825Stheravenstatic int	elf_check(int, char *, char *, Elf *, int);
112227825Stheravenstatic int	aout_check(int, char *, char *, int, int);
113227825Stheravenstatic int	run(int, char *, char *, const char *, int);
114227825Stheraven
115227825Stheraven
116227825Stheraven/*
117227825Stheraven * The following size definitions provide for allocating space for the string,
118227825Stheraven * or the string position at which any modifications to the variable will occur.
119227825Stheraven */
120227825Stheraven#define	LD_LOAD_SIZE		27
121227825Stheraven#define	LD_PATH_SIZE		23
122227825Stheraven#define	LD_BIND_SIZE		13
123227825Stheraven#define	LD_VERB_SIZE		12
124227825Stheraven#define	LD_WARN_SIZE		9
125227825Stheraven#define	LD_CONF_SIZE		13
126227825Stheraven#define	LD_FLTR_SIZE		13
127227825Stheraven#define	LD_LAZY_SIZE		15
128227825Stheraven#define	LD_INIT_SIZE		9
129227825Stheraven#define	LD_UREF_SIZE		10
130227825Stheraven#define	LD_USED_SIZE		11
131227825Stheraven
132227825Stheravenstatic char	bind[] =	"LD_BIND_NOW= ",
133227825Stheraven		load_elf[] =	"LD_TRACE_LOADED_OBJECTS_E= ",
134227825Stheraven		load_aout[] =	"LD_TRACE_LOADED_OBJECTS_A= ",
135227825Stheraven		path[] =	"LD_TRACE_SEARCH_PATHS= ",
136227825Stheraven		verb[] =	"LD_VERBOSE= ",
137227825Stheraven		warn[] =	"LD_WARN= ",
138227825Stheraven		conf[] =	"LD_NOCONFIG= ",
139227825Stheraven		fltr[] =	"LD_LOADFLTR= ",
140227825Stheraven		lazy[] =	"LD_NOLAZYLOAD=1",
141227825Stheraven		init[] =	"LD_INIT= ",
142227825Stheraven		uref[] =	"LD_UNREF= ",
143227825Stheraven		used[] =	"LD_UNUSED= ";
144227825Stheravenstatic char	*load;
145227825Stheraven
146227825Stheravenstatic const char	*prefile_32, *prefile_64, *prefile;
147227825Stheravenstatic List		eopts = { 0, 0 };
148227825Stheraven
149227825Stheraven/*
150227825Stheraven * Append an item to the specified list, and return a pointer to the list
151227825Stheraven * node created.
152227825Stheraven */
153227825StheravenListnode *
154227825Stheravenlist_append(List *lst, const void *item)
155227825Stheraven{
156227825Stheraven	Listnode	*lnp;
157227825Stheraven
158227825Stheraven	if ((lnp = malloc(sizeof (Listnode))) == (Listnode *)0)
159227825Stheraven		return (0);
160227825Stheraven
161227825Stheraven	lnp->data = (void *)item;
162227825Stheraven	lnp->next = NULL;
163227825Stheraven
164227825Stheraven	if (lst->head == NULL)
165227825Stheraven		lst->tail = lst->head = lnp;
166227825Stheraven	else {
167227825Stheraven		lst->tail->next = lnp;
168227825Stheraven		lst->tail = lst->tail->next;
169227825Stheraven	}
170227825Stheraven	return (lnp);
171227825Stheraven}
172227825Stheraven
173227825Stheravenint
174227825Stheravenmain(int argc, char **argv)
175227825Stheraven{
176227825Stheraven	char	*str, *cname = argv[0];
177227825Stheraven
178227825Stheraven	Elf	*elf;
179227825Stheraven	int	cflag = 0, dflag = 0, fflag = 0, iflag = 0, Lflag = 0;
180227825Stheraven	int	lflag = 0, rflag = 0, sflag = 0, Uflag = 0, uflag = 0;
181227825Stheraven	int	vflag = 0, nfile, var, error = 0;
182227825Stheraven
183227825Stheraven	Listnode	*lnp;
184227825Stheraven
185227825Stheraven	/*
186227825Stheraven	 * Establish locale.
187227825Stheraven	 */
188227825Stheraven	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
189227825Stheraven	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
190227825Stheraven
191227825Stheraven	/*
192227825Stheraven	 * verify command line syntax and process arguments
193227825Stheraven	 */
194227825Stheraven	opterr = 0;				/* disable getopt error mesg */
195227825Stheraven
196227825Stheraven	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_GETOPT))) != EOF) {
197227825Stheraven		switch (var) {
198227825Stheraven		case 'c' :			/* enable config search */
199227825Stheraven			cflag = 1;
200227825Stheraven			break;
201227825Stheraven		case 'd' :			/* perform data relocations */
202227825Stheraven			dflag = 1;
203227825Stheraven			if (rflag)
204227825Stheraven				error++;
205227825Stheraven			break;
206227825Stheraven		case 'e' :
207227825Stheraven			if (list_append(&eopts, optarg) == 0) {
208227825Stheraven				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
209227825Stheraven				    cname);
210227825Stheraven				exit(1);
211227825Stheraven			}
212227825Stheraven			break;
213227825Stheraven		case 'f' :
214227825Stheraven			fflag = 1;
215227825Stheraven			break;
216227825Stheraven		case 'L' :
217227825Stheraven			Lflag = 1;
218227825Stheraven			break;
219227825Stheraven		case 'l' :
220227825Stheraven			lflag = 1;
221227825Stheraven			break;
222227825Stheraven		case 'i' :			/* print the order of .init */
223227825Stheraven			iflag = 1;
224227825Stheraven			break;
225227825Stheraven		case 'r' :			/* perform all relocations */
226227825Stheraven			rflag = 1;
227227825Stheraven			if (dflag)
228227825Stheraven				error++;
229227825Stheraven			break;
230227825Stheraven		case 's' :			/* enable search path output */
231227825Stheraven			sflag = 1;
232227825Stheraven			break;
233227825Stheraven		case 'U' :			/* list unreferenced */
234227825Stheraven			Uflag = 1;		/*	dependencies */
235227825Stheraven			if (uflag)
236227825Stheraven				error++;
237227825Stheraven			break;
238227825Stheraven		case 'u' :			/* list unused dependencies */
239227825Stheraven			uflag = 1;
240227825Stheraven			if (Uflag)
241227825Stheraven				error++;
242227825Stheraven			break;
243227825Stheraven		case 'v' :			/* enable verbose output */
244227825Stheraven			vflag = 1;
245227825Stheraven			break;
246227825Stheraven		default :
247227825Stheraven			error++;
248227825Stheraven			break;
249227825Stheraven		}
250227825Stheraven		if (error)
251227825Stheraven			break;
252227825Stheraven	}
253227825Stheraven	if (error) {
254227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), cname);
255227825Stheraven		exit(1);
256227825Stheraven	}
257227825Stheraven
258227825Stheraven	/*
259227825Stheraven	 * Determine if any of the LD_PRELOAD family is already set in the
260227825Stheraven	 * environment, if so we'll continue to analyze each object with the
261227825Stheraven	 * appropriate setting.
262227825Stheraven	 */
263227825Stheraven	if (((prefile_32 = getenv(MSG_ORIG(MSG_LD_PRELOAD_32))) == NULL) ||
264227825Stheraven	    (*prefile_32 == '\0')) {
265227825Stheraven		prefile_32 = MSG_ORIG(MSG_STR_EMPTY);
266227825Stheraven	}
267227825Stheraven	if (((prefile_64 = getenv(MSG_ORIG(MSG_LD_PRELOAD_64))) == NULL) ||
268227825Stheraven	    (*prefile_64 == '\0')) {
269227825Stheraven		prefile_64 = MSG_ORIG(MSG_STR_EMPTY);
270227825Stheraven	}
271227825Stheraven	if (((prefile = getenv(MSG_ORIG(MSG_LD_PRELOAD))) == NULL) ||
272227825Stheraven	    (*prefile == '\0')) {
273227825Stheraven		prefile = MSG_ORIG(MSG_STR_EMPTY);
274227825Stheraven	}
275227825Stheraven
276227825Stheraven	/*
277227825Stheraven	 * Determine if any environment requests are for the LD_PRELOAD family,
278227825Stheraven	 * and if so override any environment settings we've established above.
279227825Stheraven	 */
280227825Stheraven	for (LIST_TRAVERSE(&eopts, lnp, str)) {
281227825Stheraven		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_32),
282227825Stheraven		    MSG_LD_PRELOAD_32_SIZE)) == 0) {
283227825Stheraven			str += MSG_LD_PRELOAD_32_SIZE;
284227825Stheraven			if ((*str++ == '=') && (*str != '\0'))
285227825Stheraven				prefile_32 = str;
286227825Stheraven			continue;
287227825Stheraven		}
288227825Stheraven		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_64),
289227825Stheraven		    MSG_LD_PRELOAD_64_SIZE)) == 0) {
290227825Stheraven			str += MSG_LD_PRELOAD_64_SIZE;
291227825Stheraven			if ((*str++ == '=') && (*str != '\0'))
292227825Stheraven				prefile_64 = str;
293227825Stheraven			continue;
294227825Stheraven		}
295227825Stheraven		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD),
296227825Stheraven		    MSG_LD_PRELOAD_SIZE)) == 0) {
297227825Stheraven			str += MSG_LD_PRELOAD_SIZE;
298227825Stheraven			if ((*str++ == '=') && (*str != '\0'))
299227825Stheraven				prefile = str;
300227825Stheraven			continue;
301227825Stheraven		}
302227825Stheraven	}
303227825Stheraven
304227825Stheraven	/*
305227825Stheraven	 * Set the appropriate relocation environment variables (Note unsetting
306227825Stheraven	 * the environment variables is done just in case the user already
307227825Stheraven	 * has these in their environment ... sort of thing the test folks
308227825Stheraven	 * would do :-)
309227825Stheraven	 */
310227825Stheraven	warn[LD_WARN_SIZE - 1] = (dflag || rflag || Uflag || uflag) ? '1' :
311227825Stheraven	    '\0';
312227825Stheraven	bind[LD_BIND_SIZE - 1] = (rflag) ? '1' : '\0';
313227825Stheraven	path[LD_PATH_SIZE - 1] = (sflag) ? '1' : '\0';
314227825Stheraven	verb[LD_VERB_SIZE - 1] = (vflag) ? '1' : '\0';
315227825Stheraven	fltr[LD_FLTR_SIZE - 1] = (Lflag) ? '\0' : (lflag) ? '2' : '1';
316227825Stheraven	init[LD_INIT_SIZE - 1] = (iflag) ? '1' : '\0';
317227825Stheraven	conf[LD_CONF_SIZE - 1] = (cflag) ? '1' : '\0';
318227825Stheraven	lazy[LD_LAZY_SIZE - 1] = (Lflag) ? '\0' : '1';
319227825Stheraven	uref[LD_UREF_SIZE - 1] = (Uflag) ? '1' : '\0';
320227825Stheraven	used[LD_USED_SIZE - 1] = (uflag) ? '1' : '\0';
321227825Stheraven
322227825Stheraven	/*
323227825Stheraven	 * coordinate libelf's version information
324227825Stheraven	 */
325227825Stheraven	if (elf_version(EV_CURRENT) == EV_NONE) {
326227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIBELF), cname,
327227825Stheraven		    EV_CURRENT);
328227825Stheraven		exit(1);
329227825Stheraven	}
330227825Stheraven
331227825Stheraven	/*
332227825Stheraven	 * Loop through remaining arguments.  Note that from here on there
333227825Stheraven	 * are no exit conditions so that we can process a list of files,
334227825Stheraven	 * any error condition is retained for a final exit status.
335227825Stheraven	 */
336227825Stheraven	nfile = argc - optind;
337227825Stheraven	for (; optind < argc; optind++) {
338227825Stheraven		char	*fname = argv[optind];
339227825Stheraven
340227825Stheraven		/*
341227825Stheraven		 * Open file (do this before checking access so that we can
342227825Stheraven		 * provide the user with better diagnostics).
343227825Stheraven		 */
344227825Stheraven		if ((var = open(fname, O_RDONLY)) == -1) {
345227825Stheraven			int	err = errno;
346227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), cname,
347227825Stheraven			    fname, strerror(err));
348227825Stheraven			error = 1;
349227825Stheraven			continue;
350227825Stheraven		}
351227825Stheraven
352227825Stheraven		/*
353227825Stheraven		 * Get the files elf descriptor and process it as an elf or
354227825Stheraven		 * a.out (4.x) file.
355227825Stheraven		 */
356227825Stheraven		elf = elf_begin(var, ELF_C_READ, (Elf *)0);
357227825Stheraven		switch (elf_kind(elf)) {
358227825Stheraven		case ELF_K_AR :
359227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO),
360227825Stheraven			    cname, fname);
361227825Stheraven			error = 1;
362227825Stheraven			break;
363227825Stheraven		case ELF_K_COFF:
364227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN),
365227825Stheraven			    cname, fname);
366227825Stheraven			error = 1;
367227825Stheraven			break;
368227825Stheraven		case ELF_K_ELF:
369227825Stheraven			if (elf_check(nfile, fname, cname, elf, fflag) != NULL)
370227825Stheraven				error = 1;
371227825Stheraven			break;
372227825Stheraven		default:
373227825Stheraven			/*
374227825Stheraven			 * This is either an unknown file or an aout format
375227825Stheraven			 */
376227825Stheraven			if (aout_check(nfile, fname, cname, var, fflag) != NULL)
377227825Stheraven				error = 1;
378227825Stheraven			break;
379227825Stheraven		}
380227825Stheraven		(void) elf_end(elf);
381227825Stheraven		(void) close(var);
382227825Stheraven	}
383227825Stheraven	return (error);
384227825Stheraven}
385227825Stheraven
386227825Stheraven
387227825Stheraven
388227825Stheravenstatic int
389227825Stheravenis_runnable(GElf_Ehdr *ehdr)
390227825Stheraven{
391227825Stheraven	if ((ehdr->e_ident[EI_CLASS] == M_CLASS) &&
392227825Stheraven	    (ehdr->e_ident[EI_DATA] == M_DATA))
393227825Stheraven		return (ELFCLASS32);
394227825Stheraven
395227825Stheraven#if	defined(sparc)
396227825Stheraven	if ((ehdr->e_machine == EM_SPARCV9) &&
397227825Stheraven	    (ehdr->e_ident[EI_DATA] == M_DATA) &&
398227825Stheraven	    (conv_sys_eclass() == ELFCLASS64))
399227825Stheraven		return (ELFCLASS64);
400227825Stheraven#elif	defined(i386) || defined(__amd64)
401227825Stheraven	if ((ehdr->e_machine == EM_AMD64) &&
402227825Stheraven	    (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) &&
403227825Stheraven	    (conv_sys_eclass() == ELFCLASS64))
404227825Stheraven		return (ELFCLASS64);
405227825Stheraven#endif
406227825Stheraven
407227825Stheraven	return (ELFCLASSNONE);
408227825Stheraven}
409227825Stheraven
410227825Stheraven
411227825Stheravenstatic int
412227825Stheravenelf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
413227825Stheraven{
414227825Stheraven	GElf_Ehdr 	ehdr;
415227825Stheraven	GElf_Phdr 	phdr;
416227825Stheraven	int		dynamic = 0, interp = 0, cnt, class;
417227825Stheraven
418227825Stheraven	/*
419227825Stheraven	 * verify information in file header
420227825Stheraven	 */
421227825Stheraven	if (gelf_getehdr(elf, &ehdr) == NULL) {
422227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR),
423227825Stheraven			cname, fname, elf_errmsg(-1));
424227825Stheraven		return (1);
425227825Stheraven	}
426227825Stheraven
427227825Stheraven	/*
428227825Stheraven	 * check class and encoding
429227825Stheraven	 */
430227825Stheraven	if ((class = is_runnable(&ehdr)) == ELFCLASSNONE) {
431227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_ELF_CLASSDATA),
432227825Stheraven			cname, fname);
433227825Stheraven		return (1);
434227825Stheraven	}
435227825Stheraven
436227825Stheraven	/*
437227825Stheraven	 * check type
438227825Stheraven	 */
439227825Stheraven	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN) &&
440227825Stheraven	    (ehdr.e_type != ET_REL)) {
441227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_ELF_BADMAGIC),
442227825Stheraven			cname, fname);
443227825Stheraven		return (1);
444227825Stheraven	}
445227825Stheraven	if ((class == ELFCLASS32) && (ehdr.e_machine != M_MACH)) {
446227825Stheraven		if (ehdr.e_machine != M_MACHPLUS) {
447227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHTYPE),
448227825Stheraven				cname, fname);
449227825Stheraven			return (1);
450227825Stheraven		}
451227825Stheraven		if ((ehdr.e_flags & M_FLAGSPLUS) == 0) {
452227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHFLAGS),
453227825Stheraven				cname, fname);
454227825Stheraven			return (1);
455227825Stheraven		}
456227825Stheraven	}
457227825Stheraven
458227825Stheraven	/*
459227825Stheraven	 * Check that the file is executable.  Dynamic executables must be
460227825Stheraven	 * executable to be exec'ed.  Shared objects need not be executable to
461227825Stheraven	 * be mapped with a dynamic executable, however, by convention they're
462227825Stheraven	 * supposed to be executable.
463227825Stheraven	 */
464227825Stheraven	if (access(fname, X_OK) != 0) {
465227825Stheraven		if (ehdr.e_type == ET_EXEC) {
466227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_1),
467227825Stheraven				cname, fname);
468227825Stheraven			return (1);
469227825Stheraven		}
470227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_2), cname,
471227825Stheraven		    fname);
472227825Stheraven	}
473227825Stheraven
474227825Stheraven	/*
475227825Stheraven	 * Determine whether we have a dynamic section or interpretor.
476227825Stheraven	 */
477227825Stheraven	for (cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) {
478227825Stheraven		if (dynamic && interp)
479227825Stheraven			break;
480227825Stheraven
481227825Stheraven		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
482227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETPHDR),
483227825Stheraven				cname, fname, elf_errmsg(-1));
484227825Stheraven			return (1);
485227825Stheraven		}
486227825Stheraven
487227825Stheraven		if (phdr.p_type == PT_DYNAMIC) {
488227825Stheraven			dynamic = 1;
489227825Stheraven			continue;
490227825Stheraven		}
491227825Stheraven
492227825Stheraven		if (phdr.p_type != PT_INTERP)
493227825Stheraven			continue;
494227825Stheraven
495227825Stheraven		interp = 1;
496227825Stheraven
497227825Stheraven		/*
498227825Stheraven		 * If fflag is not set, and euid == root, and the interpreter
499227825Stheraven		 * does not live under /lib, /usr/lib or /etc/lib then don't
500227825Stheraven		 * allow ldd to execute the image.  This prevents someone
501227825Stheraven		 * creating a `trojan horse' by substituting their own
502227825Stheraven		 * interpreter that could preform privileged operations
503227825Stheraven		 * when ldd is against it.
504227825Stheraven		 */
505227825Stheraven		if ((fflag == 0) && (geteuid() == 0) &&
506227825Stheraven		    (strcmp(fname, conv_lddstub(class)) != 0)) {
507227825Stheraven			char	*interpreter;
508227825Stheraven
509227825Stheraven			/*
510227825Stheraven			 * Does the interpreter live under a trusted directory.
511227825Stheraven			 */
512227825Stheraven			interpreter = elf_getident(elf, 0) + phdr.p_offset;
513227825Stheraven
514227825Stheraven			if ((strncmp(interpreter, MSG_ORIG(MSG_PTH_USRLIB),
515227825Stheraven			    MSG_PTH_USRLIB_SIZE) != 0) &&
516227825Stheraven			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_LIB),
517227825Stheraven			    MSG_PTH_LIB_SIZE) != 0) &&
518227825Stheraven			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_ETCLIB),
519227825Stheraven			    MSG_PTH_ETCLIB_SIZE) != 0)) {
520227825Stheraven				(void) fprintf(stderr, MSG_INTL(MSG_USP_ELFINS),
521227825Stheraven					cname, fname, interpreter);
522227825Stheraven				return (1);
523227825Stheraven			}
524227825Stheraven		}
525227825Stheraven	}
526227825Stheraven
527227825Stheraven	/*
528227825Stheraven	 * Catch the case of a static executable (ie, an ET_EXEC that has a set
529227825Stheraven	 * of program headers but no PT_DYNAMIC).
530227825Stheraven	 */
531227825Stheraven	if (ehdr.e_phnum && !dynamic) {
532227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
533227825Stheraven		    fname);
534227825Stheraven		return (1);
535227825Stheraven	}
536227825Stheraven
537227825Stheraven	/*
538227825Stheraven	 * If there is a dynamic section, then check for the DF_1_NOHDR
539227825Stheraven	 * flag, and bail if it is present. Those objects are created using
540227825Stheraven	 * the ?N mapfile option: The ELF header and program headers are
541227825Stheraven	 * not mapped as part of the first segment, and virtual addresses
542227825Stheraven	 * are computed without them. If ldd tries to interpret such
543227825Stheraven	 * a file, it will become confused and generate bad output or
544227825Stheraven	 * crash. Such objects are always special purpose files (like an OS
545227825Stheraven	 * kernel) --- files for which the ldd operation doesn't make sense.
546227825Stheraven	 */
547227825Stheraven	if (dynamic && (_gelf_getdyndtflags_1(elf) & DF_1_NOHDR)) {
548227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOHDR), cname,
549227825Stheraven		    fname);
550227825Stheraven		return (1);
551227825Stheraven	}
552227825Stheraven
553227825Stheraven	load = load_elf;
554227825Stheraven
555227825Stheraven	/*
556227825Stheraven	 * Run the required program (shared and relocatable objects require the
557227825Stheraven	 * use of lddstub).
558232950Stheraven	 */
559227825Stheraven	if ((ehdr.e_type == ET_EXEC) && interp)
560227825Stheraven		return (run(nfile, cname, fname, (const char *)fname, class));
561227825Stheraven	else
562227825Stheraven		return (run(nfile, cname, fname, conv_lddstub(class), class));
563227825Stheraven}
564227825Stheraven
565227825Stheraven
566227825Stheravenstatic int
567227825Stheravenaout_check(int nfile, char *fname, char *cname, int fd, int fflag)
568227825Stheraven{
569227825Stheraven	struct exec	aout;
570227825Stheraven	int		err;
571227825Stheraven
572227825Stheraven	if (lseek(fd, 0, SEEK_SET) != 0) {
573227825Stheraven		err = errno;
574227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname,
575227825Stheraven		    strerror(err));
576227825Stheraven		return (1);
577227825Stheraven	}
578227825Stheraven	if (read(fd, (char *)&aout, sizeof (struct exec)) !=
579227825Stheraven	    sizeof (struct exec)) {
580227825Stheraven		err = errno;
581227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname,
582227825Stheraven		    strerror(err));
583227825Stheraven		return (1);
584227825Stheraven	}
585227825Stheraven	if (aout.a_machtype != M_SPARC) {
586227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname);
587227825Stheraven		return (1);
588227825Stheraven	}
589227825Stheraven	if (N_BADMAG(aout) || !aout.a_dynamic) {
590227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
591227825Stheraven		    fname);
592227825Stheraven		return (1);
593227825Stheraven	}
594227825Stheraven	if (!fflag && (geteuid() == 0)) {
595227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname);
596227825Stheraven		return (1);
597227825Stheraven	}
598227825Stheraven
599227825Stheraven	/*
600227825Stheraven	 * Run the required program.
601227825Stheraven	 */
602227825Stheraven	if ((aout.a_magic == ZMAGIC) &&
603227825Stheraven	    (aout.a_entry <= sizeof (struct exec))) {
604227825Stheraven		load = load_elf;
605227825Stheraven		return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32),
606227825Stheraven		    ELFCLASS32));
607227825Stheraven	} else {
608227825Stheraven		load = load_aout;
609227825Stheraven		return (run(nfile, cname, fname, (const char *)fname,
610227825Stheraven		    ELFCLASS32));
611227825Stheraven	}
612227825Stheraven}
613227825Stheraven
614227825Stheraven
615227825Stheraven/*
616227825Stheraven * Run the required program, setting the preload and trace environment
617227825Stheraven * variables accordingly.
618227825Stheraven */
619227825Stheravenstatic int
620227825Stheravenrun(int nfile, char *cname, char *fname, const char *ename, int class)
621227825Stheraven{
622227825Stheraven	const char	*preload = 0;
623227825Stheraven	int		pid, status;
624232950Stheraven
625227825Stheraven	if ((pid = fork()) == -1) {
626227825Stheraven		int	err = errno;
627227825Stheraven		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), cname,
628227825Stheraven		    strerror(err));
629227825Stheraven		return (1);
630227825Stheraven	}
631227825Stheraven
632227825Stheraven	if (pid) {				/* parent */
633227825Stheraven		while (wait(&status) != pid)
634227825Stheraven			;
635227825Stheraven		if (WIFSIGNALED(status) && ((WSIGMASK & status) != SIGPIPE)) {
636227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
637227825Stheraven			    fname);
638227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_SIG),
639227825Stheraven			    (WSIGMASK & status), ((status & WCOREFLG) ?
640227825Stheraven			    MSG_INTL(MSG_SYS_EXEC_CORE) :
641227825Stheraven			    MSG_ORIG(MSG_STR_EMPTY)));
642227825Stheraven			status = 1;
643227825Stheraven		} else if (WHIBYTE(status)) {
644227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
645227825Stheraven			    fname);
646227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_STAT),
647227825Stheraven			    WHIBYTE(status));
648227825Stheraven			status = 1;
649227825Stheraven		}
650227825Stheraven	} else {				/* child */
651227825Stheraven		Listnode	*lnp;
652227825Stheraven		char		*str;
653227825Stheraven		size_t		size;
654227825Stheraven
655227825Stheraven		/*
656227825Stheraven		 * When using ldd(1) to analyze a shared object we preload the
657227825Stheraven		 * shared object with lddstub.  Any additional preload
658227825Stheraven		 * requirements are added after the object being analyzed, this
659227825Stheraven		 * allows us to skip the first object but produce diagnostics
660227825Stheraven		 * for each other preloaded object.
661227825Stheraven		 */
662227825Stheraven		if (fname != ename) {
663227825Stheraven			char		*str;
664227825Stheraven			const char	*files = prefile;
665227825Stheraven			const char	*format = MSG_ORIG(MSG_STR_FMT1);
666227825Stheraven
667227825Stheraven			for (str = fname; *str; str++)
668227825Stheraven				if (*str == '/') {
669227825Stheraven					format = MSG_ORIG(MSG_STR_FMT2);
670227825Stheraven					break;
671227825Stheraven			}
672227825Stheraven
673227825Stheraven			preload = MSG_ORIG(MSG_LD_PRELOAD);
674227825Stheraven
675227825Stheraven			/*
676227825Stheraven			 * Determine which preload files and preload environment
677227825Stheraven			 * variable to use.
678227825Stheraven			 */
679227825Stheraven			if (class == ELFCLASS64) {
680227825Stheraven				if (prefile_64 != MSG_ORIG(MSG_STR_EMPTY)) {
681227825Stheraven					files = prefile_64;
682227825Stheraven					preload = MSG_ORIG(MSG_LD_PRELOAD_64);
683227825Stheraven				}
684227825Stheraven			} else {
685227825Stheraven				if (prefile_32 != MSG_ORIG(MSG_STR_EMPTY)) {
686227825Stheraven					files = prefile_32;
687227825Stheraven					preload = MSG_ORIG(MSG_LD_PRELOAD_32);
688227825Stheraven				}
689227825Stheraven			}
690227825Stheraven
691227825Stheraven			if ((str = (char *)malloc(strlen(preload) +
692227825Stheraven			    strlen(fname) + strlen(files) + 5)) == 0) {
693227825Stheraven				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
694227825Stheraven				    cname);
695227825Stheraven				exit(1);
696227825Stheraven			}
697227825Stheraven
698227825Stheraven			(void) sprintf(str, format, preload, fname, files);
699227825Stheraven			if (putenv(str) != 0) {
700227825Stheraven				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
701227825Stheraven				    cname);
702227825Stheraven				exit(1);
703227825Stheraven			}
704227825Stheraven			load[LD_LOAD_SIZE - 1] = '2';
705227825Stheraven		} else
706227825Stheraven			load[LD_LOAD_SIZE - 1] = '1';
707227825Stheraven
708227825Stheraven
709227825Stheraven		/*
710227825Stheraven		 * Establish new environment variables to affect the child
711227825Stheraven		 * process.
712227825Stheraven		 */
713227825Stheraven		if ((putenv(warn) != 0) || (putenv(bind) != 0) ||
714227825Stheraven		    (putenv(path) != 0) || (putenv(verb) != 0) ||
715227825Stheraven		    (putenv(fltr) != 0) || (putenv(conf) != 0) ||
716227825Stheraven		    (putenv(init) != 0) || (putenv(lazy) != 0) ||
717227825Stheraven		    (putenv(uref) != 0) || (putenv(used) != 0) ||
718227825Stheraven		    (putenv(load) != 0)) {
719227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED), cname);
720227825Stheraven			exit(1);
721227825Stheraven		}
722227825Stheraven
723227825Stheraven		/*
724227825Stheraven		 * Establish explicit environment requires (but don't override
725227825Stheraven		 * any preload request established to process a shared object).
726227825Stheraven		 */
727227825Stheraven		size = 0;
728227825Stheraven		for (LIST_TRAVERSE(&eopts, lnp, str)) {
729227825Stheraven			if (preload) {
730227825Stheraven				if (size == 0)
731227825Stheraven					size = strlen(preload);
732227825Stheraven				if ((strncmp(preload, str, size) == 0) &&
733227825Stheraven				    (str[size] == '=')) {
734227825Stheraven					continue;
735227825Stheraven				}
736227825Stheraven			}
737227825Stheraven			if (putenv(str) != 0) {
738227825Stheraven				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
739227825Stheraven				    cname);
740227825Stheraven				exit(1);
741227825Stheraven			}
742227825Stheraven		}
743227825Stheraven
744227825Stheraven		/*
745227825Stheraven		 * Execute the object and let ld.so.1 do the rest.
746227825Stheraven		 */
747227825Stheraven		if (nfile > 1)
748227825Stheraven			(void) printf(MSG_ORIG(MSG_STR_FMT3), fname);
749227825Stheraven		(void) fflush(stdout);
750227825Stheraven		if ((execl(ename, ename, (char *)0)) == -1) {
751227825Stheraven			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
752227825Stheraven			    fname);
753227825Stheraven			perror(ename);
754227825Stheraven			_exit(0);
755227825Stheraven			/* NOTREACHED */
756227825Stheraven		}
757227825Stheraven	}
758227825Stheraven	return (status);
759227825Stheraven}
760227825Stheraven
761227825Stheravenconst char *
762227825Stheraven_ldd_msg(Msg mid)
763227825Stheraven{
764227825Stheraven	return (gettext(MSG_ORIG(mid)));
765227825Stheraven}
766227825Stheraven