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 #include <sys/mman.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <rtc.h>
35 #include <debug.h>
36 #include <conv.h>
37 #include "_rtld.h"
38 #include "msg.h"
39
40 static Config _config = { 0 };
41 Config *config = &_config;
42
43 /*
44 * Validate a configuration file.
45 */
46 static void
elf_config_validate(Addr addr,Rtc_head * head,Rt_map * lmp)47 elf_config_validate(Addr addr, Rtc_head *head, Rt_map *lmp)
48 {
49 Lm_list *lml = LIST(lmp);
50 const char *str, *strtbl = config->c_strtbl;
51 Rtc_obj *obj;
52 Rtc_dir *dirtbl;
53 Rtc_file *filetbl;
54 rtld_stat_t status;
55 int err;
56
57 /*
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 ...).
64 */
65 if (head->ch_app) {
66 char *_str, *_cname, *cname;
67 const char *aname = PATHNAME(lmp);
68
69 obj = (Rtc_obj *)(head->ch_app + addr);
70 cname = _cname = (char *)(strtbl + obj->co_name);
71
72 if ((_str = strrchr(aname, '/')) != NULL)
73 aname = ++_str;
74 if ((_str = strrchr(cname, '/')) != NULL)
75 cname = ++_str;
76
77 if (strcmp(aname, cname)) {
78 /*
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.
83 */
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,
88 _cname);
89 return;
90 }
91 }
92
93 /*
94 * If we have a valid alternative application reset its original
95 * name for possible $ORIGIN processing.
96 */
97 if ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0) {
98 ORIGNAME(lmp) = _cname;
99 DIRSZ(lmp) = cname - _cname - 1;
100 }
101 }
102
103 /*
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
110 * linking.
111 */
112 for (dirtbl = (Rtc_dir *)(head->ch_dir + addr);
113 dirtbl->cd_obj; dirtbl++) {
114 /*
115 * Skip directories that provide no files - this also catches
116 * RTC_OBJ_NOEXIST directories.
117 */
118 filetbl = (Rtc_file *)(dirtbl->cd_file + addr);
119 if (filetbl->cf_obj == 0)
120 continue;
121
122 /*
123 * Skip directories that haven't provided real, dumped files.
124 */
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))
128 continue;
129
130 str = strtbl + obj->co_name;
131
132 if (rtld_stat(str, &status) != 0) {
133 err = errno;
134 eprintf(lml, ERR_WARNING, MSG_INTL(MSG_CONF_DSTAT),
135 config->c_name, str, strerror(err));
136 continue;
137 }
138
139 if (status.st_mtime == obj->co_info)
140 continue;
141
142 /*
143 * The system directory is newer than the configuration files
144 * entry, start checking any dumped files.
145 */
146 for (; filetbl->cf_obj; filetbl++) {
147 obj = (Rtc_obj *)(filetbl->cf_obj + addr);
148 str = strtbl + obj->co_name;
149
150 /*
151 * Skip any files that aren't real, dumped files.
152 */
153 if ((obj->co_flags &
154 (RTC_OBJ_DUMP | RTC_OBJ_REALPTH)) !=
155 (RTC_OBJ_DUMP | RTC_OBJ_REALPTH))
156 continue;
157
158 if (rtld_stat(str, &status) != 0) {
159 err = errno;
160 eprintf(lml, ERR_WARNING,
161 MSG_INTL(MSG_CONF_FSTAT), config->c_name,
162 str, strerror(err));
163 continue;
164 }
165
166 /*
167 * If the files size is different somethings been
168 * changed.
169 */
170 if (status.st_size != obj->co_info) {
171 eprintf(lml, ERR_WARNING,
172 MSG_INTL(MSG_CONF_FCMP), config->c_name,
173 str);
174 }
175 }
176 }
177 }
178
179 /*
180 * Process a configuration file.
181 *
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(1) 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.
187 *
188 * The LD_CONFIG variable takes precedence, unless the application is secure
189 * (see ld.so.1(1), issetugid(2)), in which case the environment variable is
190 * ignored (see ld_generic_env()).
191 *
192 * A DT_CONFIG string is honored, even if the application is secure. However,
193 * the path name follows the same rules as RUNPATH's, which must be a full path
194 * name with no use of $ORIGIN.
195 */
196 int
elf_config(Rt_map * lmp)197 elf_config(Rt_map *lmp)
198 {
199 Rtc_id *id;
200 Rtc_head *head;
201 int fd, features = 0;
202 rtld_stat_t status;
203 Addr addr;
204 const char *str;
205 char path[PATH_MAX];
206
207 /*
208 * If we're dealing with an alternative application, fabricate the need
209 * for a $ORIGIN/ld.config.app-name configuration file.
210 */
211 if (rtld_flags & RT_FL_CONFAPP) {
212 if ((str = strrchr(PATHNAME(lmp), '/')) != NULL)
213 str++;
214 else
215 str = PATHNAME(lmp);
216
217 (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_ORG_CONFIG), str);
218 str = path;
219 } else
220 str = config->c_name;
221
222 /*
223 * If a configuration file name is known, expand and verify the name.
224 */
225 if (str) {
226 size_t size = strlen(str);
227 char *estr = (char *)str;
228 uint_t tkns;
229
230 /*
231 * Expand any configuration string.
232 */
233 if ((tkns = expand(&estr, &size, 0, 0,
234 (PD_TKN_ISALIST | PD_TKN_CAP), lmp)) == 0)
235 return (0);
236
237 /*
238 * If this is a secure application, validate the configuration
239 * file path name. Ignore any untrustworthy path name, and
240 * fall through to pick up the defaults.
241 */
242 if ((rtld_flags & RT_FL_SECURE) &&
243 (is_path_secure(estr, lmp, PD_FLG_FULLPATH, tkns) == 0))
244 str = NULL;
245 else
246 str = (const char *)estr;
247 }
248
249 /*
250 * If a configuration file has not been specified try opening up the
251 * default.
252 */
253 if (str == NULL) {
254 #if defined(_ELF64)
255 str = MSG_ORIG(MSG_PTH_CONFIG_64);
256 #else
257 str = MSG_ORIG(MSG_PTH_CONFIG);
258 #endif
259 }
260 config->c_name = str;
261
262 /*
263 * If we can't open the configuration file return silently.
264 */
265 if ((fd = open(str, O_RDONLY, 0)) == -1)
266 return (DBG_CONF_PRCFAIL);
267
268 /*
269 * Determine the configuration file size and map the file.
270 */
271 (void) rtld_fstat(fd, &status);
272 if (status.st_size < sizeof (Rtc_head)) {
273 (void) close(fd);
274 return (DBG_CONF_CORRUPT);
275 }
276 if ((addr = (Addr)mmap(0, status.st_size, PROT_READ, MAP_SHARED,
277 fd, 0)) == (Addr)MAP_FAILED) {
278 (void) close(fd);
279 return (DBG_CONF_PRCFAIL);
280 }
281 (void) close(fd);
282
283 /*
284 * If we have an Rtc_id block at the beginning, then validate it
285 * and advance the address to the Rtc_head. If not, then trust
286 * that the file is compatible with us and move ahead (there is
287 * some error checking for Rtc_head below as well).
288 */
289 id = (Rtc_id *) addr;
290 if (RTC_ID_TEST(id)) {
291 addr += sizeof (*id);
292 status.st_size -= sizeof (*id);
293 if (status.st_size < sizeof (Rtc_head))
294 return (DBG_CONF_CORRUPT);
295 if ((id->id_class != M_CLASS) || (id->id_data != M_DATA) ||
296 (id->id_machine != M_MACH))
297 return (DBG_CONF_ABIMISMATCH);
298 }
299
300 config->c_bgn = addr;
301 config->c_end = addr + status.st_size;
302
303 head = (Rtc_head *)addr;
304
305 /*
306 * Make sure we can handle this version of the configuration file.
307 */
308 if (head->ch_version > RTC_VER_CURRENT)
309 return (DBG_CONF_VERSION);
310
311 /*
312 * When crle(1) creates a temporary configuration file the
313 * RTC_HDR_IGNORE flag is set. Thus the mapping of the configuration
314 * file is taken into account but not its content.
315 */
316 if (head->ch_cnflags & RTC_HDR_IGNORE)
317 return (DBG_CONF_IGNORE);
318
319 /*
320 * Apply any new default library pathname.
321 */
322 if (head->ch_edlibpath) {
323 str = (const char *)(head->ch_edlibpath + addr);
324 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
325 #if defined(_ELF64)
326 str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIB_64),
327 MSG_ORIG(MSG_PTH_LIB_64), MSG_PTH_LIB_64_SIZE);
328 #else
329 str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIB),
330 MSG_ORIG(MSG_PTH_LIB), MSG_PTH_LIB_SIZE);
331 #endif
332 }
333 if (expand_paths(lmp, str, &elf_def_dirs, AL_CNT_SEARCH,
334 (LA_SER_DEFAULT | LA_SER_CONFIG), PD_TKN_CAP) != 0)
335 features |= CONF_EDLIBPATH;
336 }
337 if (head->ch_eslibpath) {
338 str = (const char *)(head->ch_eslibpath + addr);
339 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
340 #if defined(_ELF64)
341 str = conv_config_upm(str,
342 MSG_ORIG(MSG_PTH_USRLIBSE_64),
343 MSG_ORIG(MSG_PTH_LIBSE_64), MSG_PTH_LIBSE_64_SIZE);
344 #else
345 str = conv_config_upm(str, MSG_ORIG(MSG_PTH_USRLIBSE),
346 MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE);
347 #endif
348 }
349 if (expand_paths(lmp, str, &elf_sec_dirs, AL_CNT_SEARCH,
350 (LA_SER_SECURE | LA_SER_CONFIG), PD_TKN_CAP) != 0)
351 features |= CONF_ESLIBPATH;
352 }
353
354 /*
355 * Apply any environment variables. This attribute was added with
356 * RTC_VER_THREE.
357 */
358 if ((head->ch_version >= RTC_VER_THREE) && head->ch_env &&
359 (!(rtld_flags & RT_FL_NOENVCFG))) {
360 if (readenv_config((Rtc_env *)(head->ch_env + addr),
361 addr) != 0)
362 return (-1);
363 features |= CONF_ENVS;
364 }
365
366 /*
367 * Determine whether filter/filtee associations are available.
368 */
369 if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr &&
370 (!(rtld_flags2 & RT_FL2_NOFLTCFG))) {
371 rtld_flags2 |= RT_FL2_FLTCFG;
372 config->c_fltr = (Rtc_fltr *)(head->ch_fltr + addr);
373 config->c_flte = (Rtc_flte *)(head->ch_flte + addr);
374 features |= CONF_FLTR;
375 }
376
377 /*
378 * Determine whether directory configuration is available.
379 */
380 if ((!(rtld_flags & RT_FL_NODIRCFG)) && head->ch_hash) {
381 config->c_hashtbl = (Word *)(head->ch_hash + addr);
382 config->c_hashchain = &config->c_hashtbl[2 +
383 config->c_hashtbl[0]];
384 config->c_objtbl = (Rtc_obj *)(head->ch_obj + addr);
385 config->c_strtbl = (const char *)(head->ch_str + addr);
386
387 rtld_flags |= RT_FL_DIRCFG;
388 features |= CONF_DIRCFG;
389 }
390
391 /*
392 * Determine whether alternative objects are specified or an object
393 * reservation area is required. If the reservation can't be completed
394 * (either because the configuration information is out-of-date, or the
395 * the reservation can't be allocated), then alternative objects are
396 * ignored.
397 */
398 if ((!(rtld_flags & (RT_FL_NODIRCFG | RT_FL_NOOBJALT))) &&
399 (head->ch_cnflags & RTC_HDR_ALTER)) {
400 rtld_flags |= RT_FL_OBJALT;
401 features |= CONF_OBJALT;
402
403 elf_config_validate(addr, head, lmp);
404
405 if (head->ch_resbgn) {
406
407 if (((config->c_bgn <= head->ch_resbgn) &&
408 (config->c_bgn >= head->ch_resend)) ||
409 (nu_map(LIST(lmp),
410 (caddr_t)(uintptr_t)head->ch_resbgn,
411 (head->ch_resend - head->ch_resbgn), PROT_NONE,
412 MAP_FIXED | MAP_PRIVATE) == MAP_FAILED))
413 return (-1);
414
415 rtld_flags |= RT_FL_MEMRESV;
416 features |= CONF_MEMRESV;
417 }
418 }
419
420 return (features);
421 }
422
423 /*
424 * Determine whether the given file exists in the configuration file.
425 */
426 Rtc_obj *
elf_config_ent(const char * name,Word hash,int id,const char ** alternate)427 elf_config_ent(const char *name, Word hash, int id, const char **alternate)
428 {
429 Word bkt, ndx;
430 const char *str;
431 Rtc_obj *obj;
432
433 bkt = hash % config->c_hashtbl[0];
434 ndx = config->c_hashtbl[2 + bkt];
435
436 while (ndx) {
437 obj = config->c_objtbl + ndx;
438 str = config->c_strtbl + obj->co_name;
439
440 if ((obj->co_hash != hash) || (strcmp(name, str) != 0) ||
441 (id && (id != obj->co_id))) {
442 ndx = config->c_hashchain[ndx];
443 continue;
444 }
445
446 if ((obj->co_flags & RTC_OBJ_ALTER) && alternate)
447 *alternate = config->c_strtbl + obj->co_alter;
448
449 return (obj);
450 }
451 return (0);
452 }
453
454 /*
455 * Determine whether a filter and filtee string pair exists in the configuration
456 * file. If so, return the cached filtees that are associated with this pair as
457 * an Alist.
458 */
459 void
elf_config_flt(Lm_list * lml,const char * filter,const char * string,Alist ** alpp,Aliste alni)460 elf_config_flt(Lm_list *lml, const char *filter, const char *string,
461 Alist **alpp, Aliste alni)
462 {
463 Rtc_fltr *fltrtbl;
464
465 for (fltrtbl = (Rtc_fltr *)config->c_fltr; fltrtbl->fr_filter;
466 fltrtbl++) {
467 Rtc_flte *fltetbl;
468 const char *fltr, *str;
469
470 fltr = config->c_strtbl + fltrtbl->fr_filter;
471 str = config->c_strtbl + fltrtbl->fr_string;
472 if (strcmp(filter, fltr) || strcmp(string, str))
473 continue;
474
475 /*
476 * Create a path descriptor for each filtee associated with this
477 * filter/filtee string pair. Note, no expansion of filtee
478 * entries is called for, as any original expansion would have
479 * been carried out before they were recorded in the
480 * configuration file.
481 */
482 /* LINTED */
483 for (fltetbl = (Rtc_flte *)((char *)config->c_flte +
484 fltrtbl->fr_filtee); fltetbl->fe_filtee; fltetbl++) {
485 const char *flte;
486 Pdesc *pdp;
487
488 flte = config->c_strtbl + fltetbl->fe_filtee;
489
490 if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc),
491 alni)) == NULL)
492 return;
493
494 pdp->pd_pname = (char *)flte;
495 pdp->pd_plen = strlen(flte) + 1;
496 pdp->pd_flags = LA_SER_CONFIG;
497
498 DBG_CALL(Dbg_file_filter(lml, fltr, flte, 1));
499 }
500 }
501 }
502