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 /* 28 * Copyright (c) 1988 AT&T 29 * All Rights Reserved 30 */ 31 32 /* 33 * PATH setup and search directory functions. 34 */ 35 36 #include <stdio.h> 37 #include <unistd.h> 38 #include <limits.h> 39 #include <fcntl.h> 40 #include <string.h> 41 #include <sys/systeminfo.h> 42 #include <debug.h> 43 #include <conv.h> 44 #include "_rtld.h" 45 #include "msg.h" 46 47 /* 48 * Default and secure dependency search path initialization. 49 */ 50 void 51 set_dirs(Alist **alpp, Spath_defn *sdp, uint_t flags) 52 { 53 while (sdp->sd_name) { 54 Pdesc *pdp; 55 56 if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc), 57 AL_CNT_SPATH)) == NULL) 58 return; 59 60 pdp->pd_pname = (char *)sdp->sd_name; 61 pdp->pd_plen = sdp->sd_len; 62 pdp->pd_flags = flags; 63 sdp++; 64 } 65 } 66 67 static void 68 print_default_dirs(Lm_list *lml, Alist *alp, int search) 69 { 70 uint_t flags = 0; 71 int num = 0; 72 Aliste idx; 73 Pdesc *pdp; 74 75 if (search) 76 (void) printf(MSG_INTL(MSG_LDD_PTH_BGNDFL)); 77 78 for (ALIST_TRAVERSE(alp, idx, pdp)) { 79 flags = pdp->pd_flags; 80 81 if (search) { 82 const char *fmt; 83 84 if (num++) 85 fmt = MSG_ORIG(MSG_LDD_FMT_PATHN); 86 else 87 fmt = MSG_ORIG(MSG_LDD_FMT_PATH1); 88 89 (void) printf(fmt, pdp->pd_pname); 90 } else 91 DBG_CALL(Dbg_libs_path(lml, pdp->pd_pname, 92 pdp->pd_flags, config->c_name)); 93 } 94 95 if (search) { 96 if (flags & LA_SER_CONFIG) 97 (void) printf(MSG_INTL(MSG_LDD_PTH_ENDDFLC), 98 config->c_name); 99 else 100 (void) printf(MSG_INTL(MSG_LDD_PTH_ENDDFL)); 101 } 102 } 103 104 /* 105 * Given a search rule type, return a list of directories to search according 106 * to the specified rule. 107 */ 108 static Alist ** 109 get_dir_list(uchar_t rules, Rt_map *lmp, uint_t flags) 110 { 111 Alist **dalpp = NULL; 112 Lm_list *lml = LIST(lmp); 113 int search; 114 115 /* 116 * Determine whether ldd -s is in effect - ignore when we're searching 117 * for audit libraries as these will be added to their own link-map. 118 */ 119 if ((lml->lm_flags & LML_FLG_TRC_SEARCH) && 120 ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0) && 121 ((flags & FLG_RT_AUDIT) == 0)) 122 search = 1; 123 else 124 search = 0; 125 126 switch (rules) { 127 case RPLENV: 128 /* 129 * Initialize the replaceable environment variable 130 * (LD_LIBRARY_PATH) search path list. Note, we always call 131 * Dbg_libs_path() so that every library lookup diagnostic can 132 * be preceded with the appropriate search path information. 133 */ 134 if (rpl_libpath) { 135 uint_t mode = (LA_SER_LIBPATH | PD_FLG_UNIQUE); 136 137 /* 138 * Note, this path may have originated from the users 139 * environment or from a configuration file. 140 */ 141 if (env_info & ENV_INF_PATHCFG) 142 mode |= LA_SER_CONFIG; 143 144 DBG_CALL(Dbg_libs_path(lml, rpl_libpath, mode, 145 config->c_name)); 146 147 /* 148 * For ldd(1) -s, indicate the search paths that'll 149 * be used. If this is a secure application then some 150 * search paths may be ignored, therefore reset the 151 * rpl_libdirs pointer each time so that the 152 * diagnostics related to these unsecure directories 153 * will be output for each image loaded. 154 */ 155 if (search) { 156 const char *fmt; 157 158 if (env_info & ENV_INF_PATHCFG) 159 fmt = MSG_INTL(MSG_LDD_PTH_LIBPATHC); 160 else 161 fmt = MSG_INTL(MSG_LDD_PTH_LIBPATH); 162 163 (void) printf(fmt, rpl_libpath, config->c_name); 164 } 165 if (rpl_libdirs && (rtld_flags & RT_FL_SECURE) && 166 (search || DBG_ENABLED)) 167 remove_plist(&rpl_libdirs, 1); 168 169 if (rpl_libdirs == NULL) { 170 /* 171 * If this is a secure application we need to 172 * be selective over what directories we use. 173 */ 174 (void) expand_paths(lmp, rpl_libpath, 175 &rpl_libdirs, AL_CNT_SEARCH, mode, 176 PD_TKN_HWCAP); 177 } 178 dalpp = &rpl_libdirs; 179 } 180 break; 181 case PRMENV: 182 /* 183 * Initialize the permanent (LD_LIBRARY_PATH) search path list. 184 * This can only originate from a configuration file. To be 185 * consistent with the debugging display of DEFENV (above), 186 * always call Dbg_libs_path(). 187 */ 188 if (prm_libpath) { 189 uint_t mode = 190 (LA_SER_LIBPATH | LA_SER_CONFIG | PD_FLG_UNIQUE); 191 192 DBG_CALL(Dbg_libs_path(lml, prm_libpath, mode, 193 config->c_name)); 194 195 /* 196 * For ldd(1) -s, indicate the search paths that'll 197 * be used. If this is a secure application then some 198 * search paths may be ignored, therefore reset the 199 * prm_libdirs pointer each time so that the 200 * diagnostics related to these unsecure directories 201 * will be output for each image loaded. 202 */ 203 if (search) 204 (void) printf(MSG_INTL(MSG_LDD_PTH_LIBPATHC), 205 prm_libpath, config->c_name); 206 if (prm_libdirs && (rtld_flags & RT_FL_SECURE) && 207 (search || DBG_ENABLED)) 208 remove_plist(&prm_libdirs, 1); 209 210 if (prm_libdirs == NULL) { 211 /* 212 * If this is a secure application we need to 213 * be selective over what directories we use. 214 */ 215 (void) expand_paths(lmp, prm_libpath, 216 &prm_libdirs, AL_CNT_SEARCH, mode, 217 PD_TKN_HWCAP); 218 } 219 dalpp = &prm_libdirs; 220 } 221 break; 222 case RUNPATH: 223 /* 224 * Initialize the runpath search path list. To be consistent 225 * with the debugging display of DEFENV (above), always call 226 * Dbg_libs_path(). 227 */ 228 if (RPATH(lmp)) { 229 DBG_CALL(Dbg_libs_path(lml, RPATH(lmp), LA_SER_RUNPATH, 230 NAME(lmp))); 231 232 /* 233 * For ldd(1) -s, indicate the search paths that'll 234 * be used. If this is a secure application then some 235 * search paths may be ignored, therefore reset the 236 * runlist pointer each time so that the diagnostics 237 * related to these unsecure directories will be 238 * output for each image loaded. 239 */ 240 if (search) 241 (void) printf(MSG_INTL(MSG_LDD_PTH_RUNPATH), 242 RPATH(lmp), NAME(lmp)); 243 if (RLIST(lmp) && (rtld_flags & RT_FL_SECURE) && 244 (search || DBG_ENABLED)) 245 remove_plist(&RLIST(lmp), 1); 246 247 if (RLIST(lmp) == NULL) { 248 /* 249 * If this is a secure application we need to 250 * be selective over what directories we use. 251 */ 252 (void) expand_paths(lmp, RPATH(lmp), 253 &RLIST(lmp), AL_CNT_SEARCH, LA_SER_RUNPATH, 254 PD_TKN_HWCAP); 255 } 256 dalpp = &RLIST(lmp); 257 } 258 break; 259 case DEFAULT: 260 if ((FLAGS1(lmp) & FL1_RT_NODEFLIB) == 0) { 261 if ((rtld_flags & RT_FL_SECURE) && 262 (flags & (FLG_RT_PRELOAD | FLG_RT_AUDIT))) 263 dalpp = LM_SECURE_DIRS(lmp)(); 264 else 265 dalpp = LM_DEFAULT_DIRS(lmp)(); 266 } 267 268 /* 269 * For ldd(1) -s, indicate the default paths that'll be used. 270 */ 271 if (dalpp && (search || DBG_ENABLED)) 272 print_default_dirs(lml, *dalpp, search); 273 break; 274 default: 275 break; 276 } 277 return (dalpp); 278 } 279 280 /* 281 * Get the next directory in the search rules path. The seach path "cookie" 282 * provided by the caller (sdp) maintains the state of a search in progress. 283 * 284 * Typically, a search consists of a series of rules that govern the order of 285 * a search (ie. LD_LIBRARY_PATH, followed by RPATHS, followed by defaults). 286 * Each rule can establish a corresponding series of path names, which are 287 * maintained as an Alist. The index within this Alist determines the present 288 * search directory. 289 */ 290 Pdesc * 291 get_next_dir(Spath_desc *sdp, Rt_map *lmp, uint_t flags) 292 { 293 /* 294 * Make sure there are still rules to process. 295 */ 296 while (*sdp->sp_rule) { 297 Alist *alp; 298 299 /* 300 * If an Alist for this rule already exists, use if, otherwise 301 * obtain an Alist for this rule. Providing the Alist has 302 * content, and the present Alist index is less than the number 303 * of Alist members, return the associated path name descriptor. 304 */ 305 if ((sdp->sp_dalpp || ((sdp->sp_dalpp = 306 get_dir_list(*sdp->sp_rule, lmp, flags)) != NULL)) && 307 ((alp = *sdp->sp_dalpp) != NULL) && 308 (alist_nitems(alp) > sdp->sp_idx)) { 309 return (alist_item(alp, sdp->sp_idx++)); 310 } 311 312 /* 313 * If no Alist for this rule exists, or if this is the last 314 * element of this Alist, reset the Alist pointer and index, 315 * and prepare for the next rule. 316 */ 317 sdp->sp_rule++; 318 sdp->sp_dalpp = NULL; 319 sdp->sp_idx = 0; 320 } 321 322 /* 323 * All rules and search paths have been exhausted. 324 */ 325 return (NULL); 326 } 327 328 /* 329 * Process a directory (runpath) or filename (needed or filter) string looking 330 * for tokens to expand. Allocate a new buffer for the string. 331 */ 332 uint_t 333 expand(char **name, size_t *len, char **list, uint_t orig, uint_t omit, 334 Rt_map *lmp) 335 { 336 char _name[PATH_MAX]; 337 char *token = NULL, *oname, *ename, *optr, *_optr, *nptr, *_list; 338 size_t olen = 0, nlen = 0, _len; 339 int isaflag = 0; 340 uint_t flags = 0; 341 Lm_list *lml = LIST(lmp); 342 343 optr = _optr = oname = ename = *name; 344 ename += *len; 345 nptr = _name; 346 347 while ((olen < *len) && (nlen < PATH_MAX)) { 348 uint_t _flags; 349 350 if ((*optr != '$') || ((olen - *len) == 1)) { 351 /* 352 * When expanding paths while a configuration file 353 * exists that contains directory information, determine 354 * whether the path contains "./". If so, we'll resolve 355 * the path later to remove these relative entries. 356 */ 357 if ((rtld_flags & RT_FL_DIRCFG) && 358 (orig & LA_SER_MASK) && (*optr == '/') && 359 (optr != oname) && (*(optr - 1) == '.')) 360 flags |= TKN_DOTSLASH; 361 362 olen++, optr++; 363 continue; 364 } 365 366 /* 367 * Copy any string we've presently passed over to the new 368 * buffer. 369 */ 370 if ((_len = (optr - _optr)) != 0) { 371 if ((nlen += _len) < PATH_MAX) { 372 (void) strncpy(nptr, _optr, _len); 373 nptr = nptr + _len; 374 } else { 375 eprintf(lml, ERR_FATAL, 376 MSG_INTL(MSG_ERR_EXPAND1), NAME(lmp), 377 oname); 378 return (0); 379 } 380 } 381 382 /* 383 * Skip the token delimiter and determine if a reserved token 384 * match is found. 385 */ 386 olen++, optr++; 387 _flags = 0; 388 token = 0; 389 390 if (strncmp(optr, MSG_ORIG(MSG_TKN_ORIGIN), 391 MSG_TKN_ORIGIN_SIZE) == 0) { 392 token = (char *)MSG_ORIG(MSG_TKN_ORIGIN); 393 394 /* 395 * $ORIGIN expansion is required. Determine this 396 * objects basename. Expansion of $ORIGIN is allowed 397 * for secure applications but must be checked by the 398 * caller to insure the expanded path matches a 399 * registered secure name. 400 */ 401 if (((omit & PD_TKN_ORIGIN) == 0) && 402 (((_len = DIRSZ(lmp)) != 0) || 403 ((_len = fullpath(lmp, 0)) != 0))) { 404 if ((nlen += _len) < PATH_MAX) { 405 (void) strncpy(nptr, 406 ORIGNAME(lmp), _len); 407 nptr = nptr +_len; 408 olen += MSG_TKN_ORIGIN_SIZE; 409 optr += MSG_TKN_ORIGIN_SIZE; 410 _flags |= PD_TKN_ORIGIN; 411 } else { 412 eprintf(lml, ERR_FATAL, 413 MSG_INTL(MSG_ERR_EXPAND1), 414 NAME(lmp), oname); 415 return (0); 416 } 417 } 418 419 } else if (strncmp(optr, MSG_ORIG(MSG_TKN_PLATFORM), 420 MSG_TKN_PLATFORM_SIZE) == 0) { 421 token = (char *)MSG_ORIG(MSG_TKN_PLATFORM); 422 423 /* 424 * $PLATFORM expansion required. This would have been 425 * established from the AT_SUN_PLATFORM aux vector, but 426 * if not attempt to get it from sysconf(). 427 */ 428 if (((omit & PD_TKN_PLATFORM) == 0) && 429 ((platform == 0) && (platform_sz == 0))) { 430 char _info[SYS_NMLN]; 431 long _size; 432 433 _size = sysinfo(SI_PLATFORM, _info, SYS_NMLN); 434 if ((_size != -1) && ((platform = 435 malloc((size_t)_size)) != NULL)) { 436 (void) strcpy(platform, _info); 437 platform_sz = (size_t)_size - 1; 438 } 439 } 440 if (((omit & PD_TKN_PLATFORM) == 0) && 441 (platform != 0)) { 442 if ((nlen += platform_sz) < PATH_MAX) { 443 (void) strncpy(nptr, platform, 444 platform_sz); 445 nptr = nptr + platform_sz; 446 olen += MSG_TKN_PLATFORM_SIZE; 447 optr += MSG_TKN_PLATFORM_SIZE; 448 _flags |= PD_TKN_PLATFORM; 449 } else { 450 eprintf(lml, ERR_FATAL, 451 MSG_INTL(MSG_ERR_EXPAND1), 452 NAME(lmp), oname); 453 return (0); 454 } 455 } 456 457 } else if (strncmp(optr, MSG_ORIG(MSG_TKN_OSNAME), 458 MSG_TKN_OSNAME_SIZE) == 0) { 459 token = (char *)MSG_ORIG(MSG_TKN_OSNAME); 460 461 /* 462 * $OSNAME expansion required. This is established 463 * from the sysname[] returned by uname(2). 464 */ 465 if (((omit & PD_TKN_OSNAME) == 0) && (uts == NULL)) 466 uts = conv_uts(); 467 468 if (((omit & PD_TKN_OSNAME) == 0) && 469 (uts && uts->uts_osnamesz)) { 470 if ((nlen += uts->uts_osnamesz) < PATH_MAX) { 471 (void) strncpy(nptr, uts->uts_osname, 472 uts->uts_osnamesz); 473 nptr = nptr + uts->uts_osnamesz; 474 olen += MSG_TKN_OSNAME_SIZE; 475 optr += MSG_TKN_OSNAME_SIZE; 476 _flags |= PD_TKN_OSNAME; 477 } else { 478 eprintf(lml, ERR_FATAL, 479 MSG_INTL(MSG_ERR_EXPAND1), 480 NAME(lmp), oname); 481 return (0); 482 } 483 } 484 485 } else if (strncmp(optr, MSG_ORIG(MSG_TKN_OSREL), 486 MSG_TKN_OSREL_SIZE) == 0) { 487 token = (char *)MSG_ORIG(MSG_TKN_OSREL); 488 489 /* 490 * $OSREL expansion required. This is established 491 * from the release[] returned by uname(2). 492 */ 493 if (((omit & PD_TKN_OSREL) == 0) && (uts == 0)) 494 uts = conv_uts(); 495 496 if (((omit & PD_TKN_OSREL) == 0) && 497 (uts && uts->uts_osrelsz)) { 498 if ((nlen += uts->uts_osrelsz) < PATH_MAX) { 499 (void) strncpy(nptr, uts->uts_osrel, 500 uts->uts_osrelsz); 501 nptr = nptr + uts->uts_osrelsz; 502 olen += MSG_TKN_OSREL_SIZE; 503 optr += MSG_TKN_OSREL_SIZE; 504 _flags |= PD_TKN_OSREL; 505 } else { 506 eprintf(lml, ERR_FATAL, 507 MSG_INTL(MSG_ERR_EXPAND1), 508 NAME(lmp), oname); 509 return (0); 510 } 511 } 512 513 } else if ((strncmp(optr, MSG_ORIG(MSG_TKN_ISALIST), 514 MSG_TKN_ISALIST_SIZE) == 0)) { 515 int ok; 516 token = (char *)MSG_ORIG(MSG_TKN_ISALIST); 517 518 /* 519 * $ISALIST expansion required. When accompanied with 520 * a list pointer, this routine updates that pointer 521 * with the new list of potential candidates. Without 522 * this list pointer, only the first expansion is 523 * provided. NOTE, that two $ISLIST expansions within 524 * the same path aren't supported. 525 */ 526 if ((omit & PD_TKN_ISALIST) || isaflag++) 527 ok = 0; 528 else 529 ok = 1; 530 531 if (ok && (isa == NULL)) 532 isa = conv_isalist(); 533 534 if (ok && isa && isa->isa_listsz) { 535 size_t no, mlen, tlen, hlen = olen - 1; 536 char *lptr; 537 Isa_opt *opt = isa->isa_opt; 538 539 if ((nlen += opt->isa_namesz) < PATH_MAX) { 540 (void) strncpy(nptr, opt->isa_name, 541 opt->isa_namesz); 542 nptr = nptr + opt->isa_namesz; 543 olen += MSG_TKN_ISALIST_SIZE; 544 optr += MSG_TKN_ISALIST_SIZE; 545 _flags |= PD_TKN_ISALIST; 546 } else { 547 eprintf(lml, ERR_FATAL, 548 MSG_INTL(MSG_ERR_EXPAND1), 549 NAME(lmp), oname); 550 return (0); 551 } 552 553 if (list) { 554 tlen = *len - olen; 555 mlen = ((hlen + tlen) * 556 (isa->isa_optno - 1)) + 557 isa->isa_listsz - opt->isa_namesz + 558 strlen(*list); 559 if ((_list = lptr = 560 malloc(mlen)) == NULL) 561 return (0); 562 563 for (no = 1, opt++; no < isa->isa_optno; 564 no++, opt++) { 565 (void) strncpy(lptr, *name, 566 hlen); 567 lptr = lptr + hlen; 568 (void) strncpy(lptr, 569 opt->isa_name, 570 opt->isa_namesz); 571 lptr = lptr + opt->isa_namesz; 572 (void) strncpy(lptr, optr, 573 tlen); 574 lptr = lptr + tlen; 575 *lptr++ = ':'; 576 } 577 if (**list) 578 (void) strcpy(lptr, *list); 579 else 580 *--lptr = '\0'; 581 } 582 } 583 584 } else if (strncmp(optr, MSG_ORIG(MSG_TKN_HWCAP), 585 MSG_TKN_HWCAP_SIZE) == 0) { 586 char *bptr = nptr - 1; 587 char *eptr = optr + MSG_TKN_HWCAP_SIZE; 588 token = (char *)MSG_ORIG(MSG_TKN_HWCAP); 589 590 /* 591 * $HWCAP expansion required. For compatibility with 592 * older environments, only expand this token when hard- 593 * ware capability information is available. This 594 * expansion is only allowed for non-simple path names 595 * (must contain a '/'), with the token itself being the 596 * last element of the path. Therefore, all we need do 597 * is test the existence of the string "/$HWCAP\0". 598 */ 599 if (((omit & PD_TKN_HWCAP) == 0) && 600 (rtld_flags2 & RT_FL2_HWCAP) && 601 ((bptr > _name) && (*bptr == '/') && 602 ((*eptr == '\0') || (*eptr == ':')))) { 603 /* 604 * Decrement the present pointer so that the 605 * directories trailing "/" gets nuked later. 606 */ 607 nptr--, nlen--; 608 olen += MSG_TKN_HWCAP_SIZE; 609 optr += MSG_TKN_HWCAP_SIZE; 610 _flags |= PD_TKN_HWCAP; 611 } 612 613 } else { 614 /* 615 * If reserved token was not found, copy the 616 * character. 617 */ 618 *nptr++ = '$'; 619 nlen++; 620 } 621 622 /* 623 * If a reserved token was found, and could not be expanded, 624 * diagnose the error condition. 625 */ 626 if (token) { 627 if (_flags) 628 flags |= _flags; 629 else { 630 char buf[PATH_MAX], *str; 631 632 /* 633 * Note, the original string we're expanding 634 * might contain a number of ':' separated 635 * paths. Isolate the path we're processing to 636 * provide a more precise error diagnostic. 637 */ 638 if (str = strchr(oname, ':')) { 639 size_t slen = str - oname; 640 641 (void) strncpy(buf, oname, slen); 642 buf[slen] = '\0'; 643 str = buf; 644 } else 645 str = oname; 646 647 eprintf(lml, ERR_FATAL, 648 MSG_INTL(MSG_ERR_EXPAND2), NAME(lmp), 649 str, token); 650 return (0); 651 } 652 } 653 _optr = optr; 654 } 655 656 /* 657 * First make sure the current length is shorter than PATH_MAX. We may 658 * arrive here if the given path contains '$' characters which are not 659 * the lead of a reserved token. 660 */ 661 if (nlen >= PATH_MAX) { 662 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1), NAME(lmp), 663 oname); 664 return (0); 665 } 666 667 /* 668 * If any ISALIST processing has occurred not only do we return the 669 * expanded node we're presently working on, but we can also update the 670 * remaining list so that it is effectively prepended with this node 671 * expanded to all remaining ISALIST options. Note that we can only 672 * handle one ISALIST per node. For more than one ISALIST to be 673 * processed we'd need a better algorithm than above to replace the 674 * newly generated list. Whether we want to encourage the number of 675 * path name permutations this would provide is another question. So, 676 * for now if more than one ISALIST is encountered we return the 677 * original node untouched. 678 */ 679 if (isa && isaflag) { 680 if (isaflag == 1) { 681 if (list) 682 *list = _list; 683 } else { 684 flags &= ~PD_TKN_ISALIST; 685 if ((nptr = (char *)stravl_insert(*name, 0, 686 (*len + 1), 1)) == NULL) 687 return (0); 688 *name = nptr; 689 return (TKN_NONE); 690 } 691 } 692 693 /* 694 * Copy any remaining string. Terminate the new string with a null as 695 * this string can be displayed via debugging diagnostics. 696 */ 697 if ((_len = (optr - _optr)) != 0) { 698 if ((nlen += _len) < PATH_MAX) { 699 (void) strncpy(nptr, _optr, _len); 700 nptr = nptr + _len; 701 } else { 702 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1), 703 NAME(lmp), oname); 704 return (0); 705 } 706 } 707 *nptr = '\0'; 708 709 /* 710 * A path that has been expanded is typically used to create full 711 * path names for objects that will be opened. The final path name is 712 * resolved to simplify it, and set the stage for possible $ORIGIN 713 * processing. Therefore, it's usually unnecessary to resolve the path 714 * at this point. However, if a configuration file, containing 715 * directory information is in use, then we might need to lookup this 716 * path in the configuration file. To keep the number of path name 717 * resolutions to a minimum, only resolve paths that contain "./". The 718 * use of "$ORIGIN/../lib" will probably only match a configuration file 719 * entry after resolution. 720 */ 721 if (list && (rtld_flags & RT_FL_DIRCFG) && (flags & TKN_DOTSLASH)) { 722 int len; 723 724 if ((len = resolvepath(_name, _name, (PATH_MAX - 1))) >= 0) { 725 nlen = (size_t)len; 726 _name[nlen] = '\0'; 727 flags |= PD_TKN_RESOLVED; 728 } 729 } 730 731 /* 732 * Allocate a new string if necessary. 733 * 734 * If any form of token expansion, or string resolution has occurred, 735 * the storage must be allocated for the new string. 736 * 737 * If we're processing a substring, for example, any string besides the 738 * last string within a search path "A:B:C", then this substring needs 739 * to be isolated with a null terminator. However, if this search path 740 * was created from a previous ISALIST expansion, then all strings must 741 * be allocated, as the isalist expansion will be freed after expansion 742 * processing. 743 */ 744 if ((nptr = (char *)stravl_insert(_name, 0, (nlen + 1), 1)) == NULL) 745 return (0); 746 *name = nptr; 747 *len = nlen; 748 return (flags ? flags : TKN_NONE); 749 } 750 751 /* 752 * Determine whether a path name is secure. 753 */ 754 int 755 is_path_secure(char *opath, Rt_map *clmp, uint_t info, uint_t flags) 756 { 757 Alist **salpp; 758 Aliste idx; 759 char buffer[PATH_MAX], *npath = NULL; 760 Lm_list *lml = LIST(clmp); 761 Pdesc *pdp; 762 763 /* 764 * If a path name originates from a configuration file, use it. The use 765 * of a configuration file is already validated for secure applications, 766 * so if we're using a configuration file, we must be able to use all 767 * that it defines. 768 */ 769 if (info & LA_SER_CONFIG) 770 return (1); 771 772 if ((info & LA_SER_MASK) == 0) { 773 char *str; 774 775 /* 776 * If the path name specifies a file (rather than a directory), 777 * peel off the file before making the comparison. 778 */ 779 str = strrchr(opath, '/'); 780 781 /* 782 * Carry out some initial security checks. 783 * 784 * . a simple file name (one containing no "/") is fine, as 785 * this file name will be combined with search paths to 786 * determine the complete path. Note, a secure application 787 * may provide a configuration file, and this can only be 788 * a full path name (PN_FLG_FULLPATH). 789 * . a full path (one starting with "/") is fine, provided 790 * this path name isn't a preload/audit path. 791 * . provided $ORIGIN expansion has not been employed, the 792 * above categories of path are deemed secure. 793 */ 794 if ((((str == 0) && ((info & PD_FLG_FULLPATH) == 0)) || 795 ((*opath == '/') && (str != opath) && 796 ((info & PD_FLG_EXTLOAD) == 0))) && 797 ((flags & PD_TKN_ORIGIN) == 0)) 798 return (1); 799 800 /* 801 * Determine the directory name of the present path. 802 */ 803 if (str) { 804 if (str == opath) 805 npath = (char *)MSG_ORIG(MSG_STR_SLASH); 806 else { 807 size_t size; 808 809 if ((size = str - opath) >= PATH_MAX) 810 return (0); 811 812 (void) strncpy(buffer, opath, size); 813 buffer[size] = '\0'; 814 npath = buffer; 815 } 816 817 /* 818 * If $ORIGIN processing has been employed, then allow 819 * any directory that has already been used to satisfy 820 * other dependencies, to be used. 821 */ 822 if ((flags & PD_TKN_ORIGIN) && 823 spavl_recorded(npath, 0)) { 824 DBG_CALL(Dbg_libs_insecure(lml, npath, 1)); 825 return (1); 826 } 827 } 828 } else { 829 /* 830 * A search path, i.e., RPATH, configuration file path, etc. is 831 * used as is. Exceptions to this are: 832 * 833 * . LD_LIBRARY_PATH. 834 * . any $ORIGIN expansion, unless used by a setuid ld.so.1 835 * to find its own dependencies, or the path name has 836 * already been used to find other dependencies. 837 * . any relative path. 838 */ 839 if (((info & LA_SER_LIBPATH) == 0) && (*opath == '/') && 840 ((flags & PD_TKN_ORIGIN) == 0)) 841 return (1); 842 843 /* 844 * If $ORIGIN processing is requested, allow a setuid ld.so.1 845 * to use this path for its own dependencies. Allow the 846 * application to use this path name only if the path name has 847 * already been used to locate other dependencies. 848 */ 849 if (flags & PD_TKN_ORIGIN) { 850 if ((lml->lm_flags & LML_FLG_RTLDLM) && 851 is_rtld_setuid()) 852 return (1); 853 else if (spavl_recorded(opath, 0)) { 854 DBG_CALL(Dbg_libs_insecure(lml, opath, 1)); 855 return (1); 856 } 857 } 858 npath = (char *)opath; 859 } 860 861 /* 862 * Determine whether the present directory is trusted. 863 */ 864 if (npath) { 865 salpp = LM_SECURE_DIRS(LIST(clmp)->lm_head)(); 866 for (ALIST_TRAVERSE(*salpp, idx, pdp)) { 867 if (strcmp(npath, pdp->pd_pname) == 0) 868 return (1); 869 } 870 } 871 872 /* 873 * The path is insecure, so depending on the caller, provide a 874 * diagnostic. Preloaded, or audit libraries generate a warning, as 875 * the process will run without them. 876 */ 877 if (info & PD_FLG_EXTLOAD) { 878 if (lml->lm_flags & LML_FLG_TRC_ENABLE) { 879 if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0) 880 (void) printf(MSG_INTL(MSG_LDD_FIL_ILLEGAL), 881 opath); 882 } else 883 eprintf(lml, ERR_WARNING, MSG_INTL(MSG_SEC_ILLEGAL), 884 opath); 885 886 return (0); 887 } 888 889 /* 890 * Explicit file references are fatal. 891 */ 892 if ((info & LA_SER_MASK) == 0) { 893 if (lml->lm_flags & LML_FLG_TRC_ENABLE) { 894 /* BEGIN CSTYLED */ 895 if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0) { 896 if (lml->lm_flags & 897 (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH)) 898 (void) printf( 899 MSG_INTL(MSG_LDD_FIL_FIND), 900 opath, NAME(clmp)); 901 902 if (((rtld_flags & RT_FL_SILENCERR) == 0) || 903 (lml->lm_flags & LML_FLG_TRC_VERBOSE)) 904 (void) printf( 905 MSG_INTL(MSG_LDD_FIL_ILLEGAL), 906 opath); 907 } 908 /* END CSTYLED */ 909 } else 910 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), opath, 911 strerror(EACCES)); 912 } else { 913 /* 914 * Search paths. 915 */ 916 DBG_CALL(Dbg_libs_insecure(lml, opath, 0)); 917 if ((lml->lm_flags & LML_FLG_TRC_SEARCH) && 918 ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0)) 919 (void) printf(MSG_INTL(MSG_LDD_PTH_IGNORE), opath); 920 } 921 return (0); 922 } 923 924 /* 925 * Determine whether a path already exists within the callers Pnode list. 926 */ 927 inline static uint_t 928 is_path_unique(Alist *alp, const char *path) 929 { 930 Aliste idx; 931 Pdesc *pdp; 932 933 for (ALIST_TRAVERSE(alp, idx, pdp)) { 934 if (pdp->pd_plen && (strcmp(pdp->pd_pname, path) == 0)) 935 return (PD_FLG_DUPLICAT); 936 } 937 return (0); 938 } 939 940 /* 941 * Expand one or more path names. This routine is called for all path strings, 942 * i.e., NEEDED, rpaths, default search paths, configuration file search paths, 943 * filtees, etc. The path may be a single path name, or a colon separated list 944 * of path names. Each individual path name is processed for possible reserved 945 * token expansion. All string nodes are maintained in allocated memory 946 * (regardless of whether they are constant (":"), or token expanded) to 947 * simplify path name descriptor removal. 948 * 949 * The info argument passes in auxiliary information regarding the callers 950 * intended use of the path names. This information may be maintained in the 951 * path name descriptor element produced to describe the path name (i.e., 952 * LA_SER_LIBPATH etc.), or may be used to determine additional security or 953 * diagnostic processing. 954 */ 955 int 956 expand_paths(Rt_map *clmp, const char *list, Alist **alpp, Aliste alni, 957 uint_t orig, uint_t omit) 958 { 959 char *str, *olist = 0, *nlist = (char *)list; 960 int fnull = FALSE; /* TRUE if empty final path segment seen */ 961 Pdesc *pdp = NULL; 962 963 for (str = nlist; *nlist || fnull; str = nlist) { 964 char *ostr; 965 char *elist = NULL; 966 size_t len, olen; 967 uint_t tkns = 0; 968 969 if (*nlist == ';') 970 ++nlist, ++str; 971 if ((*nlist == ':') || fnull) { 972 /* If not a final null segment, check following one */ 973 fnull = !(fnull || *(nlist + 1)); 974 975 if (*nlist) 976 nlist++; 977 978 /* 979 * When the shell sees a null PATH segment, it 980 * treats it as if it were the cwd (.). We mimic 981 * this behavior for LD_LIBRARY_PATH and runpaths 982 * (mainly for backwards compatibility with previous 983 * behavior). For other paths, this makes no sense, 984 * so we simply ignore the segment. 985 */ 986 if (!(orig & (LA_SER_LIBPATH | LA_SER_RUNPATH))) 987 continue; /* Process next segment */ 988 989 str = (char *)MSG_ORIG(MSG_FMT_CWD); 990 len = MSG_FMT_CWD_SIZE; 991 992 } else { 993 uint_t _tkns; 994 995 len = 0; 996 while (*nlist && (*nlist != ':') && (*nlist != ';')) { 997 if (*nlist == '/') 998 tkns |= PD_FLG_PNSLASH; 999 nlist++, len++; 1000 } 1001 1002 /* Check for a following final null segment */ 1003 fnull = (*nlist == ':') && !*(nlist + 1); 1004 1005 if (*nlist) 1006 nlist++; 1007 1008 /* 1009 * Expand the captured string. Besides expanding the 1010 * present path/file entry, we may have a new list to 1011 * deal with (ISALIST expands to multiple new entries). 1012 */ 1013 elist = nlist; 1014 ostr = str; 1015 olen = len; 1016 if ((_tkns = expand(&str, &len, &elist, orig, omit, 1017 clmp)) == 0) 1018 continue; 1019 tkns |= _tkns; 1020 } 1021 1022 /* 1023 * If this a secure application, validation of the expanded 1024 * path name may be necessary. 1025 */ 1026 if ((rtld_flags & RT_FL_SECURE) && 1027 (is_path_secure(str, clmp, orig, tkns) == 0)) 1028 continue; 1029 1030 /* 1031 * If required, ensure that the string is unique. For search 1032 * paths such as LD_LIBRARY_PATH, users often inherit multiple 1033 * paths which result in unnecessary duplication. Note, if 1034 * we're debugging, any duplicate entry is retained and flagged 1035 * so that the entry can be diagnosed later as part of unused 1036 * processing. 1037 */ 1038 if (orig & PD_FLG_UNIQUE) { 1039 Word tracing; 1040 1041 tracing = LIST(clmp)->lm_flags & 1042 (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED); 1043 tkns |= is_path_unique(*alpp, str); 1044 1045 /* 1046 * Note, use the debug strings rpl_debug and prm_debug 1047 * as an indicator that debugging has been requested, 1048 * rather than DBG_ENABLE(), as the initial use of 1049 * LD_LIBRARY_PATH occurs in preparation for loading 1050 * our debugging library. 1051 */ 1052 if ((tkns & PD_FLG_DUPLICAT) && (tracing == 0) && 1053 (rpl_debug == 0) && (prm_debug == 0)) 1054 continue; 1055 } 1056 1057 /* 1058 * Create a new pathname descriptor. 1059 */ 1060 if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc), 1061 alni)) == NULL) 1062 return (0); 1063 1064 pdp->pd_pname = str; 1065 pdp->pd_plen = len; 1066 pdp->pd_flags = (orig & LA_SER_MASK) | (tkns & PD_MSK_INHERIT); 1067 1068 /* 1069 * If token expansion occurred, maintain the original string. 1070 * This string can be used to provide a more informative error 1071 * diagnostic for a file that fails to load, or for displaying 1072 * unused search paths. 1073 */ 1074 if ((tkns & PD_MSK_EXPAND) && ((pdp->pd_oname = 1075 stravl_insert(ostr, 0, (olen + 1), 1)) == NULL)) 1076 return (0); 1077 1078 /* 1079 * Now that any duplication of the original string has occurred, 1080 * release any previous old listing. 1081 */ 1082 if (elist && (elist != nlist)) { 1083 if (olist) 1084 free(olist); 1085 nlist = olist = elist; 1086 } 1087 } 1088 1089 if (olist) 1090 free(olist); 1091 1092 /* 1093 * If no paths could be determined (perhaps because of security), then 1094 * indicate a failure. 1095 */ 1096 return (pdp != NULL); 1097 } 1098 1099 /* 1100 * Establish an objects fully resolved path. 1101 * 1102 * When $ORIGIN was first introduced, the expansion of a relative path name was 1103 * deferred until it was required. However now we insure a full path name is 1104 * always created - things like the analyzer wish to rely on librtld_db 1105 * returning a full path. The overhead of this is perceived to be low, 1106 * providing the associated libc version of getcwd is available (see 4336878). 1107 * This getcwd() was ported back to Solaris 8.1. 1108 */ 1109 size_t 1110 fullpath(Rt_map *lmp, Fdesc *fdp) 1111 { 1112 const char *name; 1113 1114 /* 1115 * Determine whether this path name is already resolved. 1116 */ 1117 if (fdp && (fdp->fd_flags & FLG_FD_RESOLVED)) { 1118 /* 1119 * If the resolved path differed from the original name, the 1120 * resolved path would have been recorded as the fd_pname. 1121 * Steal this path name from the file descriptor. Otherwise, 1122 * the path name is the same as the name of this object. 1123 */ 1124 if (fdp->fd_pname) 1125 PATHNAME(lmp) = fdp->fd_pname; 1126 else 1127 PATHNAME(lmp) = NAME(lmp); 1128 } else { 1129 /* 1130 * If this path name has not yet been resolved, resolve the 1131 * current name. 1132 */ 1133 char _path[PATH_MAX]; 1134 const char *path; 1135 int size, rsize; 1136 1137 if (fdp && fdp->fd_pname) 1138 PATHNAME(lmp) = fdp->fd_pname; 1139 else 1140 PATHNAME(lmp) = NAME(lmp); 1141 1142 name = path = PATHNAME(lmp); 1143 size = strlen(name); 1144 1145 if (path[0] != '/') { 1146 /* 1147 * If we can't determine the current directory (possible 1148 * if too many files are open - EMFILE), or if the 1149 * created path is too big, simply revert back to the 1150 * initial path name. 1151 */ 1152 if (getcwd(_path, (PATH_MAX - 2 - size)) != NULL) { 1153 (void) strcat(_path, MSG_ORIG(MSG_STR_SLASH)); 1154 (void) strcat(_path, name); 1155 path = _path; 1156 size = strlen(path); 1157 } 1158 } 1159 1160 /* 1161 * See if the path name can be reduced further. 1162 */ 1163 if ((rsize = resolvepath(path, _path, (PATH_MAX - 1))) > 0) { 1164 _path[rsize] = '\0'; 1165 path = _path; 1166 size = rsize; 1167 } 1168 1169 /* 1170 * If the path name is different from the original, duplicate it 1171 * so that it is available in a core file. If the duplication 1172 * fails simply leave the original path name alone. 1173 */ 1174 if ((PATHNAME(lmp) = 1175 stravl_insert(path, 0, (size + 1), 0)) == NULL) 1176 PATHNAME(lmp) = name; 1177 } 1178 1179 name = ORIGNAME(lmp) = PATHNAME(lmp); 1180 1181 /* 1182 * Establish the directory name size - this also acts as a flag that the 1183 * directory name has been computed. 1184 */ 1185 DIRSZ(lmp) = strrchr(name, '/') - name; 1186 return (DIRSZ(lmp)); 1187 } 1188