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