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