| 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 |