config_elf.c revision 11827:d7ef53deac3f
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include	<sys/mman.h>
28#include	<sys/types.h>
29#include	<sys/stat.h>
30#include	<fcntl.h>
31#include	<limits.h>
32#include	<stdio.h>
33#include	<string.h>
34#include	<rtc.h>
35#include	<debug.h>
36#include	<conv.h>
37#include	"_rtld.h"
38#include	"msg.h"
39
40static Config	_config = { 0 };
41Config		*config = &_config;
42
43/*
44 * Validate a configuration file.
45 */
46static void
47elf_config_validate(Addr addr, Rtc_head *head, Rt_map *lmp)
48{
49	Lm_list		*lml = LIST(lmp);
50	const char	*str, *strtbl = config->c_strtbl;
51	Rtc_obj		*obj;
52	Rtc_dir		*dirtbl;
53	Rtc_file	*filetbl;
54	rtld_stat_t	status;
55	int		err;
56
57	/*
58	 * If this configuration file is for a specific application make sure
59	 * we've been invoked by the application.  Note that we only check the
60	 * basename component of the application as the original application
61	 * and its cached equivalent are never going to have the same pathnames.
62	 * Also, we use PATHNAME() and not NAME() - this catches things like vi
63	 * that exec shells using execv(/usr/bin/ksh, sh ...).
64	 */
65	if (head->ch_app) {
66		char		*_str, *_cname, *cname;
67		const char	*aname = PATHNAME(lmp);
68
69		obj = (Rtc_obj *)(head->ch_app + addr);
70		cname = _cname = (char *)(strtbl + obj->co_name);
71
72		if ((_str = strrchr(aname, '/')) != NULL)
73			aname = ++_str;
74		if ((_str = strrchr(cname, '/')) != NULL)
75			cname = ++_str;
76
77		if (strcmp(aname, cname)) {
78			/*
79			 * It's possible a user is trying to ldd(1) an alternate
80			 * shared object and point to a configuration file that
81			 * the shared object is part of.  In this case ignore
82			 * any mismatch name warnings.
83			 */
84			if ((lml->lm_flags & LML_FLG_TRC_ENABLE) &&
85			    ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0)) {
86				eprintf(lml, ERR_WARNING,
87				    MSG_INTL(MSG_CONF_APP), config->c_name,
88				    _cname);
89				return;
90			}
91		}
92
93		/*
94		 * If we have a valid alternative application reset its original
95		 * name for possible $ORIGIN processing.
96		 */
97		if ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0) {
98			ORIGNAME(lmp) = _cname;
99			DIRSZ(lmp) = cname - _cname - 1;
100		}
101	}
102
103	/*
104	 * If alternative objects are specified traverse the directories
105	 * specified in the configuration file, if any directory is newer than
106	 * the time it was recorded in the cache then continue to inspect its
107	 * files.  Any file determined newer than its configuration recording
108	 * questions the the use of any alternative objects.  The intent here
109	 * is to make sure no-one abuses a configuration as a means of static
110	 * linking.
111	 */
112	for (dirtbl = (Rtc_dir *)(head->ch_dir + addr);
113	    dirtbl->cd_obj; dirtbl++) {
114		/*
115		 * Skip directories that provide no files - this also catches
116		 * RTC_OBJ_NOEXIST directories.
117		 */
118		filetbl = (Rtc_file *)(dirtbl->cd_file + addr);
119		if (filetbl->cf_obj == NULL)
120			continue;
121
122		/*
123		 * Skip directories that haven't provided real, dumped files.
124		 */
125		obj = (Rtc_obj *)(dirtbl->cd_obj + addr);
126		if ((obj->co_flags & (RTC_OBJ_DUMP | RTC_OBJ_REALPTH)) !=
127		    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH))
128			continue;
129
130		str = strtbl + obj->co_name;
131
132		if (rtld_stat(str, &status) != 0) {
133			err = errno;
134			eprintf(lml, ERR_WARNING, MSG_INTL(MSG_CONF_DSTAT),
135			    config->c_name, str, strerror(err));
136			continue;
137		}
138
139		if (status.st_mtime == obj->co_info)
140			continue;
141
142		/*
143		 * The system directory is newer than the configuration files
144		 * entry, start checking any dumped files.
145		 */
146		for (; filetbl->cf_obj; filetbl++) {
147			obj = (Rtc_obj *)(filetbl->cf_obj + addr);
148			str = strtbl + obj->co_name;
149
150			/*
151			 * Skip any files that aren't real, dumped files.
152			 */
153			if ((obj->co_flags &
154			    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH)) !=
155			    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH))
156				continue;
157
158			if (rtld_stat(str, &status) != 0) {
159				err = errno;
160				eprintf(lml, ERR_WARNING,
161				    MSG_INTL(MSG_CONF_FSTAT), config->c_name,
162				    str, strerror(err));
163				continue;
164			}
165
166			/*
167			 * If the files size is different somethings been
168			 * changed.
169			 */
170			if (status.st_size != obj->co_info) {
171				eprintf(lml, ERR_WARNING,
172				    MSG_INTL(MSG_CONF_FCMP), config->c_name,
173				    str);
174			}
175		}
176	}
177}
178
179/*
180 * Process a configuration file.
181 *
182 * A configuration file can be specified using the LD_CONFIG environment
183 * variable, from a DT_CONFIG string recorded in the executable (see ld(1) -c),
184 * or in the case of a crle() dumped image, the file is "fabricated" to a
185 * configuration file that may have been associated with the dumped image.  In
186 * the absence of any of these techniques, a default configuration file is used.
187 *
188 * The LD_CONFIG variable take precedence, unless the application is secure, in
189 * which case the environment variable is ignored (see ld_generic_env()).
190 *
191 * A DT_CONFIG string is honored, even if the application is secure.  However,
192 * the path name follows the same rules as RUNPATH's, which must be a full path
193 * name with no use of $ORIGIN.
194 */
195int
196elf_config(Rt_map *lmp, int aout)
197{
198	Rtc_id		*id;
199	Rtc_head	*head;
200	int		fd, features = 0;
201	rtld_stat_t	status;
202	Addr		addr;
203	const char	*str;
204	char		path[PATH_MAX];
205
206	/*
207	 * If we're dealing with an alternative application, fabricate the need
208	 * for a $ORIGIN/ld.config.app-name configuration file.
209	 */
210	if (rtld_flags & RT_FL_CONFAPP) {
211		if ((str = strrchr(PATHNAME(lmp), '/')) != NULL)
212			str++;
213		else
214			str = PATHNAME(lmp);
215
216		(void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_ORG_CONFIG), str);
217		str = path;
218	} else
219		str = config->c_name;
220
221	/*
222	 * If a configuration file name is known, expand and verify the name.
223	 */
224	if (str) {
225		size_t	size = strlen(str);
226		char	*estr = (char *)str;
227		uint_t	tkns;
228
229		/*
230		 * Expand any configuration string.
231		 */
232		if ((tkns = expand(&estr, &size, 0, 0,
233		    (PD_TKN_ISALIST | PD_TKN_CAP), lmp)) == 0)
234			return (0);
235
236		/*
237		 * If this is a secure application, validate the configuration
238		 * file path name.  Ignore any untrustworthy path name, and
239		 * fall through to pick up the defaults.
240		 */
241		if ((rtld_flags & RT_FL_SECURE) &&
242		    (is_path_secure(estr, lmp, PD_FLG_FULLPATH, tkns) == 0))
243			str = NULL;
244		else
245			str = (const char *)estr;
246	}
247
248	/*
249	 * If a configuration file has not been specified try opening up the
250	 * default.
251	 */
252	if (str == NULL) {
253#if	defined(_ELF64)
254		str = MSG_ORIG(MSG_PTH_CONFIG_64);
255#else
256		str = MSG_ORIG(MSG_PTH_CONFIG);
257#endif
258	}
259	config->c_name = str;
260
261	/*
262	 * If we can't open the configuration file return silently.
263	 */
264	if ((fd = open(str, O_RDONLY, 0)) == -1)
265		return (DBG_CONF_PRCFAIL);
266
267	/*
268	 * Determine the configuration file size and map the file.
269	 */
270	(void) rtld_fstat(fd, &status);
271	if (status.st_size < sizeof (Rtc_head)) {
272		(void) close(fd);
273		return (DBG_CONF_CORRUPT);
274	}
275	if ((addr = (Addr)mmap(0, status.st_size, PROT_READ, MAP_SHARED,
276	    fd, 0)) == (Addr)MAP_FAILED) {
277		(void) close(fd);
278		return (DBG_CONF_PRCFAIL);
279	}
280	(void) close(fd);
281
282	/*
283	 * If we have an Rtc_id block at the beginning, then validate it
284	 * and advance the address to the Rtc_head. If not, then trust
285	 * that the file is compatible with us and move ahead (there is
286	 * some error checking for Rtc_head below as well).
287	 */
288	id = (Rtc_id *) addr;
289	if (RTC_ID_TEST(id)) {
290		addr += sizeof (*id);
291		status.st_size -= sizeof (*id);
292		if (status.st_size < sizeof (Rtc_head))
293			return (DBG_CONF_CORRUPT);
294		if ((id->id_class != M_CLASS) || (id->id_data != M_DATA) ||
295		    (id->id_machine != M_MACH))
296			return (DBG_CONF_ABIMISMATCH);
297	}
298
299	config->c_bgn = addr;
300	config->c_end = addr + status.st_size;
301
302	head = (Rtc_head *)addr;
303
304	/*
305	 * Make sure we can handle this version of the configuration file.
306	 */
307	if (head->ch_version > RTC_VER_CURRENT)
308		return (DBG_CONF_VERSION);
309
310	/*
311	 * When crle(1) creates a temporary configuration file the
312	 * RTC_HDR_IGNORE flag is set.  Thus the mapping of the configuration
313	 * file is taken into account but not its content.
314	 */
315	if (head->ch_cnflags & RTC_HDR_IGNORE)
316		return (DBG_CONF_IGNORE);
317
318	/*
319	 * Apply any new default library pathname.
320	 */
321	if (head->ch_edlibpath) {
322		str = (const char *)(head->ch_edlibpath + addr);
323#ifndef	SGS_PRE_UNIFIED_PROCESS
324		if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
325#if	defined(_ELF64)
326			str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIB_64),
327			    MSG_ORIG(MSG_PTH_LIB_64), MSG_PTH_LIB_64_SIZE);
328#else
329			str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIB),
330			    MSG_ORIG(MSG_PTH_LIB), MSG_PTH_LIB_SIZE);
331#endif
332		}
333#endif
334		if (expand_paths(lmp, str, &elf_def_dirs, AL_CNT_SEARCH,
335		    (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
336			features |= CONF_EDLIBPATH;
337	}
338	if (head->ch_eslibpath) {
339		str = (const char *)(head->ch_eslibpath + addr);
340#ifndef	SGS_PRE_UNIFIED_PROCESS
341		if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
342#if	defined(_ELF64)
343			str = conv_config_upm(str,
344			    MSG_ORIG(MSG_PTH_USRLIBSE_64),
345			    MSG_ORIG(MSG_PTH_LIBSE_64), MSG_PTH_LIBSE_64_SIZE);
346#else
347			str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIBSE),
348			    MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE);
349#endif
350		}
351#endif
352		if (expand_paths(lmp, str, &elf_sec_dirs, AL_CNT_SEARCH,
353		    (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
354			features |= CONF_ESLIBPATH;
355	}
356#if	defined(__sparc) && !defined(_ELF64)
357	if (head->ch_adlibpath) {
358		str = (const char *)(head->ch_adlibpath + addr);
359		if (expand_paths(lmp, str, &aout_def_dirs, AL_CNT_SEARCH,
360		    (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
361			features |= CONF_ADLIBPATH;
362	}
363	if (head->ch_aslibpath) {
364		str = (const char *)(head->ch_aslibpath + addr);
365		if (expand_paths(lmp, str, &aout_sec_dirs, AL_CNT_SEARCH,
366		    (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_CAP) != NULL)
367			features |= CONF_ASLIBPATH;
368	}
369#endif
370	/*
371	 * Apply any environment variables.  This attribute was added with
372	 * RTC_VER_THREE.
373	 */
374	if ((head->ch_version >= RTC_VER_THREE) && head->ch_env &&
375	    (!(rtld_flags & RT_FL_NOENVCFG))) {
376		if (readenv_config((Rtc_env *)(head->ch_env + addr),
377		    addr, aout) != 0)
378			return (-1);
379		features |= CONF_ENVS;
380	}
381
382	/*
383	 * Determine whether filter/filtee associations are available.
384	 */
385	if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr &&
386	    (!(rtld_flags2 & RT_FL2_NOFLTCFG))) {
387		rtld_flags2 |= RT_FL2_FLTCFG;
388		config->c_fltr = (Rtc_fltr *)(head->ch_fltr + addr);
389		config->c_flte = (Rtc_flte *)(head->ch_flte + addr);
390		features |= CONF_FLTR;
391	}
392
393	/*
394	 * Determine whether directory configuration is available.
395	 */
396	if ((!(rtld_flags & RT_FL_NODIRCFG)) && head->ch_hash) {
397		config->c_hashtbl = (Word *)(head->ch_hash + addr);
398		config->c_hashchain = &config->c_hashtbl[2 +
399		    config->c_hashtbl[0]];
400		config->c_objtbl = (Rtc_obj *)(head->ch_obj + addr);
401		config->c_strtbl = (const char *)(head->ch_str + addr);
402
403		rtld_flags |= RT_FL_DIRCFG;
404		features |= CONF_DIRCFG;
405	}
406
407	/*
408	 * Determine whether alternative objects are specified or an object
409	 * reservation area is required.  If the reservation can't be completed
410	 * (either because the configuration information is out-of-date, or the
411	 * the reservation can't be allocated), then alternative objects are
412	 * ignored.
413	 */
414	if ((!(rtld_flags & (RT_FL_NODIRCFG | RT_FL_NOOBJALT))) &&
415	    (head->ch_cnflags & RTC_HDR_ALTER)) {
416		rtld_flags |= RT_FL_OBJALT;
417		features |= CONF_OBJALT;
418
419		elf_config_validate(addr, head, lmp);
420
421		if (head->ch_resbgn) {
422
423			if (((config->c_bgn <= head->ch_resbgn) &&
424			    (config->c_bgn >= head->ch_resend)) ||
425			    (nu_map(LIST(lmp),
426			    (caddr_t)(uintptr_t)head->ch_resbgn,
427			    (head->ch_resend - head->ch_resbgn), PROT_NONE,
428			    MAP_FIXED | MAP_PRIVATE) == MAP_FAILED))
429				return (-1);
430
431			rtld_flags |= RT_FL_MEMRESV;
432			features |= CONF_MEMRESV;
433		}
434	}
435
436	return (features);
437}
438
439/*
440 * Determine whether the given file exists in the configuration file.
441 */
442Rtc_obj *
443elf_config_ent(const char *name, Word hash, int id, const char **alternate)
444{
445	Word		bkt, ndx;
446	const char	*str;
447	Rtc_obj		*obj;
448
449	bkt = hash % config->c_hashtbl[0];
450	ndx = config->c_hashtbl[2 + bkt];
451
452	while (ndx) {
453		obj = config->c_objtbl + ndx;
454		str = config->c_strtbl + obj->co_name;
455
456		if ((obj->co_hash != hash) || (strcmp(name, str) != 0) ||
457		    (id && (id != obj->co_id))) {
458			ndx = config->c_hashchain[ndx];
459			continue;
460		}
461
462		if ((obj->co_flags & RTC_OBJ_ALTER) && alternate)
463			*alternate = config->c_strtbl + obj->co_alter;
464
465		return (obj);
466	}
467	return (0);
468}
469
470/*
471 * Determine whether a filter and filtee string pair exists in the configuration
472 * file.  If so, return the cached filtees that are associated with this pair as
473 * an Alist.
474 */
475void
476elf_config_flt(Lm_list *lml, const char *filter, const char *string,
477    Alist **alpp, Aliste alni)
478{
479	Rtc_fltr	*fltrtbl;
480
481	for (fltrtbl = (Rtc_fltr *)config->c_fltr; fltrtbl->fr_filter;
482	    fltrtbl++) {
483		Rtc_flte	*fltetbl;
484		const char	*fltr, *str;
485
486		fltr = config->c_strtbl + fltrtbl->fr_filter;
487		str = config->c_strtbl + fltrtbl->fr_string;
488		if (strcmp(filter, fltr) || strcmp(string, str))
489			continue;
490
491		/*
492		 * Create a path descriptor for each filtee associated with this
493		 * filter/filtee string pair.  Note, no expansion of filtee
494		 * entries is called for, as any original expansion would have
495		 * been carried out before they were recorded in the
496		 * configuration file.
497		 */
498		/* LINTED */
499		for (fltetbl = (Rtc_flte *)((char *)config->c_flte +
500		    fltrtbl->fr_filtee); fltetbl->fe_filtee; fltetbl++) {
501			const char	*flte;
502			Pdesc		*pdp;
503
504			flte = config->c_strtbl + fltetbl->fe_filtee;
505
506			if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc),
507			    alni)) == NULL)
508				return;
509
510			pdp->pd_pname = (char *)flte;
511			pdp->pd_plen = strlen(flte) + 1;
512			pdp->pd_flags = LA_SER_CONFIG;
513
514			DBG_CALL(Dbg_file_filter(lml, fltr, flte, 1));
515		}
516	}
517}
518