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