xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/config_elf.c (revision 257873cfc1dd3337766407f80397db60a56f2f5a)
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 2008 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 
40 static Config	_config = { 0 };
41 Config		*config = &_config;
42 
43 /*
44  * Validate a configuration file.
45  */
46 static void
47 elf_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 	struct stat	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, *aname = PATHNAME(lmp);
67 
68 		obj = (Rtc_obj *)(head->ch_app + addr);
69 		cname = _cname = (char *)(strtbl + obj->co_name);
70 
71 		if ((_str = strrchr(aname, '/')) != NULL)
72 			aname = ++_str;
73 		if ((_str = strrchr(cname, '/')) != NULL)
74 			cname = ++_str;
75 
76 		if (strcmp(aname, cname)) {
77 			/*
78 			 * It's possible a user is trying to ldd(1) an alternate
79 			 * shared object and point to a configuration file that
80 			 * the shared object is part of.  In this case ignore
81 			 * any mismatch name warnings.
82 			 */
83 			if ((lml->lm_flags & LML_FLG_TRC_ENABLE) &&
84 			    ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0)) {
85 				eprintf(lml, ERR_WARNING,
86 				    MSG_INTL(MSG_CONF_APP), config->c_name,
87 				    _cname);
88 				return;
89 			}
90 		}
91 
92 		/*
93 		 * If we have a valid alternative application reset its original
94 		 * name for possible $ORIGIN processing.
95 		 */
96 		if ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0) {
97 			ORIGNAME(lmp) = _cname;
98 			DIRSZ(lmp) = cname - _cname - 1;
99 		}
100 	}
101 
102 	/*
103 	 * If alternative objects are specified traverse the directories
104 	 * specified in the configuration file, if any directory is newer than
105 	 * the time it was recorded in the cache then continue to inspect its
106 	 * files.  Any file determined newer than its configuration recording
107 	 * questions the the use of any alternative objects.  The intent here
108 	 * is to make sure no-one abuses a configuration as a means of static
109 	 * linking.
110 	 */
111 	for (dirtbl = (Rtc_dir *)(head->ch_dir + addr);
112 	    dirtbl->cd_obj; dirtbl++) {
113 		/*
114 		 * Skip directories that provide no files - this also catches
115 		 * RTC_OBJ_NOEXIST directories.
116 		 */
117 		filetbl = (Rtc_file *)(dirtbl->cd_file + addr);
118 		if (filetbl->cf_obj == NULL)
119 			continue;
120 
121 		/*
122 		 * Skip directories that haven't provided real, dumped files.
123 		 */
124 		obj = (Rtc_obj *)(dirtbl->cd_obj + addr);
125 		if ((obj->co_flags & (RTC_OBJ_DUMP | RTC_OBJ_REALPTH)) !=
126 		    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH))
127 			continue;
128 
129 		str = strtbl + obj->co_name;
130 
131 		if (stat(str, &status) != 0) {
132 			err = errno;
133 			eprintf(lml, ERR_WARNING, MSG_INTL(MSG_CONF_DSTAT),
134 			    config->c_name, str, strerror(err));
135 			continue;
136 		}
137 
138 		if (status.st_mtime == obj->co_info)
139 			continue;
140 
141 		/*
142 		 * The system directory is newer than the configuration files
143 		 * entry, start checking any dumped files.
144 		 */
145 		for (; filetbl->cf_obj; filetbl++) {
146 			obj = (Rtc_obj *)(filetbl->cf_obj + addr);
147 			str = strtbl + obj->co_name;
148 
149 			/*
150 			 * Skip any files that aren't real, dumped files.
151 			 */
152 			if ((obj->co_flags &
153 			    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH)) !=
154 			    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH))
155 				continue;
156 
157 			if (stat(str, &status) != 0) {
158 				err = errno;
159 				eprintf(lml, ERR_WARNING,
160 				    MSG_INTL(MSG_CONF_FSTAT), config->c_name,
161 				    str, strerror(err));
162 				continue;
163 			}
164 
165 			/*
166 			 * If the files size is different somethings been
167 			 * changed.
168 			 */
169 			if (status.st_size != obj->co_info) {
170 				eprintf(lml, ERR_WARNING,
171 				    MSG_INTL(MSG_CONF_FCMP), config->c_name,
172 				    str);
173 			}
174 		}
175 	}
176 }
177 
178 /*
179  * Process a configuration file.
180  *
181  * A configuration file can be specified using the LD_CONFIG environment
182  * variable, from a DT_CONFIG string recorded in the executable (see ld(1) -c),
183  * or in the case of a crle() dumped image, the file is "fabricated" to a
184  * configuration file that may have been associated with the dumped image.  In
185  * the absence of any of these techniques, a default configuration file is used.
186  *
187  * The LD_CONFIG variable take precedence, unless the application is secure, in
188  * which case the environment variable is ignored (see ld_generic_env()).
189  *
190  * A DT_CONFIG string is honored, even if the application is secure.  However,
191  * the path name follows the same rules as RUNPATH's, which must be a full path
192  * name with no use of $ORIGIN.
193  */
194 int
195 elf_config(Rt_map *lmp, int aout)
196 {
197 	Rtc_id		*id;
198 	Rtc_head	*head;
199 	int		fd, features = 0;
200 	struct stat	status;
201 	Addr		addr;
202 	Pnode		*pnp;
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 		    (PN_TKN_ISALIST | PN_TKN_HWCAP), 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, PN_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) 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 ((pnp = expand_paths(lmp, str,
335 		    (LA_SER_DEFAULT | LA_SER_CONFIG), PN_TKN_HWCAP)) != 0)
336 			elf_fct.fct_dflt_dirs = pnp;
337 		features |= CONF_EDLIBPATH;
338 	}
339 	if (head->ch_eslibpath) {
340 		str = (const char *)(head->ch_eslibpath + addr);
341 #ifndef	SGS_PRE_UNIFIED_PROCESS
342 		if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
343 #if	defined(_ELF64)
344 			str = conv_config_upm(str,
345 			    MSG_ORIG(MSG_PTH_USRLIBSE_64),
346 			    MSG_ORIG(MSG_PTH_LIBSE_64), MSG_PTH_LIBSE_64_SIZE);
347 #else
348 			str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIBSE),
349 			    MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE);
350 #endif
351 		}
352 #endif
353 		if ((pnp = expand_paths(lmp, str,
354 		    (LA_SER_SECURE | LA_SER_CONFIG), PN_TKN_HWCAP)) != 0)
355 			elf_fct.fct_secure_dirs = pnp;
356 		features |= CONF_ESLIBPATH;
357 	}
358 #if	defined(__sparc) && !defined(_ELF64)
359 	if (head->ch_adlibpath) {
360 		str = (const char *)(head->ch_adlibpath + addr);
361 		if ((pnp = expand_paths(lmp, str,
362 		    (LA_SER_DEFAULT | LA_SER_CONFIG), PN_TKN_HWCAP)) != 0)
363 			aout_fct.fct_dflt_dirs = pnp;
364 		features |= CONF_ADLIBPATH;
365 	}
366 	if (head->ch_aslibpath) {
367 		str = (const char *)(head->ch_aslibpath + addr);
368 		if ((pnp = expand_paths(lmp, str,
369 		    (LA_SER_SECURE | LA_SER_CONFIG), PN_TKN_HWCAP)) != 0)
370 			aout_fct.fct_secure_dirs = pnp;
371 		features |= CONF_ASLIBPATH;
372 	}
373 #endif
374 	/*
375 	 * Apply any environment variables.  This attribute was added with
376 	 * RTC_VER_THREE.
377 	 */
378 	if ((head->ch_version >= RTC_VER_THREE) && head->ch_env &&
379 	    (!(rtld_flags & RT_FL_NOENVCFG))) {
380 		if (readenv_config((Rtc_env *)(head->ch_env + addr),
381 		    addr, aout) != 0)
382 			return (-1);
383 		features |= CONF_ENVS;
384 	}
385 
386 	/*
387 	 * Determine whether filter/filtee associations are available.
388 	 */
389 	if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr &&
390 	    (!(rtld_flags2 & RT_FL2_NOFLTCFG))) {
391 		rtld_flags2 |= RT_FL2_FLTCFG;
392 		config->c_fltr = (Rtc_fltr *)(head->ch_fltr + addr);
393 		config->c_flte = (Rtc_flte *)(head->ch_flte + addr);
394 		features |= CONF_FLTR;
395 	}
396 
397 	/*
398 	 * Determine whether directory configuration is available.
399 	 */
400 	if ((!(rtld_flags & RT_FL_NODIRCFG)) && head->ch_hash) {
401 		config->c_hashtbl = (Word *)(head->ch_hash + addr);
402 		config->c_hashchain = &config->c_hashtbl[2 +
403 		    config->c_hashtbl[0]];
404 		config->c_objtbl = (Rtc_obj *)(head->ch_obj + addr);
405 		config->c_strtbl = (const char *)(head->ch_str + addr);
406 
407 		rtld_flags |= RT_FL_DIRCFG;
408 		features |= CONF_DIRCFG;
409 	}
410 
411 	/*
412 	 * Determine whether alternative objects are specified or an object
413 	 * reservation area is required.  If the reservation can't be completed
414 	 * (either because the configuration information is out-of-date, or the
415 	 * the reservation can't be allocated), then alternative objects are
416 	 * ignored.
417 	 */
418 	if ((!(rtld_flags & (RT_FL_NODIRCFG | RT_FL_NOOBJALT))) &&
419 	    (head->ch_cnflags & RTC_HDR_ALTER)) {
420 		rtld_flags |= RT_FL_OBJALT;
421 		features |= CONF_OBJALT;
422 
423 		elf_config_validate(addr, head, lmp);
424 
425 		if (head->ch_resbgn) {
426 
427 			if (((config->c_bgn <= head->ch_resbgn) &&
428 			    (config->c_bgn >= head->ch_resend)) ||
429 			    (nu_map(LIST(lmp),
430 			    (caddr_t)(uintptr_t)head->ch_resbgn,
431 			    (head->ch_resend - head->ch_resbgn), PROT_NONE,
432 			    MAP_FIXED | MAP_PRIVATE) == MAP_FAILED))
433 				return (-1);
434 
435 			rtld_flags |= RT_FL_MEMRESV;
436 			features |= CONF_MEMRESV;
437 		}
438 	}
439 
440 	return (features);
441 }
442 
443 /*
444  * Determine whether the given file exists in the configuration file.
445  */
446 Rtc_obj *
447 elf_config_ent(const char *name, Word hash, int id, const char **alternate)
448 {
449 	Word		bkt, ndx;
450 	const char	*str;
451 	Rtc_obj		*obj;
452 
453 	bkt = hash % config->c_hashtbl[0];
454 	ndx = config->c_hashtbl[2 + bkt];
455 
456 	while (ndx) {
457 		obj = config->c_objtbl + ndx;
458 		str = config->c_strtbl + obj->co_name;
459 
460 		if ((obj->co_hash != hash) || (strcmp(name, str) != 0) ||
461 		    (id && (id != obj->co_id))) {
462 			ndx = config->c_hashchain[ndx];
463 			continue;
464 		}
465 
466 		if ((obj->co_flags & RTC_OBJ_ALTER) && alternate)
467 			*alternate = config->c_strtbl + obj->co_alter;
468 
469 		return (obj);
470 	}
471 	return (0);
472 }
473 
474 /*
475  * Determine whether a filter and filtee string pair exists in the configuration
476  * file.  If so, return the cached filtees that are associated with this pair as
477  * a Pnode list.
478  */
479 Pnode *
480 elf_config_flt(Lm_list *lml, const char *filter, const char *string)
481 {
482 	Rtc_fltr	*fltrtbl;
483 	Pnode		*pnp = NULL, *npnp, *opnp = NULL;
484 
485 	for (fltrtbl = (Rtc_fltr *)config->c_fltr; fltrtbl->fr_filter;
486 	    fltrtbl++) {
487 		Rtc_flte	*fltetbl;
488 		const char	*fltr, *str;
489 
490 		fltr = config->c_strtbl + fltrtbl->fr_filter;
491 		str = config->c_strtbl + fltrtbl->fr_string;
492 		if (strcmp(filter, fltr) || strcmp(string, str))
493 			continue;
494 
495 		/*
496 		 * Create a pnode list for each filtee associated with this
497 		 * filter/filtee string pair.  Note, no expansion of filtee
498 		 * entries is called for, as any original expansion would have
499 		 * been carried out before they were recorded in the
500 		 * configuration file.
501 		 */
502 		/* LINTED */
503 		for (fltetbl = (Rtc_flte *)((char *)config->c_flte +
504 		    fltrtbl->fr_filtee); fltetbl->fe_filtee; fltetbl++) {
505 			const char	*flte;
506 
507 			flte = config->c_strtbl + fltetbl->fe_filtee;
508 
509 			if (((npnp = calloc(1, sizeof (Pnode))) == NULL) ||
510 			    ((npnp->p_name = strdup(flte)) == NULL))
511 				return (0);
512 
513 			DBG_CALL(Dbg_file_filter(lml, fltr, flte, 1));
514 
515 			if (opnp == NULL)
516 				pnp = npnp;
517 			else
518 				opnp->p_next = npnp;
519 
520 			npnp->p_len = strlen(flte) + 1;
521 			npnp->p_orig = LA_SER_CONFIG;
522 
523 			opnp = npnp;
524 		}
525 		return (pnp);
526 	}
527 	return (0);
528 }
529