xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/paths.c (revision e5803b76927480e8f9b67b22201c484ccf4c2bcf)
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
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
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 **
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 *
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
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
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
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
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
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