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