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