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