File: | src/libexec/ld.so/loader.c |
Warning: | line 715, column 3 Value stored to 'fails' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: loader.c,v 1.195 2022/01/08 06:49:41 guenther Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1998 Per Fogelstrom, Opsycon AB |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS |
16 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | * SUCH DAMAGE. |
26 | * |
27 | */ |
28 | |
29 | #define _DYN_LOADER |
30 | |
31 | #include <sys/types.h> |
32 | #include <sys/mman.h> |
33 | #include <sys/exec.h> |
34 | #ifdef __i386__ |
35 | # include <machine/vmparam.h> |
36 | #endif |
37 | #include <string.h> |
38 | #include <link.h> |
39 | #include <limits.h> /* NAME_MAX */ |
40 | #include <dlfcn.h> |
41 | #include <tib.h> |
42 | |
43 | #include "syscall.h" |
44 | #include "util.h" |
45 | #include "resolve.h" |
46 | #include "path.h" |
47 | #include "sod.h" |
48 | |
49 | /* |
50 | * Local decls. |
51 | */ |
52 | unsigned long _dl_boot(const char **, char **, const long, long *) __boot__attribute__((section(".boot.text"))); |
53 | void _dl_debug_state(void); |
54 | void _dl_setup_env(const char *_argv0, char **_envp) __boot__attribute__((section(".boot.text"))); |
55 | void _dl_dtors(void); |
56 | void _dl_dopreload(char *_paths) __boot__attribute__((section(".boot.text"))); |
57 | void _dl_fixup_user_env(void) __boot__attribute__((section(".boot.text"))); |
58 | void _dl_call_preinit(elf_object_t *) __boot__attribute__((section(".boot.text"))); |
59 | void _dl_call_init_recurse(elf_object_t *object, int initfirst); |
60 | void _dl_clean_boot(void); |
61 | static inline void unprotect_if_textrel(elf_object_t *_object); |
62 | static inline void reprotect_if_textrel(elf_object_t *_object); |
63 | static void _dl_rreloc(elf_object_t *_object); |
64 | |
65 | int _dl_pagesz __relro__attribute__((section(".data.rel.ro"))) = 4096; |
66 | int _dl_bindnow __relro__attribute__((section(".data.rel.ro"))) = 0; |
67 | int _dl_debug __relro__attribute__((section(".data.rel.ro"))) = 0; |
68 | int _dl_trust __relro__attribute__((section(".data.rel.ro"))) = 0; |
69 | char **_dl_libpath __relro__attribute__((section(".data.rel.ro"))) = NULL((void*)0); |
70 | const char **_dl_argv __relro__attribute__((section(".data.rel.ro"))) = NULL((void*)0); |
71 | int _dl_argc __relro__attribute__((section(".data.rel.ro"))) = 0; |
72 | |
73 | char *_dl_preload __boot_data__attribute__((section(".boot.data"))) = NULL((void*)0); |
74 | char *_dl_tracefmt1 __boot_data__attribute__((section(".boot.data"))) = NULL((void*)0); |
75 | char *_dl_tracefmt2 __boot_data__attribute__((section(".boot.data"))) = NULL((void*)0); |
76 | char *_dl_traceprog __boot_data__attribute__((section(".boot.data"))) = NULL((void*)0); |
77 | void *_dl_exec_hint __boot_data__attribute__((section(".boot.data"))) = NULL((void*)0); |
78 | |
79 | char **environ = NULL((void*)0); |
80 | char *__progname = NULL((void*)0); |
81 | |
82 | int _dl_traceld; |
83 | struct r_debug *_dl_debug_map; |
84 | |
85 | static dl_cb_cb _dl_cb_cb; |
86 | const struct dl_cb_0 callbacks_0 = { |
87 | .dl_allocate_tib = &_dl_allocate_tib, |
88 | .dl_free_tib = &_dl_free_tib, |
89 | #if DO_CLEAN_BOOT1 |
90 | .dl_clean_boot = &_dl_clean_boot, |
91 | #endif |
92 | .dlopen = &dlopen, |
93 | .dlclose = &dlclose, |
94 | .dlsym = &dlsym, |
95 | .dladdr = &dladdr, |
96 | .dlctl = &dlctl, |
97 | .dlerror = &dlerror, |
98 | .dl_iterate_phdr = &dl_iterate_phdr, |
99 | }; |
100 | |
101 | |
102 | /* |
103 | * Run dtors for a single object. |
104 | */ |
105 | void |
106 | _dl_run_dtors(elf_object_t *obj) |
107 | { |
108 | if (obj->dynDyn.u.fini_array) { |
109 | int num = obj->dynDyn.u.fini_arraysz / sizeof(Elf_AddrElf64_Addr); |
110 | int i; |
111 | |
112 | DL_DEB(("doing finiarray obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing finiarray obj %p @%p: [%s]\n" , obj, obj->Dyn.u.fini_array, obj->load_name) ; } while (0) |
113 | obj, obj->dyn.fini_array, obj->load_name))do { if (_dl_debug) _dl_printf ("doing finiarray obj %p @%p: [%s]\n" , obj, obj->Dyn.u.fini_array, obj->load_name) ; } while (0); |
114 | for (i = num; i > 0; i--) |
115 | (*obj->dynDyn.u.fini_array[i-1])(); |
116 | } |
117 | |
118 | if (obj->dynDyn.u.fini) { |
119 | DL_DEB(("doing dtors obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing dtors obj %p @%p: [%s]\n" , obj, obj->Dyn.u.fini, obj->load_name) ; } while (0) |
120 | obj, obj->dyn.fini, obj->load_name))do { if (_dl_debug) _dl_printf ("doing dtors obj %p @%p: [%s]\n" , obj, obj->Dyn.u.fini, obj->load_name) ; } while (0); |
121 | (*obj->dynDyn.u.fini)(); |
122 | } |
123 | } |
124 | |
125 | /* |
126 | * Run dtors for all objects that are eligible. |
127 | */ |
128 | void |
129 | _dl_run_all_dtors(void) |
130 | { |
131 | elf_object_t *node; |
132 | int fini_complete; |
133 | int skip_initfirst; |
134 | int initfirst_skipped; |
135 | |
136 | fini_complete = 0; |
137 | skip_initfirst = 1; |
138 | initfirst_skipped = 0; |
139 | |
140 | while (fini_complete == 0) { |
141 | fini_complete = 1; |
142 | for (node = _dl_objects; |
143 | node != NULL((void*)0); |
144 | node = node->next) { |
145 | if ((node->dynDyn.u.fini || node->dynDyn.u.fini_array) && |
146 | (OBJECT_REF_CNT(node)((node->refcount + node->opencount + node->grprefcount )) == 0) && |
147 | (node->status & STAT_INIT_DONE0x004) && |
148 | ((node->status & STAT_FINI_DONE0x008) == 0)) { |
149 | if (skip_initfirst && |
150 | (node->obj_flags & DF_1_INITFIRST0x00000020)) |
151 | initfirst_skipped = 1; |
152 | else |
153 | node->status |= STAT_FINI_READY0x010; |
154 | } |
155 | } |
156 | for (node = _dl_objects; |
157 | node != NULL((void*)0); |
158 | node = node->next ) { |
159 | if ((node->dynDyn.u.fini || node->dynDyn.u.fini_array) && |
160 | (OBJECT_REF_CNT(node)((node->refcount + node->opencount + node->grprefcount )) == 0) && |
161 | (node->status & STAT_INIT_DONE0x004) && |
162 | ((node->status & STAT_FINI_DONE0x008) == 0) && |
163 | (!skip_initfirst || |
164 | (node->obj_flags & DF_1_INITFIRST0x00000020) == 0)) { |
165 | struct object_vector vec = node->child_vec; |
166 | int i; |
167 | |
168 | for (i = 0; i < vec.len; i++) |
169 | vec.vec[i]->status &= ~STAT_FINI_READY0x010; |
170 | } |
171 | } |
172 | |
173 | |
174 | for (node = _dl_objects; |
175 | node != NULL((void*)0); |
176 | node = node->next ) { |
177 | if (node->status & STAT_FINI_READY0x010) { |
178 | fini_complete = 0; |
179 | node->status |= STAT_FINI_DONE0x008; |
180 | node->status &= ~STAT_FINI_READY0x010; |
181 | _dl_run_dtors(node); |
182 | } |
183 | } |
184 | |
185 | if (fini_complete && initfirst_skipped) |
186 | fini_complete = initfirst_skipped = skip_initfirst = 0; |
187 | } |
188 | } |
189 | |
190 | /* |
191 | * Routine to walk through all of the objects except the first |
192 | * (main executable). |
193 | * |
194 | * Big question, should dlopen()ed objects be unloaded before or after |
195 | * the destructor for the main application runs? |
196 | */ |
197 | void |
198 | _dl_dtors(void) |
199 | { |
200 | _dl_thread_kern_stop(); |
201 | |
202 | /* ORDER? */ |
203 | _dl_unload_dlopen(); |
204 | |
205 | DL_DEB(("doing dtors\n"))do { if (_dl_debug) _dl_printf ("doing dtors\n") ; } while (0 ); |
206 | |
207 | _dl_objects->opencount--; |
208 | _dl_notify_unload_shlib(_dl_objects); |
209 | |
210 | _dl_run_all_dtors(); |
211 | } |
212 | |
213 | #if DO_CLEAN_BOOT1 |
214 | void |
215 | _dl_clean_boot(void) |
216 | { |
217 | extern char boot_text_start[], boot_text_end[]; |
218 | #if 0 /* XXX breaks boehm-gc?!? */ |
219 | extern char boot_data_start[], boot_data_end[]; |
220 | #endif |
221 | |
222 | _dl_munmap(boot_text_start, boot_text_end - boot_text_start); |
223 | #if 0 /* XXX breaks boehm-gc?!? */ |
224 | _dl_munmap(boot_data_start, boot_data_end - boot_data_start); |
225 | #endif |
226 | } |
227 | #endif /* DO_CLEAN_BOOT */ |
228 | |
229 | void |
230 | _dl_dopreload(char *paths) |
231 | { |
232 | char *cp, *dp; |
233 | elf_object_t *shlib; |
234 | int count; |
235 | |
236 | dp = paths = _dl_strdup(paths); |
237 | if (dp == NULL((void*)0)) |
238 | _dl_oom(); |
239 | |
240 | /* preallocate child_vec for the LD_PRELOAD objects */ |
241 | count = 1; |
242 | while (*dp++ != '\0') |
243 | if (*dp == ':') |
244 | count++; |
245 | object_vec_grow(&_dl_objects->child_vec, count); |
246 | |
247 | dp = paths; |
248 | while ((cp = _dl_strsep(&dp, ":")) != NULL((void*)0)) { |
249 | shlib = _dl_load_shlib(cp, _dl_objects, OBJTYPE_LIB3, |
250 | _dl_objects->obj_flags); |
251 | if (shlib == NULL((void*)0)) |
252 | _dl_die("can't preload library '%s'", cp); |
253 | _dl_add_object(shlib); |
254 | _dl_link_child(shlib, _dl_objects); |
255 | } |
256 | _dl_free(paths); |
257 | return; |
258 | } |
259 | |
260 | /* |
261 | * grab interesting environment variables, zap bad env vars if |
262 | * issetugid, and set the exported environ and __progname variables |
263 | */ |
264 | void |
265 | _dl_setup_env(const char *argv0, char **envp) |
266 | { |
267 | static char progname_storage[NAME_MAX255+1] = ""; |
268 | |
269 | /* |
270 | * Don't allow someone to change the search paths if he runs |
271 | * a suid program without credentials high enough. |
272 | */ |
273 | _dl_trust = !_dl_issetugid(); |
274 | if (!_dl_trust) { /* Zap paths if s[ug]id... */ |
275 | _dl_unsetenv("LD_DEBUG", envp); |
276 | _dl_unsetenv("LD_LIBRARY_PATH", envp); |
277 | _dl_unsetenv("LD_PRELOAD", envp); |
278 | _dl_unsetenv("LD_BIND_NOW", envp); |
279 | } else { |
280 | /* |
281 | * Get paths to various things we are going to use. |
282 | */ |
283 | _dl_debug = _dl_getenv("LD_DEBUG", envp) != NULL((void*)0); |
284 | _dl_libpath = _dl_split_path(_dl_getenv("LD_LIBRARY_PATH", |
285 | envp)); |
286 | _dl_preload = _dl_getenv("LD_PRELOAD", envp); |
287 | _dl_bindnow = _dl_getenv("LD_BIND_NOW", envp) != NULL((void*)0); |
288 | } |
289 | |
290 | /* these are usable even in setugid processes */ |
291 | _dl_traceld = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp) != NULL((void*)0); |
292 | _dl_tracefmt1 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT1", envp); |
293 | _dl_tracefmt2 = _dl_getenv("LD_TRACE_LOADED_OBJECTS_FMT2", envp); |
294 | _dl_traceprog = _dl_getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", envp); |
295 | |
296 | environ = envp; |
297 | |
298 | _dl_trace_setup(envp); |
299 | |
300 | if (argv0 != NULL((void*)0)) { /* NULL ptr if argc = 0 */ |
301 | const char *p = _dl_strrchr(argv0, '/'); |
302 | |
303 | if (p == NULL((void*)0)) |
304 | p = argv0; |
305 | else |
306 | p++; |
307 | _dl_strlcpy(progname_storage, p, sizeof(progname_storage)); |
308 | } |
309 | __progname = progname_storage; |
310 | } |
311 | |
312 | int |
313 | _dl_load_dep_libs(elf_object_t *object, int flags, int booting) |
314 | { |
315 | elf_object_t *dynobj; |
316 | Elf_DynElf64_Dyn *dynp; |
317 | unsigned int loop; |
318 | int libcount; |
319 | int depflags; |
320 | |
321 | dynobj = object; |
322 | while (dynobj) { |
323 | DL_DEB(("examining: '%s'\n", dynobj->load_name))do { if (_dl_debug) _dl_printf ("examining: '%s'\n", dynobj-> load_name) ; } while (0); |
324 | libcount = 0; |
325 | |
326 | /* propagate DF_1_NOW to deplibs (can be set by dynamic tags) */ |
327 | depflags = flags | (dynobj->obj_flags & DF_1_NOW0x00000001); |
328 | |
329 | for (dynp = dynobj->load_dyn; dynp->d_tag; dynp++) { |
330 | if (dynp->d_tag == DT_NEEDED1) { |
331 | libcount++; |
332 | } |
333 | } |
334 | |
335 | if ( libcount != 0) { |
336 | struct listent { |
337 | Elf_DynElf64_Dyn *dynp; |
338 | elf_object_t *depobj; |
339 | } *liblist; |
340 | int *randomlist; |
341 | |
342 | liblist = _dl_reallocarray(NULL((void*)0), libcount, |
343 | sizeof(struct listent)); |
344 | randomlist = _dl_reallocarray(NULL((void*)0), libcount, |
345 | sizeof(int)); |
346 | |
347 | if (liblist == NULL((void*)0) || randomlist == NULL((void*)0)) |
348 | _dl_oom(); |
349 | |
350 | for (dynp = dynobj->load_dyn, loop = 0; dynp->d_tag; |
351 | dynp++) |
352 | if (dynp->d_tag == DT_NEEDED1) |
353 | liblist[loop++].dynp = dynp; |
354 | |
355 | /* Randomize these */ |
356 | for (loop = 0; loop < libcount; loop++) |
357 | randomlist[loop] = loop; |
358 | |
359 | for (loop = 1; loop < libcount; loop++) { |
360 | unsigned int rnd; |
361 | int cur; |
362 | rnd = _dl_arc4random(); |
363 | rnd = rnd % (loop+1); |
364 | cur = randomlist[rnd]; |
365 | randomlist[rnd] = randomlist[loop]; |
366 | randomlist[loop] = cur; |
367 | } |
368 | |
369 | for (loop = 0; loop < libcount; loop++) { |
370 | elf_object_t *depobj; |
371 | const char *libname; |
372 | libname = dynobj->dynDyn.u.strtab; |
373 | libname += |
374 | liblist[randomlist[loop]].dynp->d_un.d_val; |
375 | DL_DEB(("loading: %s required by %s\n", libname,do { if (_dl_debug) _dl_printf ("loading: %s required by %s\n" , libname, dynobj->load_name) ; } while (0) |
376 | dynobj->load_name))do { if (_dl_debug) _dl_printf ("loading: %s required by %s\n" , libname, dynobj->load_name) ; } while (0); |
377 | depobj = _dl_load_shlib(libname, dynobj, |
378 | OBJTYPE_LIB3, depflags); |
379 | if (depobj == 0) { |
380 | if (booting) { |
381 | _dl_die( |
382 | "can't load library '%s'", |
383 | libname); |
384 | } |
385 | DL_DEB(("dlopen: failed to open %s\n",do { if (_dl_debug) _dl_printf ("dlopen: failed to open %s\n" , libname) ; } while (0) |
386 | libname))do { if (_dl_debug) _dl_printf ("dlopen: failed to open %s\n" , libname) ; } while (0); |
387 | _dl_free(liblist); |
388 | _dl_free(randomlist); |
389 | return (1); |
390 | } |
391 | liblist[randomlist[loop]].depobj = depobj; |
392 | } |
393 | |
394 | object_vec_grow(&dynobj->child_vec, libcount); |
395 | for (loop = 0; loop < libcount; loop++) { |
396 | _dl_add_object(liblist[loop].depobj); |
397 | _dl_link_child(liblist[loop].depobj, dynobj); |
398 | } |
399 | _dl_free(liblist); |
400 | _dl_free(randomlist); |
401 | } |
402 | dynobj = dynobj->next; |
403 | } |
404 | |
405 | _dl_cache_grpsym_list_setup(object); |
406 | |
407 | return(0); |
408 | } |
409 | |
410 | |
411 | /* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */ |
412 | static inline void |
413 | _dl_self_relro(long loff) |
414 | { |
415 | Elf_EhdrElf64_Ehdr *ehdp; |
416 | Elf_PhdrElf64_Phdr *phdp; |
417 | int i; |
418 | |
419 | ehdp = (Elf_EhdrElf64_Ehdr *)loff; |
420 | phdp = (Elf_PhdrElf64_Phdr *)(loff + ehdp->e_phoff); |
421 | for (i = 0; i < ehdp->e_phnum; i++, phdp++) { |
422 | switch (phdp->p_type) { |
423 | #if defined(__alpha__) || defined(__hppa__) || defined(__powerpc__) || \ |
424 | defined(__sparc64__) |
425 | case PT_LOAD1: |
426 | if ((phdp->p_flags & (PF_X0x1 | PF_W0x2)) != (PF_X0x1 | PF_W0x2)) |
427 | break; |
428 | _dl_mprotect((void *)(phdp->p_vaddr + loff), |
429 | phdp->p_memsz, PROT_READ0x01); |
430 | break; |
431 | #endif |
432 | case PT_GNU_RELRO0x6474e552: |
433 | _dl_mprotect((void *)(phdp->p_vaddr + loff), |
434 | phdp->p_memsz, PROT_READ0x01); |
435 | break; |
436 | } |
437 | } |
438 | } |
439 | |
440 | |
441 | #define PFLAGS(X)((((X) & 0x4) ? 0x01 : 0) | (((X) & 0x2) ? 0x02 : 0) | (((X) & 0x1) ? 0x04 : 0)) ((((X) & PF_R0x4) ? PROT_READ0x01 : 0) | \ |
442 | (((X) & PF_W0x2) ? PROT_WRITE0x02 : 0) | \ |
443 | (((X) & PF_X0x1) ? PROT_EXEC0x04 : 0)) |
444 | |
445 | /* |
446 | * This is the dynamic loader entrypoint. When entering here, depending |
447 | * on architecture type, the stack and registers are set up according |
448 | * to the architectures ABI specification. The first thing required |
449 | * to do is to dig out all information we need to accomplish our task. |
450 | */ |
451 | unsigned long |
452 | _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) |
453 | { |
454 | struct elf_object *exe_obj; /* Pointer to executable object */ |
455 | struct elf_object *dyn_obj; /* Pointer to ld.so object */ |
456 | struct r_debug **map_link; /* Where to put pointer for gdb */ |
457 | struct r_debug *debug_map; |
458 | struct load_list *next_load, *load_list = NULL((void*)0); |
459 | Elf_DynElf64_Dyn *dynp; |
460 | Elf_PhdrElf64_Phdr *phdp; |
461 | Elf_EhdrElf64_Ehdr *ehdr; |
462 | char *us = NULL((void*)0); |
463 | unsigned int loop; |
464 | int failed; |
465 | struct dep_node *n; |
466 | Elf_AddrElf64_Addr minva, maxva, exe_loff, exec_end, cur_exec_end; |
467 | Elf_AddrElf64_Addr relro_addr = 0, relro_size = 0; |
468 | Elf_PhdrElf64_Phdr *ptls = NULL((void*)0); |
469 | int align; |
470 | |
471 | if (dl_data[AUX_pagesz] != 0) |
472 | _dl_pagesz = dl_data[AUX_pagesz]; |
473 | _dl_malloc_init(); |
474 | |
475 | _dl_argv = argv; |
476 | while (_dl_argv[_dl_argc] != NULL((void*)0)) |
477 | _dl_argc++; |
478 | _dl_setup_env(argv[0], envp); |
479 | |
480 | /* |
481 | * Make read-only the GOT and PLT and variables initialized |
482 | * during the ld.so setup above. |
483 | */ |
484 | _dl_self_relro(dyn_loff); |
485 | |
486 | align = _dl_pagesz - 1; |
487 | |
488 | #define ROUND_PG(x)(((x) + align) & ~(align)) (((x) + align) & ~(align)) |
489 | #define TRUNC_PG(x)((x) & ~(align)) ((x) & ~(align)) |
490 | |
491 | if (_dl_bindnow) { |
492 | /* Lazy binding disabled, so disable kbind */ |
493 | _dl_kbind(NULL((void*)0), 0, 0); |
494 | } |
495 | |
496 | DL_DEB(("ld.so loading: '%s'\n", __progname))do { if (_dl_debug) _dl_printf ("ld.so loading: '%s'\n", __progname ) ; } while (0); |
497 | |
498 | /* init this in runtime, not statically */ |
499 | TAILQ_INIT(&_dlopened_child_list)do { (&_dlopened_child_list)->tqh_first = ((void*)0); ( &_dlopened_child_list)->tqh_last = &(&_dlopened_child_list )->tqh_first; } while (0); |
500 | |
501 | exe_obj = NULL((void*)0); |
502 | _dl_loading_object = NULL((void*)0); |
503 | |
504 | minva = ELF_NO_ADDR((__uint64_t) ~0); |
505 | maxva = exe_loff = exec_end = 0; |
506 | |
507 | /* |
508 | * Examine the user application and set up object information. |
509 | */ |
510 | phdp = (Elf_PhdrElf64_Phdr *)dl_data[AUX_phdr]; |
511 | for (loop = 0; loop < dl_data[AUX_phnum]; loop++) { |
512 | switch (phdp->p_type) { |
513 | case PT_PHDR6: |
514 | exe_loff = (Elf_AddrElf64_Addr)dl_data[AUX_phdr] - phdp->p_vaddr; |
515 | us += exe_loff; |
516 | DL_DEB(("exe load offset: 0x%lx\n", exe_loff))do { if (_dl_debug) _dl_printf ("exe load offset: 0x%lx\n", exe_loff ) ; } while (0); |
517 | break; |
518 | case PT_DYNAMIC2: |
519 | minva = TRUNC_PG(minva)((minva) & ~(align)); |
520 | maxva = ROUND_PG(maxva)(((maxva) + align) & ~(align)); |
521 | exe_obj = _dl_finalize_object(argv[0] ? argv[0] : "", |
522 | (Elf_DynElf64_Dyn *)(phdp->p_vaddr + exe_loff), |
523 | (Elf_PhdrElf64_Phdr *)dl_data[AUX_phdr], |
524 | dl_data[AUX_phnum], OBJTYPE_EXE2, minva + exe_loff, |
525 | exe_loff); |
526 | _dl_add_object(exe_obj); |
527 | break; |
528 | case PT_INTERP3: |
529 | us += phdp->p_vaddr; |
530 | break; |
531 | case PT_LOAD1: |
532 | if (phdp->p_vaddr < minva) |
533 | minva = phdp->p_vaddr; |
534 | if (phdp->p_vaddr > maxva) |
535 | maxva = phdp->p_vaddr + phdp->p_memsz; |
536 | |
537 | next_load = _dl_calloc(1, sizeof(struct load_list)); |
538 | if (next_load == NULL((void*)0)) |
539 | _dl_oom(); |
540 | next_load->next = load_list; |
541 | load_list = next_load; |
542 | next_load->start = (char *)TRUNC_PG(phdp->p_vaddr)((phdp->p_vaddr) & ~(align)) + exe_loff; |
543 | next_load->size = (phdp->p_vaddr & align) + phdp->p_filesz; |
544 | next_load->prot = PFLAGS(phdp->p_flags)((((phdp->p_flags) & 0x4) ? 0x01 : 0) | (((phdp->p_flags ) & 0x2) ? 0x02 : 0) | (((phdp->p_flags) & 0x1) ? 0x04 : 0)); |
545 | cur_exec_end = (Elf_AddrElf64_Addr)next_load->start + next_load->size; |
546 | if ((next_load->prot & PROT_EXEC0x04) != 0 && |
547 | cur_exec_end > exec_end) |
548 | exec_end = cur_exec_end; |
549 | break; |
550 | case PT_TLS7: |
551 | if (phdp->p_filesz > phdp->p_memsz) |
552 | _dl_die("invalid tls data"); |
553 | ptls = phdp; |
554 | break; |
555 | case PT_GNU_RELRO0x6474e552: |
556 | relro_addr = phdp->p_vaddr + exe_loff; |
557 | relro_size = phdp->p_memsz; |
558 | break; |
559 | } |
560 | phdp++; |
561 | } |
562 | exe_obj->load_list = load_list; |
563 | exe_obj->obj_flags |= DF_1_GLOBAL0x00000002; |
564 | exe_obj->load_size = maxva - minva; |
565 | exe_obj->relro_addr = relro_addr; |
566 | exe_obj->relro_size = relro_size; |
567 | _dl_set_sod(exe_obj->load_name, &exe_obj->sod); |
568 | |
569 | #ifdef __i386__ |
570 | if (exec_end > I386_MAX_EXE_ADDR) |
571 | _dl_exec_hint = (void *)ROUND_PG(exec_end-I386_MAX_EXE_ADDR)(((exec_end-I386_MAX_EXE_ADDR) + align) & ~(align)); |
572 | DL_DEB(("_dl_exec_hint: 0x%lx\n", _dl_exec_hint))do { if (_dl_debug) _dl_printf ("_dl_exec_hint: 0x%lx\n", _dl_exec_hint ) ; } while (0); |
573 | #endif |
574 | |
575 | /* TLS bits in the base executable */ |
576 | if (ptls != NULL((void*)0) && ptls->p_memsz) |
577 | _dl_set_tls(exe_obj, ptls, exe_loff, NULL((void*)0)); |
578 | |
579 | n = _dl_malloc(sizeof *n); |
580 | if (n == NULL((void*)0)) |
581 | _dl_oom(); |
582 | n->data = exe_obj; |
583 | TAILQ_INSERT_TAIL(&_dlopened_child_list, n, next_sib)do { (n)->next_sib.tqe_next = ((void*)0); (n)->next_sib .tqe_prev = (&_dlopened_child_list)->tqh_last; *(& _dlopened_child_list)->tqh_last = (n); (&_dlopened_child_list )->tqh_last = &(n)->next_sib.tqe_next; } while (0); |
584 | exe_obj->opencount++; |
585 | |
586 | if (_dl_preload != NULL((void*)0)) |
587 | _dl_dopreload(_dl_preload); |
588 | |
589 | _dl_load_dep_libs(exe_obj, exe_obj->obj_flags, 1); |
590 | |
591 | /* |
592 | * Now add the dynamic loader itself last in the object list |
593 | * so we can use the _dl_ code when serving dl.... calls. |
594 | * Intentionally left off the exe child_vec. |
595 | */ |
596 | dynp = (Elf_DynElf64_Dyn *)((void *)_DYNAMIC); |
597 | ehdr = (Elf_EhdrElf64_Ehdr *)dl_data[AUX_base]; |
598 | dyn_obj = _dl_finalize_object(us, dynp, |
599 | (Elf_PhdrElf64_Phdr *)((char *)dl_data[AUX_base] + ehdr->e_phoff), |
600 | ehdr->e_phnum, OBJTYPE_LDR1, dl_data[AUX_base], dyn_loff); |
601 | _dl_add_object(dyn_obj); |
602 | |
603 | dyn_obj->refcount++; |
604 | _dl_link_grpsym(dyn_obj); |
605 | |
606 | dyn_obj->status |= STAT_RELOC_DONE0x001; |
607 | _dl_set_sod(dyn_obj->load_name, &dyn_obj->sod); |
608 | |
609 | /* calculate the offsets for static TLS allocations */ |
610 | _dl_allocate_tls_offsets(); |
611 | |
612 | /* |
613 | * Make something to help gdb when poking around in the code. |
614 | * Do this poking at the .dynamic section now, before relocation |
615 | * renders it read-only |
616 | */ |
617 | map_link = NULL((void*)0); |
618 | #ifdef __mips__ |
619 | if (exe_obj->Dyn.info[DT_MIPS_RLD_MAP - DT_LOPROC0x70000000 + DT_NUM(36 + 1)] != 0) |
620 | map_link = (struct r_debug **)(exe_obj->Dyn.info[ |
621 | DT_MIPS_RLD_MAP - DT_LOPROC0x70000000 + DT_NUM(36 + 1)] + exe_loff); |
622 | #endif |
623 | if (map_link == NULL((void*)0)) { |
624 | for (dynp = exe_obj->load_dyn; dynp->d_tag; dynp++) { |
625 | if (dynp->d_tag == DT_DEBUG21) { |
626 | map_link = (struct r_debug **)&dynp->d_un.d_ptr; |
627 | break; |
628 | } |
629 | } |
630 | if (dynp->d_tag != DT_DEBUG21) |
631 | DL_DEB(("failed to mark DTDEBUG\n"))do { if (_dl_debug) _dl_printf ("failed to mark DTDEBUG\n") ; } while (0); |
632 | } |
633 | if (map_link) { |
634 | debug_map = _dl_malloc(sizeof(*debug_map)); |
635 | if (debug_map == NULL((void*)0)) |
636 | _dl_oom(); |
637 | debug_map->r_version = 1; |
638 | debug_map->r_map = (struct link_map *)_dl_objects; |
639 | debug_map->r_brk = (Elf_AddrElf64_Addr)_dl_debug_state; |
640 | debug_map->r_state = RT_CONSISTENT; |
641 | debug_map->r_ldbase = dyn_loff; |
642 | _dl_debug_map = debug_map; |
643 | #ifdef __mips__ |
644 | relro_addr = exe_obj->relro_addr; |
645 | if (dynp->d_tag == DT_DEBUG21 && |
646 | ((Elf_AddrElf64_Addr)map_link + sizeof(*map_link) <= relro_addr || |
647 | (Elf_AddrElf64_Addr)map_link >= relro_addr + exe_obj->relro_size)) { |
648 | _dl_mprotect(map_link, sizeof(*map_link), |
649 | PROT_READ0x01|PROT_WRITE0x02); |
650 | *map_link = _dl_debug_map; |
651 | _dl_mprotect(map_link, sizeof(*map_link), |
652 | PROT_READ0x01|PROT_EXEC0x04); |
653 | } else |
654 | #endif |
655 | *map_link = _dl_debug_map; |
656 | } |
657 | |
658 | |
659 | /* |
660 | * Everything should be in place now for doing the relocation |
661 | * and binding. Call _dl_rtld to do the job. Fingers crossed. |
662 | */ |
663 | |
664 | failed = 0; |
665 | if (!_dl_traceld) |
666 | failed = _dl_rtld(_dl_objects); |
667 | |
668 | if (_dl_debug || _dl_traceld) { |
669 | if (_dl_traceld) |
670 | _dl_pledge("stdio rpath", NULL((void*)0)); |
671 | _dl_show_objects(); |
672 | } |
673 | |
674 | DL_DEB(("dynamic loading done, %s.\n",do { if (_dl_debug) _dl_printf ("dynamic loading done, %s.\n" , (failed == 0) ? "success":"failed") ; } while (0) |
675 | (failed == 0) ? "success":"failed"))do { if (_dl_debug) _dl_printf ("dynamic loading done, %s.\n" , (failed == 0) ? "success":"failed") ; } while (0); |
676 | |
677 | if (failed != 0) |
678 | _dl_die("relocation failed"); |
679 | |
680 | if (_dl_traceld) |
681 | _dl_exit(0); |
682 | |
683 | _dl_loading_object = NULL((void*)0); |
684 | |
685 | /* set up the TIB for the initial thread */ |
686 | _dl_allocate_first_tib(); |
687 | |
688 | _dl_fixup_user_env(); |
689 | |
690 | _dl_debug_state(); |
691 | |
692 | /* |
693 | * Do not run init code if run from ldd. |
694 | */ |
695 | if (_dl_objects->next != NULL((void*)0)) { |
696 | _dl_call_preinit(_dl_objects); |
697 | _dl_call_init(_dl_objects); |
698 | } |
699 | |
700 | DL_DEB(("entry point: 0x%lx\n", dl_data[AUX_entry]))do { if (_dl_debug) _dl_printf ("entry point: 0x%lx\n", dl_data [AUX_entry]) ; } while (0); |
701 | |
702 | /* |
703 | * Return the entry point. |
704 | */ |
705 | return(dl_data[AUX_entry]); |
706 | } |
707 | |
708 | int |
709 | _dl_rtld(elf_object_t *object) |
710 | { |
711 | struct load_list *llist; |
712 | int fails = 0; |
713 | |
714 | if (object->next) |
715 | fails += _dl_rtld(object->next); |
Value stored to 'fails' is never read | |
716 | |
717 | if (object->status & STAT_RELOC_DONE0x001) |
718 | return 0; |
719 | |
720 | /* |
721 | * Do relocation information first, then GOT. |
722 | */ |
723 | unprotect_if_textrel(object); |
724 | _dl_rreloc(object); |
725 | fails =_dl_md_reloc(object, DT_REL17, DT_RELSZ18); |
726 | fails += _dl_md_reloc(object, DT_RELA7, DT_RELASZ8); |
727 | reprotect_if_textrel(object); |
728 | |
729 | /* |
730 | * We do lazy resolution by default, doing eager resolution if |
731 | * - the object requests it with -znow, OR |
732 | * - LD_BIND_NOW is set and this object isn't being ltraced |
733 | * |
734 | * Note that -znow disables ltrace for the object: on at least |
735 | * amd64 'ld' doesn't generate the trampoline for lazy relocation |
736 | * when -znow is used. |
737 | */ |
738 | fails += _dl_md_reloc_got(object, !(object->obj_flags & DF_1_NOW0x00000001) && |
739 | !(_dl_bindnow && !object->traced)); |
740 | |
741 | /* |
742 | * Look for W&X segments and make them read-only. |
743 | */ |
744 | for (llist = object->load_list; llist != NULL((void*)0); llist = llist->next) { |
745 | if ((llist->prot & PROT_WRITE0x02) && (llist->prot & PROT_EXEC0x04)) { |
746 | _dl_mprotect(llist->start, llist->size, |
747 | llist->prot & ~PROT_WRITE0x02); |
748 | } |
749 | } |
750 | |
751 | if (fails == 0) |
752 | object->status |= STAT_RELOC_DONE0x001; |
753 | |
754 | return (fails); |
755 | } |
756 | |
757 | void |
758 | _dl_call_preinit(elf_object_t *object) |
759 | { |
760 | if (object->dynDyn.u.preinit_array) { |
761 | int num = object->dynDyn.u.preinit_arraysz / sizeof(Elf_AddrElf64_Addr); |
762 | int i; |
763 | |
764 | DL_DEB(("doing preinitarray obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing preinitarray obj %p @%p: [%s]\n" , object, object->Dyn.u.preinit_array, object->load_name ) ; } while (0) |
765 | object, object->dyn.preinit_array, object->load_name))do { if (_dl_debug) _dl_printf ("doing preinitarray obj %p @%p: [%s]\n" , object, object->Dyn.u.preinit_array, object->load_name ) ; } while (0); |
766 | for (i = 0; i < num; i++) |
767 | (*object->dynDyn.u.preinit_array[i])(_dl_argc, _dl_argv, |
768 | environ, &_dl_cb_cb); |
769 | } |
770 | } |
771 | |
772 | void |
773 | _dl_call_init(elf_object_t *object) |
774 | { |
775 | _dl_call_init_recurse(object, 1); |
776 | _dl_call_init_recurse(object, 0); |
777 | } |
778 | |
779 | static void |
780 | _dl_relro(elf_object_t *object) |
781 | { |
782 | /* |
783 | * Handle GNU_RELRO |
784 | */ |
785 | if (object->relro_addr != 0 && object->relro_size != 0) { |
786 | Elf_AddrElf64_Addr addr = object->relro_addr; |
787 | |
788 | DL_DEB(("protect RELRO [0x%lx,0x%lx) in %s\n",do { if (_dl_debug) _dl_printf ("protect RELRO [0x%lx,0x%lx) in %s\n" , addr, addr + object->relro_size, object->load_name) ; } while (0) |
789 | addr, addr + object->relro_size, object->load_name))do { if (_dl_debug) _dl_printf ("protect RELRO [0x%lx,0x%lx) in %s\n" , addr, addr + object->relro_size, object->load_name) ; } while (0); |
790 | _dl_mprotect((void *)addr, object->relro_size, PROT_READ0x01); |
791 | } |
792 | } |
793 | |
794 | void |
795 | _dl_call_init_recurse(elf_object_t *object, int initfirst) |
796 | { |
797 | struct object_vector vec; |
798 | int visited_flag = initfirst ? STAT_VISIT_INITFIRST0x100 : STAT_VISIT_INIT0x200; |
799 | int i; |
800 | |
801 | object->status |= visited_flag; |
802 | |
803 | for (vec = object->child_vec, i = 0; i < vec.len; i++) { |
804 | if (vec.vec[i]->status & visited_flag) |
805 | continue; |
806 | _dl_call_init_recurse(vec.vec[i], initfirst); |
807 | } |
808 | |
809 | if (object->status & STAT_INIT_DONE0x004) |
810 | return; |
811 | |
812 | if (initfirst && (object->obj_flags & DF_1_INITFIRST0x00000020) == 0) |
813 | return; |
814 | |
815 | if (!initfirst) |
816 | _dl_relro(object); |
817 | |
818 | if (object->dynDyn.u.init) { |
819 | DL_DEB(("doing ctors obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing ctors obj %p @%p: [%s]\n" , object, object->Dyn.u.init, object->load_name) ; } while (0) |
820 | object, object->dyn.init, object->load_name))do { if (_dl_debug) _dl_printf ("doing ctors obj %p @%p: [%s]\n" , object, object->Dyn.u.init, object->load_name) ; } while (0); |
821 | (*object->dynDyn.u.init)(); |
822 | } |
823 | |
824 | if (object->dynDyn.u.init_array) { |
825 | int num = object->dynDyn.u.init_arraysz / sizeof(Elf_AddrElf64_Addr); |
826 | int i; |
827 | |
828 | DL_DEB(("doing initarray obj %p @%p: [%s]\n",do { if (_dl_debug) _dl_printf ("doing initarray obj %p @%p: [%s]\n" , object, object->Dyn.u.init_array, object->load_name) ; } while (0) |
829 | object, object->dyn.init_array, object->load_name))do { if (_dl_debug) _dl_printf ("doing initarray obj %p @%p: [%s]\n" , object, object->Dyn.u.init_array, object->load_name) ; } while (0); |
830 | for (i = 0; i < num; i++) |
831 | (*object->dynDyn.u.init_array[i])(_dl_argc, _dl_argv, |
832 | environ, &_dl_cb_cb); |
833 | } |
834 | |
835 | if (initfirst) |
836 | _dl_relro(object); |
837 | |
838 | object->status |= STAT_INIT_DONE0x004; |
839 | } |
840 | |
841 | char * |
842 | _dl_getenv(const char *var, char **env) |
843 | { |
844 | const char *ep; |
845 | |
846 | while ((ep = *env++)) { |
847 | const char *vp = var; |
848 | |
849 | while (*vp && *vp == *ep) { |
850 | vp++; |
851 | ep++; |
852 | } |
853 | if (*vp == '\0' && *ep++ == '=') |
854 | return((char *)ep); |
855 | } |
856 | return(NULL((void*)0)); |
857 | } |
858 | |
859 | void |
860 | _dl_unsetenv(const char *var, char **env) |
861 | { |
862 | char *ep; |
863 | |
864 | while ((ep = *env)) { |
865 | const char *vp = var; |
866 | |
867 | while (*vp && *vp == *ep) { |
868 | vp++; |
869 | ep++; |
870 | } |
871 | if (*vp == '\0' && *ep++ == '=') { |
872 | char **P; |
873 | |
874 | for (P = env;; ++P) |
875 | if (!(*P = *(P + 1))) |
876 | break; |
877 | } else |
878 | env++; |
879 | } |
880 | } |
881 | |
882 | static inline void |
883 | fixup_sym(struct elf_object *dummy_obj, const char *name, void *addr) |
884 | { |
885 | struct sym_res sr; |
886 | |
887 | sr = _dl_find_symbol(name, SYM_SEARCH_ALL0x00|SYM_NOWARNNOTFOUND0x00|SYM_PLT0x20, |
888 | NULL((void*)0), dummy_obj); |
889 | if (sr.sym != NULL((void*)0)) { |
890 | void *p = (void *)(sr.sym->st_value + sr.obj->obj_base); |
891 | if (p != addr) { |
892 | DL_DEB(("setting %s %p@%s[%p] from %p\n", name,do { if (_dl_debug) _dl_printf ("setting %s %p@%s[%p] from %p\n" , name, p, sr.obj->load_name, (void *)sr.obj, addr) ; } while (0) |
893 | p, sr.obj->load_name, (void *)sr.obj, addr))do { if (_dl_debug) _dl_printf ("setting %s %p@%s[%p] from %p\n" , name, p, sr.obj->load_name, (void *)sr.obj, addr) ; } while (0); |
894 | *(void **)p = *(void **)addr; |
895 | } |
896 | } |
897 | } |
898 | |
899 | /* |
900 | * _dl_fixup_user_env() |
901 | * |
902 | * Set the user environment so that programs can use the environment |
903 | * while running constructors. Specifically, MALLOC_OPTIONS= for malloc() |
904 | */ |
905 | void |
906 | _dl_fixup_user_env(void) |
907 | { |
908 | struct elf_object dummy_obj; |
909 | |
910 | dummy_obj.dynDyn.u.symbolic = 0; |
911 | dummy_obj.load_name = "ld.so"; |
912 | fixup_sym(&dummy_obj, "environ", &environ); |
913 | fixup_sym(&dummy_obj, "__progname", &__progname); |
914 | } |
915 | |
916 | const void * |
917 | _dl_cb_cb(int version) |
918 | { |
919 | DL_DEB(("version %d callbacks requested\n", version))do { if (_dl_debug) _dl_printf ("version %d callbacks requested\n" , version) ; } while (0); |
920 | if (version == 0) |
921 | return &callbacks_0; |
922 | return NULL((void*)0); |
923 | } |
924 | |
925 | static inline void |
926 | unprotect_if_textrel(elf_object_t *object) |
927 | { |
928 | struct load_list *ll; |
929 | |
930 | if (__predict_false(object->dyn.textrel == 1)__builtin_expect(((object->Dyn.u.textrel == 1) != 0), 0)) { |
931 | for (ll = object->load_list; ll != NULL((void*)0); ll = ll->next) { |
932 | if ((ll->prot & PROT_WRITE0x02) == 0) |
933 | _dl_mprotect(ll->start, ll->size, |
934 | PROT_READ0x01 | PROT_WRITE0x02); |
935 | } |
936 | } |
937 | } |
938 | |
939 | static inline void |
940 | reprotect_if_textrel(elf_object_t *object) |
941 | { |
942 | struct load_list *ll; |
943 | |
944 | if (__predict_false(object->dyn.textrel == 1)__builtin_expect(((object->Dyn.u.textrel == 1) != 0), 0)) { |
945 | for (ll = object->load_list; ll != NULL((void*)0); ll = ll->next) { |
946 | if ((ll->prot & PROT_WRITE0x02) == 0) |
947 | _dl_mprotect(ll->start, ll->size, ll->prot); |
948 | } |
949 | } |
950 | } |
951 | |
952 | static void |
953 | _dl_rreloc(elf_object_t *object) |
954 | { |
955 | const Elf_RelrElf64_Relr *reloc, *rend; |
956 | Elf_AddrElf64_Addr loff = object->obj_base; |
957 | |
958 | reloc = object->dynDyn.u.relr; |
959 | rend = (const Elf_RelrElf64_Relr *)((char *)reloc + object->dynDyn.u.relrsz); |
960 | |
961 | while (reloc < rend) { |
962 | Elf_AddrElf64_Addr *where; |
963 | |
964 | where = (Elf_AddrElf64_Addr *)(*reloc + loff); |
965 | *where++ += loff; |
966 | |
967 | for (reloc++; reloc < rend && (*reloc & 1); reloc++) { |
968 | Elf_AddrElf64_Addr bits = *reloc >> 1; |
969 | |
970 | Elf_AddrElf64_Addr *here = where; |
971 | while (bits != 0) { |
972 | if (bits & 1) { |
973 | *here += loff; |
974 | } |
975 | bits >>= 1; |
976 | here++; |
977 | } |
978 | where += (8 * sizeof *reloc) - 1; |
979 | } |
980 | } |
981 | } |
982 |