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, 0, 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