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