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