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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <sys/types.h>
40 static Config _config
= { 0 };
41 Config
*config
= &_config
;
44 * Validate a configuration file.
47 elf_config_validate(Addr addr
, Rtc_head
*head
, Rt_map
*lmp
)
49 Lm_list
*lml
= LIST(lmp
);
50 const char *str
, *strtbl
= config
->c_strtbl
;
58 * If this configuration file is for a specific application make sure
59 * we've been invoked by the application. Note that we only check the
60 * basename component of the application as the original application
61 * and its cached equivalent are never going to have the same pathnames.
62 * Also, we use PATHNAME() and not NAME() - this catches things like vi
63 * that exec shells using execv(/usr/bin/ksh, sh ...).
66 char *_str
, *_cname
, *cname
;
67 const char *aname
= PATHNAME(lmp
);
69 obj
= (Rtc_obj
*)(head
->ch_app
+ addr
);
70 cname
= _cname
= (char *)(strtbl
+ obj
->co_name
);
72 if ((_str
= strrchr(aname
, '/')) != NULL
)
74 if ((_str
= strrchr(cname
, '/')) != NULL
)
77 if (strcmp(aname
, cname
)) {
79 * It's possible a user is trying to ldd(1) an alternate
80 * shared object and point to a configuration file that
81 * the shared object is part of. In this case ignore
82 * any mismatch name warnings.
84 if ((lml
->lm_flags
& LML_FLG_TRC_ENABLE
) &&
85 ((FLAGS1(lmp
) & FL1_RT_LDDSTUB
) == 0)) {
86 eprintf(lml
, ERR_WARNING
,
87 MSG_INTL(MSG_CONF_APP
), config
->c_name
,
94 * If we have a valid alternative application reset its original
95 * name for possible $ORIGIN processing.
97 if ((FLAGS1(lmp
) & FL1_RT_LDDSTUB
) == 0) {
98 ORIGNAME(lmp
) = _cname
;
99 DIRSZ(lmp
) = cname
- _cname
- 1;
104 * If alternative objects are specified traverse the directories
105 * specified in the configuration file, if any directory is newer than
106 * the time it was recorded in the cache then continue to inspect its
107 * files. Any file determined newer than its configuration recording
108 * questions the the use of any alternative objects. The intent here
109 * is to make sure no-one abuses a configuration as a means of static
112 for (dirtbl
= (Rtc_dir
*)(head
->ch_dir
+ addr
);
113 dirtbl
->cd_obj
; dirtbl
++) {
115 * Skip directories that provide no files - this also catches
116 * RTC_OBJ_NOEXIST directories.
118 filetbl
= (Rtc_file
*)(dirtbl
->cd_file
+ addr
);
119 if (filetbl
->cf_obj
== 0)
123 * Skip directories that haven't provided real, dumped files.
125 obj
= (Rtc_obj
*)(dirtbl
->cd_obj
+ addr
);
126 if ((obj
->co_flags
& (RTC_OBJ_DUMP
| RTC_OBJ_REALPTH
)) !=
127 (RTC_OBJ_DUMP
| RTC_OBJ_REALPTH
))
130 str
= strtbl
+ obj
->co_name
;
132 if (rtld_stat(str
, &status
) != 0) {
134 eprintf(lml
, ERR_WARNING
, MSG_INTL(MSG_CONF_DSTAT
),
135 config
->c_name
, str
, strerror(err
));
139 if (status
.st_mtime
== obj
->co_info
)
143 * The system directory is newer than the configuration files
144 * entry, start checking any dumped files.
146 for (; filetbl
->cf_obj
; filetbl
++) {
147 obj
= (Rtc_obj
*)(filetbl
->cf_obj
+ addr
);
148 str
= strtbl
+ obj
->co_name
;
151 * Skip any files that aren't real, dumped files.
154 (RTC_OBJ_DUMP
| RTC_OBJ_REALPTH
)) !=
155 (RTC_OBJ_DUMP
| RTC_OBJ_REALPTH
))
158 if (rtld_stat(str
, &status
) != 0) {
160 eprintf(lml
, ERR_WARNING
,
161 MSG_INTL(MSG_CONF_FSTAT
), config
->c_name
,
167 * If the files size is different somethings been
170 if (status
.st_size
!= obj
->co_info
) {
171 eprintf(lml
, ERR_WARNING
,
172 MSG_INTL(MSG_CONF_FCMP
), config
->c_name
,
180 * Process a configuration file.
182 * A configuration file can be specified using the LD_CONFIG environment
183 * variable, from a DT_CONFIG string recorded in the executable (see ld(1) -c),
184 * or in the case of a crle() dumped image, the file is "fabricated" to a
185 * configuration file that may have been associated with the dumped image. In
186 * the absence of any of these techniques, a default configuration file is used.
188 * The LD_CONFIG variable take precedence, unless the application is secure, in
189 * which case the environment variable is ignored (see ld_generic_env()).
191 * A DT_CONFIG string is honored, even if the application is secure. However,
192 * the path name follows the same rules as RUNPATH's, which must be a full path
193 * name with no use of $ORIGIN.
196 elf_config(Rt_map
*lmp
, int aout
)
200 int fd
, features
= 0;
207 * If we're dealing with an alternative application, fabricate the need
208 * for a $ORIGIN/ld.config.app-name configuration file.
210 if (rtld_flags
& RT_FL_CONFAPP
) {
211 if ((str
= strrchr(PATHNAME(lmp
), '/')) != NULL
)
216 (void) snprintf(path
, PATH_MAX
, MSG_ORIG(MSG_ORG_CONFIG
), str
);
219 str
= config
->c_name
;
222 * If a configuration file name is known, expand and verify the name.
225 size_t size
= strlen(str
);
226 char *estr
= (char *)str
;
230 * Expand any configuration string.
232 if ((tkns
= expand(&estr
, &size
, 0, 0,
233 (PD_TKN_ISALIST
| PD_TKN_CAP
), lmp
)) == 0)
237 * If this is a secure application, validate the configuration
238 * file path name. Ignore any untrustworthy path name, and
239 * fall through to pick up the defaults.
241 if ((rtld_flags
& RT_FL_SECURE
) &&
242 (is_path_secure(estr
, lmp
, PD_FLG_FULLPATH
, tkns
) == 0))
245 str
= (const char *)estr
;
249 * If a configuration file has not been specified try opening up the
254 str
= MSG_ORIG(MSG_PTH_CONFIG_64
);
256 str
= MSG_ORIG(MSG_PTH_CONFIG
);
259 config
->c_name
= str
;
262 * If we can't open the configuration file return silently.
264 if ((fd
= open(str
, O_RDONLY
, 0)) == -1)
265 return (DBG_CONF_PRCFAIL
);
268 * Determine the configuration file size and map the file.
270 (void) rtld_fstat(fd
, &status
);
271 if (status
.st_size
< sizeof (Rtc_head
)) {
273 return (DBG_CONF_CORRUPT
);
275 if ((addr
= (Addr
)mmap(NULL
, status
.st_size
, PROT_READ
, MAP_SHARED
,
276 fd
, 0)) == (Addr
)MAP_FAILED
) {
278 return (DBG_CONF_PRCFAIL
);
283 * If we have an Rtc_id block at the beginning, then validate it
284 * and advance the address to the Rtc_head. If not, then trust
285 * that the file is compatible with us and move ahead (there is
286 * some error checking for Rtc_head below as well).
288 id
= (Rtc_id
*) addr
;
289 if (RTC_ID_TEST(id
)) {
290 addr
+= sizeof (*id
);
291 status
.st_size
-= sizeof (*id
);
292 if (status
.st_size
< sizeof (Rtc_head
))
293 return (DBG_CONF_CORRUPT
);
294 if ((id
->id_class
!= M_CLASS
) || (id
->id_data
!= M_DATA
) ||
295 (id
->id_machine
!= M_MACH
))
296 return (DBG_CONF_ABIMISMATCH
);
299 config
->c_bgn
= addr
;
300 config
->c_end
= addr
+ status
.st_size
;
302 head
= (Rtc_head
*)addr
;
305 * Make sure we can handle this version of the configuration file.
307 if (head
->ch_version
> RTC_VER_CURRENT
)
308 return (DBG_CONF_VERSION
);
311 * When crle(1) creates a temporary configuration file the
312 * RTC_HDR_IGNORE flag is set. Thus the mapping of the configuration
313 * file is taken into account but not its content.
315 if (head
->ch_cnflags
& RTC_HDR_IGNORE
)
316 return (DBG_CONF_IGNORE
);
319 * Apply any new default library pathname.
321 if (head
->ch_edlibpath
) {
322 str
= (const char *)(head
->ch_edlibpath
+ addr
);
323 #ifndef SGS_PRE_UNIFIED_PROCESS
324 if ((head
->ch_cnflags
& RTC_HDR_UPM
) == 0) {
326 str
= conv_config_upm(str
, MSG_ORIG(MSG_PTH_USRLIB_64
),
327 MSG_ORIG(MSG_PTH_LIB_64
), MSG_PTH_LIB_64_SIZE
);
329 str
= conv_config_upm(str
, MSG_ORIG(MSG_PTH_USRLIB
),
330 MSG_ORIG(MSG_PTH_LIB
), MSG_PTH_LIB_SIZE
);
334 if (expand_paths(lmp
, str
, &elf_def_dirs
, AL_CNT_SEARCH
,
335 (LA_SER_DEFAULT
| LA_SER_CONFIG
), PD_TKN_CAP
) != 0)
336 features
|= CONF_EDLIBPATH
;
338 if (head
->ch_eslibpath
) {
339 str
= (const char *)(head
->ch_eslibpath
+ addr
);
340 #ifndef SGS_PRE_UNIFIED_PROCESS
341 if ((head
->ch_cnflags
& RTC_HDR_UPM
) == 0) {
343 str
= conv_config_upm(str
,
344 MSG_ORIG(MSG_PTH_USRLIBSE_64
),
345 MSG_ORIG(MSG_PTH_LIBSE_64
), MSG_PTH_LIBSE_64_SIZE
);
347 str
= conv_config_upm(str
, MSG_ORIG(MSG_PTH_USRLIBSE
),
348 MSG_ORIG(MSG_PTH_LIBSE
), MSG_PTH_LIBSE_SIZE
);
352 if (expand_paths(lmp
, str
, &elf_sec_dirs
, AL_CNT_SEARCH
,
353 (LA_SER_SECURE
| LA_SER_CONFIG
), PD_TKN_CAP
) != 0)
354 features
|= CONF_ESLIBPATH
;
356 #if defined(__sparc) && !defined(_ELF64)
357 if (head
->ch_adlibpath
) {
358 str
= (const char *)(head
->ch_adlibpath
+ addr
);
359 if (expand_paths(lmp
, str
, &aout_def_dirs
, AL_CNT_SEARCH
,
360 (LA_SER_DEFAULT
| LA_SER_CONFIG
), PD_TKN_CAP
) != NULL
)
361 features
|= CONF_ADLIBPATH
;
363 if (head
->ch_aslibpath
) {
364 str
= (const char *)(head
->ch_aslibpath
+ addr
);
365 if (expand_paths(lmp
, str
, &aout_sec_dirs
, AL_CNT_SEARCH
,
366 (LA_SER_SECURE
| LA_SER_CONFIG
), PD_TKN_CAP
) != NULL
)
367 features
|= CONF_ASLIBPATH
;
371 * Apply any environment variables. This attribute was added with
374 if ((head
->ch_version
>= RTC_VER_THREE
) && head
->ch_env
&&
375 (!(rtld_flags
& RT_FL_NOENVCFG
))) {
376 if (readenv_config((Rtc_env
*)(head
->ch_env
+ addr
),
379 features
|= CONF_ENVS
;
383 * Determine whether filter/filtee associations are available.
385 if ((head
->ch_version
>= RTC_VER_FOUR
) && head
->ch_fltr
&&
386 (!(rtld_flags2
& RT_FL2_NOFLTCFG
))) {
387 rtld_flags2
|= RT_FL2_FLTCFG
;
388 config
->c_fltr
= (Rtc_fltr
*)(head
->ch_fltr
+ addr
);
389 config
->c_flte
= (Rtc_flte
*)(head
->ch_flte
+ addr
);
390 features
|= CONF_FLTR
;
394 * Determine whether directory configuration is available.
396 if ((!(rtld_flags
& RT_FL_NODIRCFG
)) && head
->ch_hash
) {
397 config
->c_hashtbl
= (Word
*)(head
->ch_hash
+ addr
);
398 config
->c_hashchain
= &config
->c_hashtbl
[2 +
399 config
->c_hashtbl
[0]];
400 config
->c_objtbl
= (Rtc_obj
*)(head
->ch_obj
+ addr
);
401 config
->c_strtbl
= (const char *)(head
->ch_str
+ addr
);
403 rtld_flags
|= RT_FL_DIRCFG
;
404 features
|= CONF_DIRCFG
;
408 * Determine whether alternative objects are specified or an object
409 * reservation area is required. If the reservation can't be completed
410 * (either because the configuration information is out-of-date, or the
411 * the reservation can't be allocated), then alternative objects are
414 if ((!(rtld_flags
& (RT_FL_NODIRCFG
| RT_FL_NOOBJALT
))) &&
415 (head
->ch_cnflags
& RTC_HDR_ALTER
)) {
416 rtld_flags
|= RT_FL_OBJALT
;
417 features
|= CONF_OBJALT
;
419 elf_config_validate(addr
, head
, lmp
);
421 if (head
->ch_resbgn
) {
423 if (((config
->c_bgn
<= head
->ch_resbgn
) &&
424 (config
->c_bgn
>= head
->ch_resend
)) ||
426 (caddr_t
)(uintptr_t)head
->ch_resbgn
,
427 (head
->ch_resend
- head
->ch_resbgn
), PROT_NONE
,
428 MAP_FIXED
| MAP_PRIVATE
) == MAP_FAILED
))
431 rtld_flags
|= RT_FL_MEMRESV
;
432 features
|= CONF_MEMRESV
;
440 * Determine whether the given file exists in the configuration file.
443 elf_config_ent(const char *name
, Word hash
, int id
, const char **alternate
)
449 bkt
= hash
% config
->c_hashtbl
[0];
450 ndx
= config
->c_hashtbl
[2 + bkt
];
453 obj
= config
->c_objtbl
+ ndx
;
454 str
= config
->c_strtbl
+ obj
->co_name
;
456 if ((obj
->co_hash
!= hash
) || (strcmp(name
, str
) != 0) ||
457 (id
&& (id
!= obj
->co_id
))) {
458 ndx
= config
->c_hashchain
[ndx
];
462 if ((obj
->co_flags
& RTC_OBJ_ALTER
) && alternate
)
463 *alternate
= config
->c_strtbl
+ obj
->co_alter
;
471 * Determine whether a filter and filtee string pair exists in the configuration
472 * file. If so, return the cached filtees that are associated with this pair as
476 elf_config_flt(Lm_list
*lml
, const char *filter
, const char *string
,
477 Alist
**alpp
, Aliste alni
)
481 for (fltrtbl
= (Rtc_fltr
*)config
->c_fltr
; fltrtbl
->fr_filter
;
484 const char *fltr
, *str
;
486 fltr
= config
->c_strtbl
+ fltrtbl
->fr_filter
;
487 str
= config
->c_strtbl
+ fltrtbl
->fr_string
;
488 if (strcmp(filter
, fltr
) || strcmp(string
, str
))
492 * Create a path descriptor for each filtee associated with this
493 * filter/filtee string pair. Note, no expansion of filtee
494 * entries is called for, as any original expansion would have
495 * been carried out before they were recorded in the
496 * configuration file.
499 for (fltetbl
= (Rtc_flte
*)((char *)config
->c_flte
+
500 fltrtbl
->fr_filtee
); fltetbl
->fe_filtee
; fltetbl
++) {
504 flte
= config
->c_strtbl
+ fltetbl
->fe_filtee
;
506 if ((pdp
= alist_append(alpp
, NULL
, sizeof (Pdesc
),
510 pdp
->pd_pname
= (char *)flte
;
511 pdp
->pd_plen
= strlen(flte
) + 1;
512 pdp
->pd_flags
= LA_SER_CONFIG
;
514 DBG_CALL(Dbg_file_filter(lml
, fltr
, flte
, 1));