Home | History | Annotate | Download | only in common
      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 2009 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 	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  */
    195 int
    196 elf_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_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, 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_HWCAP) != 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_HWCAP) != 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_HWCAP) != 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_HWCAP) != 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  */
    442 Rtc_obj *
    443 elf_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  */
    475 void
    476 elf_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