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