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 2010 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 == 0) 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(1) 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 takes precedence, unless the application is secure 189 * (see ld.so.1(1), issetugid(2)), in which case the environment variable is 190 * ignored (see ld_generic_env()). 191 * 192 * A DT_CONFIG string is honored, even if the application is secure. However, 193 * the path name follows the same rules as RUNPATH's, which must be a full path 194 * name with no use of $ORIGIN. 195 */ 196 int 197 elf_config(Rt_map *lmp) 198 { 199 Rtc_id *id; 200 Rtc_head *head; 201 int fd, features = 0; 202 rtld_stat_t status; 203 Addr addr; 204 const char *str; 205 char path[PATH_MAX]; 206 207 /* 208 * If we're dealing with an alternative application, fabricate the need 209 * for a $ORIGIN/ld.config.app-name configuration file. 210 */ 211 if (rtld_flags & RT_FL_CONFAPP) { 212 if ((str = strrchr(PATHNAME(lmp), '/')) != NULL) 213 str++; 214 else 215 str = PATHNAME(lmp); 216 217 (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_ORG_CONFIG), str); 218 str = path; 219 } else 220 str = config->c_name; 221 222 /* 223 * If a configuration file name is known, expand and verify the name. 224 */ 225 if (str) { 226 size_t size = strlen(str); 227 char *estr = (char *)str; 228 uint_t tkns; 229 230 /* 231 * Expand any configuration string. 232 */ 233 if ((tkns = expand(&estr, &size, 0, 0, 234 (PD_TKN_ISALIST | PD_TKN_CAP), lmp)) == 0) 235 return (0); 236 237 /* 238 * If this is a secure application, validate the configuration 239 * file path name. Ignore any untrustworthy path name, and 240 * fall through to pick up the defaults. 241 */ 242 if ((rtld_flags & RT_FL_SECURE) && 243 (is_path_secure(estr, lmp, PD_FLG_FULLPATH, tkns) == 0)) 244 str = NULL; 245 else 246 str = (const char *)estr; 247 } 248 249 /* 250 * If a configuration file has not been specified try opening up the 251 * default. 252 */ 253 if (str == NULL) { 254 #if defined(_ELF64) 255 str = MSG_ORIG(MSG_PTH_CONFIG_64); 256 #else 257 str = MSG_ORIG(MSG_PTH_CONFIG); 258 #endif 259 } 260 config->c_name = str; 261 262 /* 263 * If we can't open the configuration file return silently. 264 */ 265 if ((fd = open(str, O_RDONLY, 0)) == -1) 266 return (DBG_CONF_PRCFAIL); 267 268 /* 269 * Determine the configuration file size and map the file. 270 */ 271 (void) rtld_fstat(fd, &status); 272 if (status.st_size < sizeof (Rtc_head)) { 273 (void) close(fd); 274 return (DBG_CONF_CORRUPT); 275 } 276 if ((addr = (Addr)mmap(0, status.st_size, PROT_READ, MAP_SHARED, 277 fd, 0)) == (Addr)MAP_FAILED) { 278 (void) close(fd); 279 return (DBG_CONF_PRCFAIL); 280 } 281 (void) close(fd); 282 283 /* 284 * If we have an Rtc_id block at the beginning, then validate it 285 * and advance the address to the Rtc_head. If not, then trust 286 * that the file is compatible with us and move ahead (there is 287 * some error checking for Rtc_head below as well). 288 */ 289 id = (Rtc_id *) addr; 290 if (RTC_ID_TEST(id)) { 291 addr += sizeof (*id); 292 status.st_size -= sizeof (*id); 293 if (status.st_size < sizeof (Rtc_head)) 294 return (DBG_CONF_CORRUPT); 295 if ((id->id_class != M_CLASS) || (id->id_data != M_DATA) || 296 (id->id_machine != M_MACH)) 297 return (DBG_CONF_ABIMISMATCH); 298 } 299 300 config->c_bgn = addr; 301 config->c_end = addr + status.st_size; 302 303 head = (Rtc_head *)addr; 304 305 /* 306 * Make sure we can handle this version of the configuration file. 307 */ 308 if (head->ch_version > RTC_VER_CURRENT) 309 return (DBG_CONF_VERSION); 310 311 /* 312 * When crle(1) creates a temporary configuration file the 313 * RTC_HDR_IGNORE flag is set. Thus the mapping of the configuration 314 * file is taken into account but not its content. 315 */ 316 if (head->ch_cnflags & RTC_HDR_IGNORE) 317 return (DBG_CONF_IGNORE); 318 319 /* 320 * Apply any new default library pathname. 321 */ 322 if (head->ch_edlibpath) { 323 str = (const char *)(head->ch_edlibpath + addr); 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 if (expand_paths(lmp, str, &elf_def_dirs, AL_CNT_SEARCH, 334 (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_CAP) != 0) 335 features |= CONF_EDLIBPATH; 336 } 337 if (head->ch_eslibpath) { 338 str = (const char *)(head->ch_eslibpath + addr); 339 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) { 340 #if defined(_ELF64) 341 str = conv_config_upm(str, 342 MSG_ORIG(MSG_PTH_USRLIBSE_64), 343 MSG_ORIG(MSG_PTH_LIBSE_64), MSG_PTH_LIBSE_64_SIZE); 344 #else 345 str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIBSE), 346 MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE); 347 #endif 348 } 349 if (expand_paths(lmp, str, &elf_sec_dirs, AL_CNT_SEARCH, 350 (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_CAP) != 0) 351 features |= CONF_ESLIBPATH; 352 } 353 354 /* 355 * Apply any environment variables. This attribute was added with 356 * RTC_VER_THREE. 357 */ 358 if ((head->ch_version >= RTC_VER_THREE) && head->ch_env && 359 (!(rtld_flags & RT_FL_NOENVCFG))) { 360 if (readenv_config((Rtc_env *)(head->ch_env + addr), 361 addr) != 0) 362 return (-1); 363 features |= CONF_ENVS; 364 } 365 366 /* 367 * Determine whether filter/filtee associations are available. 368 */ 369 if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr && 370 (!(rtld_flags2 & RT_FL2_NOFLTCFG))) { 371 rtld_flags2 |= RT_FL2_FLTCFG; 372 config->c_fltr = (Rtc_fltr *)(head->ch_fltr + addr); 373 config->c_flte = (Rtc_flte *)(head->ch_flte + addr); 374 features |= CONF_FLTR; 375 } 376 377 /* 378 * Determine whether directory configuration is available. 379 */ 380 if ((!(rtld_flags & RT_FL_NODIRCFG)) && head->ch_hash) { 381 config->c_hashtbl = (Word *)(head->ch_hash + addr); 382 config->c_hashchain = &config->c_hashtbl[2 + 383 config->c_hashtbl[0]]; 384 config->c_objtbl = (Rtc_obj *)(head->ch_obj + addr); 385 config->c_strtbl = (const char *)(head->ch_str + addr); 386 387 rtld_flags |= RT_FL_DIRCFG; 388 features |= CONF_DIRCFG; 389 } 390 391 /* 392 * Determine whether alternative objects are specified or an object 393 * reservation area is required. If the reservation can't be completed 394 * (either because the configuration information is out-of-date, or the 395 * the reservation can't be allocated), then alternative objects are 396 * ignored. 397 */ 398 if ((!(rtld_flags & (RT_FL_NODIRCFG | RT_FL_NOOBJALT))) && 399 (head->ch_cnflags & RTC_HDR_ALTER)) { 400 rtld_flags |= RT_FL_OBJALT; 401 features |= CONF_OBJALT; 402 403 elf_config_validate(addr, head, lmp); 404 405 if (head->ch_resbgn) { 406 407 if (((config->c_bgn <= head->ch_resbgn) && 408 (config->c_bgn >= head->ch_resend)) || 409 (nu_map(LIST(lmp), 410 (caddr_t)(uintptr_t)head->ch_resbgn, 411 (head->ch_resend - head->ch_resbgn), PROT_NONE, 412 MAP_FIXED | MAP_PRIVATE) == MAP_FAILED)) 413 return (-1); 414 415 rtld_flags |= RT_FL_MEMRESV; 416 features |= CONF_MEMRESV; 417 } 418 } 419 420 return (features); 421 } 422 423 /* 424 * Determine whether the given file exists in the configuration file. 425 */ 426 Rtc_obj * 427 elf_config_ent(const char *name, Word hash, int id, const char **alternate) 428 { 429 Word bkt, ndx; 430 const char *str; 431 Rtc_obj *obj; 432 433 bkt = hash % config->c_hashtbl[0]; 434 ndx = config->c_hashtbl[2 + bkt]; 435 436 while (ndx) { 437 obj = config->c_objtbl + ndx; 438 str = config->c_strtbl + obj->co_name; 439 440 if ((obj->co_hash != hash) || (strcmp(name, str) != 0) || 441 (id && (id != obj->co_id))) { 442 ndx = config->c_hashchain[ndx]; 443 continue; 444 } 445 446 if ((obj->co_flags & RTC_OBJ_ALTER) && alternate) 447 *alternate = config->c_strtbl + obj->co_alter; 448 449 return (obj); 450 } 451 return (0); 452 } 453 454 /* 455 * Determine whether a filter and filtee string pair exists in the configuration 456 * file. If so, return the cached filtees that are associated with this pair as 457 * an Alist. 458 */ 459 void 460 elf_config_flt(Lm_list *lml, const char *filter, const char *string, 461 Alist **alpp, Aliste alni) 462 { 463 Rtc_fltr *fltrtbl; 464 465 for (fltrtbl = (Rtc_fltr *)config->c_fltr; fltrtbl->fr_filter; 466 fltrtbl++) { 467 Rtc_flte *fltetbl; 468 const char *fltr, *str; 469 470 fltr = config->c_strtbl + fltrtbl->fr_filter; 471 str = config->c_strtbl + fltrtbl->fr_string; 472 if (strcmp(filter, fltr) || strcmp(string, str)) 473 continue; 474 475 /* 476 * Create a path descriptor for each filtee associated with this 477 * filter/filtee string pair. Note, no expansion of filtee 478 * entries is called for, as any original expansion would have 479 * been carried out before they were recorded in the 480 * configuration file. 481 */ 482 /* LINTED */ 483 for (fltetbl = (Rtc_flte *)((char *)config->c_flte + 484 fltrtbl->fr_filtee); fltetbl->fe_filtee; fltetbl++) { 485 const char *flte; 486 Pdesc *pdp; 487 488 flte = config->c_strtbl + fltetbl->fe_filtee; 489 490 if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc), 491 alni)) == NULL) 492 return; 493 494 pdp->pd_pname = (char *)flte; 495 pdp->pd_plen = strlen(flte) + 1; 496 pdp->pd_flags = LA_SER_CONFIG; 497 498 DBG_CALL(Dbg_file_filter(lml, fltr, flte, 1)); 499 } 500 } 501 } 502