File: | src/libexec/ld.so/loader.c |
Warning: | line 562, column 21 Access to field 'load_list' results in a dereference of a null pointer (loaded from variable 'exe_obj') |
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); | |||
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 |