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