| 1 | /* Copyright (C) 1998-2020 Free Software Foundation, Inc. | 
|---|
| 2 | This file is part of the GNU C Library. | 
|---|
| 3 |  | 
|---|
| 4 | The GNU C Library is free software; you can redistribute it and/or | 
|---|
| 5 | modify it under the terms of the GNU Lesser General Public | 
|---|
| 6 | License as published by the Free Software Foundation; either | 
|---|
| 7 | version 2.1 of the License, or (at your option) any later version. | 
|---|
| 8 |  | 
|---|
| 9 | The GNU C Library is distributed in the hope that it will be useful, | 
|---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 12 | Lesser General Public License for more details. | 
|---|
| 13 |  | 
|---|
| 14 | You should have received a copy of the GNU Lesser General Public | 
|---|
| 15 | License along with the GNU C Library; if not, see | 
|---|
| 16 | <https://www.gnu.org/licenses/>.  */ | 
|---|
| 17 |  | 
|---|
| 18 | #include <assert.h> | 
|---|
| 19 | #include <stdlib.h> | 
|---|
| 20 | #include <stdio.h> | 
|---|
| 21 | #include <unistd.h> | 
|---|
| 22 | #include <ldsodefs.h> | 
|---|
| 23 | #include <exit-thread.h> | 
|---|
| 24 | #include <libc-internal.h> | 
|---|
| 25 | #include <elf/libc-early-init.h> | 
|---|
| 26 | #include <stdbool.h> | 
|---|
| 27 |  | 
|---|
| 28 | #include <elf/dl-tunables.h> | 
|---|
| 29 |  | 
|---|
| 30 | extern void __libc_init_first (int argc, char **argv, char **envp); | 
|---|
| 31 |  | 
|---|
| 32 | #include <tls.h> | 
|---|
| 33 | #ifndef SHARED | 
|---|
| 34 | # include <dl-osinfo.h> | 
|---|
| 35 | # ifndef THREAD_SET_STACK_GUARD | 
|---|
| 36 | /* Only exported for architectures that don't store the stack guard canary | 
|---|
| 37 | in thread local area.  */ | 
|---|
| 38 | uintptr_t __stack_chk_guard attribute_relro; | 
|---|
| 39 | # endif | 
|---|
| 40 | # ifndef  THREAD_SET_POINTER_GUARD | 
|---|
| 41 | /* Only exported for architectures that don't store the pointer guard | 
|---|
| 42 | value in thread local area.  */ | 
|---|
| 43 | uintptr_t __pointer_chk_guard_local | 
|---|
| 44 | attribute_relro attribute_hidden __attribute__ ((nocommon)); | 
|---|
| 45 | # endif | 
|---|
| 46 | #endif | 
|---|
| 47 |  | 
|---|
| 48 | #ifdef HAVE_PTR_NTHREADS | 
|---|
| 49 | /* We need atomic operations.  */ | 
|---|
| 50 | # include <atomic.h> | 
|---|
| 51 | #endif | 
|---|
| 52 |  | 
|---|
| 53 |  | 
|---|
| 54 | #ifndef SHARED | 
|---|
| 55 | # include <link.h> | 
|---|
| 56 | # include <dl-irel.h> | 
|---|
| 57 |  | 
|---|
| 58 | # ifdef ELF_MACHINE_IRELA | 
|---|
| 59 | #  define IREL_T	ElfW(Rela) | 
|---|
| 60 | #  define IPLT_START	__rela_iplt_start | 
|---|
| 61 | #  define IPLT_END	__rela_iplt_end | 
|---|
| 62 | #  define IREL		elf_irela | 
|---|
| 63 | # elif defined ELF_MACHINE_IREL | 
|---|
| 64 | #  define IREL_T	ElfW(Rel) | 
|---|
| 65 | #  define IPLT_START	__rel_iplt_start | 
|---|
| 66 | #  define IPLT_END	__rel_iplt_end | 
|---|
| 67 | #  define IREL		elf_irel | 
|---|
| 68 | # endif | 
|---|
| 69 |  | 
|---|
| 70 | static void | 
|---|
| 71 | apply_irel (void) | 
|---|
| 72 | { | 
|---|
| 73 | # ifdef IREL | 
|---|
| 74 | /* We use weak references for these so that we'll still work with a linker | 
|---|
| 75 | that doesn't define them.  Such a linker doesn't support IFUNC at all | 
|---|
| 76 | and so uses won't work, but a statically-linked program that doesn't | 
|---|
| 77 | use any IFUNC symbols won't have a problem.  */ | 
|---|
| 78 | extern const IREL_T IPLT_START[] __attribute__ ((weak)); | 
|---|
| 79 | extern const IREL_T IPLT_END[] __attribute__ ((weak)); | 
|---|
| 80 | for (const IREL_T *ipltent = IPLT_START; ipltent < IPLT_END; ++ipltent) | 
|---|
| 81 | IREL (ipltent); | 
|---|
| 82 | # endif | 
|---|
| 83 | } | 
|---|
| 84 | #endif | 
|---|
| 85 |  | 
|---|
| 86 |  | 
|---|
| 87 | #ifdef LIBC_START_MAIN | 
|---|
| 88 | # ifdef LIBC_START_DISABLE_INLINE | 
|---|
| 89 | #  define STATIC static | 
|---|
| 90 | # else | 
|---|
| 91 | #  define STATIC static inline __attribute__ ((always_inline)) | 
|---|
| 92 | # endif | 
|---|
| 93 | #else | 
|---|
| 94 | # define STATIC | 
|---|
| 95 | # define LIBC_START_MAIN __libc_start_main | 
|---|
| 96 | #endif | 
|---|
| 97 |  | 
|---|
| 98 | #ifdef MAIN_AUXVEC_ARG | 
|---|
| 99 | /* main gets passed a pointer to the auxiliary.  */ | 
|---|
| 100 | # define MAIN_AUXVEC_DECL	, void * | 
|---|
| 101 | # define MAIN_AUXVEC_PARAM	, auxvec | 
|---|
| 102 | #else | 
|---|
| 103 | # define MAIN_AUXVEC_DECL | 
|---|
| 104 | # define MAIN_AUXVEC_PARAM | 
|---|
| 105 | #endif | 
|---|
| 106 |  | 
|---|
| 107 | #ifndef ARCH_INIT_CPU_FEATURES | 
|---|
| 108 | # define ARCH_INIT_CPU_FEATURES() | 
|---|
| 109 | #endif | 
|---|
| 110 |  | 
|---|
| 111 | #include <libc-start.h> | 
|---|
| 112 |  | 
|---|
| 113 | STATIC int LIBC_START_MAIN (int (*main) (int, char **, char ** | 
|---|
| 114 | MAIN_AUXVEC_DECL), | 
|---|
| 115 | int argc, | 
|---|
| 116 | char **argv, | 
|---|
| 117 | #ifdef LIBC_START_MAIN_AUXVEC_ARG | 
|---|
| 118 | ElfW(auxv_t) *auxvec, | 
|---|
| 119 | #endif | 
|---|
| 120 | __typeof (main) init, | 
|---|
| 121 | void (*fini) (void), | 
|---|
| 122 | void (*rtld_fini) (void), | 
|---|
| 123 | void *stack_end) | 
|---|
| 124 | __attribute__ ((noreturn)); | 
|---|
| 125 |  | 
|---|
| 126 |  | 
|---|
| 127 | /* Note: the fini parameter is ignored here for shared library.  It | 
|---|
| 128 | is registered with __cxa_atexit.  This had the disadvantage that | 
|---|
| 129 | finalizers were called in more than one place.  */ | 
|---|
| 130 | STATIC int | 
|---|
| 131 | LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), | 
|---|
| 132 | int argc, char **argv, | 
|---|
| 133 | #ifdef LIBC_START_MAIN_AUXVEC_ARG | 
|---|
| 134 | ElfW(auxv_t) *auxvec, | 
|---|
| 135 | #endif | 
|---|
| 136 | __typeof (main) init, | 
|---|
| 137 | void (*fini) (void), | 
|---|
| 138 | void (*rtld_fini) (void), void *stack_end) | 
|---|
| 139 | { | 
|---|
| 140 | /* Result of the 'main' function.  */ | 
|---|
| 141 | int result; | 
|---|
| 142 |  | 
|---|
| 143 | __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up; | 
|---|
| 144 |  | 
|---|
| 145 | #ifndef SHARED | 
|---|
| 146 | _dl_relocate_static_pie (); | 
|---|
| 147 |  | 
|---|
| 148 | char **ev = &argv[argc + 1]; | 
|---|
| 149 |  | 
|---|
| 150 | __environ = ev; | 
|---|
| 151 |  | 
|---|
| 152 | /* Store the lowest stack address.  This is done in ld.so if this is | 
|---|
| 153 | the code for the DSO.  */ | 
|---|
| 154 | __libc_stack_end = stack_end; | 
|---|
| 155 |  | 
|---|
| 156 | # ifdef HAVE_AUX_VECTOR | 
|---|
| 157 | /* First process the auxiliary vector since we need to find the | 
|---|
| 158 | program header to locate an eventually present PT_TLS entry.  */ | 
|---|
| 159 | #  ifndef LIBC_START_MAIN_AUXVEC_ARG | 
|---|
| 160 | ElfW(auxv_t) *auxvec; | 
|---|
| 161 | { | 
|---|
| 162 | char **evp = ev; | 
|---|
| 163 | while (*evp++ != NULL) | 
|---|
| 164 | ; | 
|---|
| 165 | auxvec = (ElfW(auxv_t) *) evp; | 
|---|
| 166 | } | 
|---|
| 167 | #  endif | 
|---|
| 168 | _dl_aux_init (auxvec); | 
|---|
| 169 | if (GL(dl_phdr) == NULL) | 
|---|
| 170 | # endif | 
|---|
| 171 | { | 
|---|
| 172 | /* Starting from binutils-2.23, the linker will define the | 
|---|
| 173 | magic symbol __ehdr_start to point to our own ELF header | 
|---|
| 174 | if it is visible in a segment that also includes the phdrs. | 
|---|
| 175 | So we can set up _dl_phdr and _dl_phnum even without any | 
|---|
| 176 | information from auxv.  */ | 
|---|
| 177 |  | 
|---|
| 178 | extern const ElfW(Ehdr) __ehdr_start | 
|---|
| 179 | __attribute__ ((weak, visibility ( "hidden"))); | 
|---|
| 180 | if (&__ehdr_start != NULL) | 
|---|
| 181 | { | 
|---|
| 182 | assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); | 
|---|
| 183 | GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff; | 
|---|
| 184 | GL(dl_phnum) = __ehdr_start.e_phnum; | 
|---|
| 185 | } | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | /* Initialize very early so that tunables can use it.  */ | 
|---|
| 189 | __libc_init_secure (); | 
|---|
| 190 |  | 
|---|
| 191 | __tunables_init (__environ); | 
|---|
| 192 |  | 
|---|
| 193 | ARCH_INIT_CPU_FEATURES (); | 
|---|
| 194 |  | 
|---|
| 195 | /* Perform IREL{,A} relocations.  */ | 
|---|
| 196 | ARCH_SETUP_IREL (); | 
|---|
| 197 |  | 
|---|
| 198 | /* The stack guard goes into the TCB, so initialize it early.  */ | 
|---|
| 199 | ARCH_SETUP_TLS (); | 
|---|
| 200 |  | 
|---|
| 201 | /* In some architectures, IREL{,A} relocations happen after TLS setup in | 
|---|
| 202 | order to let IFUNC resolvers benefit from TCB information, e.g. powerpc's | 
|---|
| 203 | hwcap and platform fields available in the TCB.  */ | 
|---|
| 204 | ARCH_APPLY_IREL (); | 
|---|
| 205 |  | 
|---|
| 206 | /* Set up the stack checker's canary.  */ | 
|---|
| 207 | uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random); | 
|---|
| 208 | # ifdef THREAD_SET_STACK_GUARD | 
|---|
| 209 | THREAD_SET_STACK_GUARD (stack_chk_guard); | 
|---|
| 210 | # else | 
|---|
| 211 | __stack_chk_guard = stack_chk_guard; | 
|---|
| 212 | # endif | 
|---|
| 213 |  | 
|---|
| 214 | # ifdef DL_SYSDEP_OSCHECK | 
|---|
| 215 | if (!__libc_multiple_libcs) | 
|---|
| 216 | { | 
|---|
| 217 | /* This needs to run to initiliaze _dl_osversion before TLS | 
|---|
| 218 | setup might check it.  */ | 
|---|
| 219 | DL_SYSDEP_OSCHECK (__libc_fatal); | 
|---|
| 220 | } | 
|---|
| 221 | # endif | 
|---|
| 222 |  | 
|---|
| 223 | /* Initialize libpthread if linked in.  */ | 
|---|
| 224 | if (__pthread_initialize_minimal != NULL) | 
|---|
| 225 | __pthread_initialize_minimal (); | 
|---|
| 226 |  | 
|---|
| 227 | /* Set up the pointer guard value.  */ | 
|---|
| 228 | uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random, | 
|---|
| 229 | stack_chk_guard); | 
|---|
| 230 | # ifdef THREAD_SET_POINTER_GUARD | 
|---|
| 231 | THREAD_SET_POINTER_GUARD (pointer_chk_guard); | 
|---|
| 232 | # else | 
|---|
| 233 | __pointer_chk_guard_local = pointer_chk_guard; | 
|---|
| 234 | # endif | 
|---|
| 235 |  | 
|---|
| 236 | #endif /* !SHARED  */ | 
|---|
| 237 |  | 
|---|
| 238 | /* Register the destructor of the dynamic linker if there is any.  */ | 
|---|
| 239 | if (__glibc_likely (rtld_fini != NULL)) | 
|---|
| 240 | __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL); | 
|---|
| 241 |  | 
|---|
| 242 | #ifndef SHARED | 
|---|
| 243 | /* Perform early initialization.  In the shared case, this function | 
|---|
| 244 | is called from the dynamic loader as early as possible.  */ | 
|---|
| 245 | __libc_early_init (true); | 
|---|
| 246 |  | 
|---|
| 247 | /* Call the initializer of the libc.  This is only needed here if we | 
|---|
| 248 | are compiling for the static library in which case we haven't | 
|---|
| 249 | run the constructors in `_dl_start_user'.  */ | 
|---|
| 250 | __libc_init_first (argc, argv, __environ); | 
|---|
| 251 |  | 
|---|
| 252 | /* Register the destructor of the program, if any.  */ | 
|---|
| 253 | if (fini) | 
|---|
| 254 | __cxa_atexit ((void (*) (void *)) fini, NULL, NULL); | 
|---|
| 255 |  | 
|---|
| 256 | /* Some security at this point.  Prevent starting a SUID binary where | 
|---|
| 257 | the standard file descriptors are not opened.  We have to do this | 
|---|
| 258 | only for statically linked applications since otherwise the dynamic | 
|---|
| 259 | loader did the work already.  */ | 
|---|
| 260 | if (__builtin_expect (__libc_enable_secure, 0)) | 
|---|
| 261 | __libc_check_standard_fds (); | 
|---|
| 262 | #endif | 
|---|
| 263 |  | 
|---|
| 264 | /* Call the initializer of the program, if any.  */ | 
|---|
| 265 | #ifdef SHARED | 
|---|
| 266 | if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) | 
|---|
| 267 | GLRO(dl_debug_printf) ( "\ninitialize program: %s\n\n", argv[0]); | 
|---|
| 268 | #endif | 
|---|
| 269 | if (init) | 
|---|
| 270 | (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM); | 
|---|
| 271 |  | 
|---|
| 272 | #ifdef SHARED | 
|---|
| 273 | /* Auditing checkpoint: we have a new object.  */ | 
|---|
| 274 | if (__glibc_unlikely (GLRO(dl_naudit) > 0)) | 
|---|
| 275 | { | 
|---|
| 276 | struct audit_ifaces *afct = GLRO(dl_audit); | 
|---|
| 277 | struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded; | 
|---|
| 278 | for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) | 
|---|
| 279 | { | 
|---|
| 280 | if (afct->preinit != NULL) | 
|---|
| 281 | afct->preinit (&link_map_audit_state (head, cnt)->cookie); | 
|---|
| 282 |  | 
|---|
| 283 | afct = afct->next; | 
|---|
| 284 | } | 
|---|
| 285 | } | 
|---|
| 286 | #endif | 
|---|
| 287 |  | 
|---|
| 288 | #ifdef SHARED | 
|---|
| 289 | if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) | 
|---|
| 290 | GLRO(dl_debug_printf) ( "\ntransferring control: %s\n\n", argv[0]); | 
|---|
| 291 | #endif | 
|---|
| 292 |  | 
|---|
| 293 | #ifndef SHARED | 
|---|
| 294 | _dl_debug_initialize (0, LM_ID_BASE); | 
|---|
| 295 | #endif | 
|---|
| 296 | #ifdef HAVE_CLEANUP_JMP_BUF | 
|---|
| 297 | /* Memory for the cancellation buffer.  */ | 
|---|
| 298 | struct pthread_unwind_buf unwind_buf; | 
|---|
| 299 |  | 
|---|
| 300 | int not_first_call; | 
|---|
| 301 | not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); | 
|---|
| 302 | if (__glibc_likely (! not_first_call)) | 
|---|
| 303 | { | 
|---|
| 304 | struct pthread *self = THREAD_SELF; | 
|---|
| 305 |  | 
|---|
| 306 | /* Store old info.  */ | 
|---|
| 307 | unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); | 
|---|
| 308 | unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); | 
|---|
| 309 |  | 
|---|
| 310 | /* Store the new cleanup handler info.  */ | 
|---|
| 311 | THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); | 
|---|
| 312 |  | 
|---|
| 313 | /* Run the program.  */ | 
|---|
| 314 | result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); | 
|---|
| 315 | } | 
|---|
| 316 | else | 
|---|
| 317 | { | 
|---|
| 318 | /* Remove the thread-local data.  */ | 
|---|
| 319 | # ifdef SHARED | 
|---|
| 320 | PTHFCT_CALL (ptr__nptl_deallocate_tsd, ()); | 
|---|
| 321 | # else | 
|---|
| 322 | extern void __nptl_deallocate_tsd (void) __attribute ((weak)); | 
|---|
| 323 | __nptl_deallocate_tsd (); | 
|---|
| 324 | # endif | 
|---|
| 325 |  | 
|---|
| 326 | /* One less thread.  Decrement the counter.  If it is zero we | 
|---|
| 327 | terminate the entire process.  */ | 
|---|
| 328 | result = 0; | 
|---|
| 329 | # ifdef SHARED | 
|---|
| 330 | unsigned int *ptr = __libc_pthread_functions.ptr_nthreads; | 
|---|
| 331 | #  ifdef PTR_DEMANGLE | 
|---|
| 332 | PTR_DEMANGLE (ptr); | 
|---|
| 333 | #  endif | 
|---|
| 334 | # else | 
|---|
| 335 | extern unsigned int __nptl_nthreads __attribute ((weak)); | 
|---|
| 336 | unsigned int *const ptr = &__nptl_nthreads; | 
|---|
| 337 | # endif | 
|---|
| 338 |  | 
|---|
| 339 | if (! atomic_decrement_and_test (ptr)) | 
|---|
| 340 | /* Not much left to do but to exit the thread, not the process.  */ | 
|---|
| 341 | __exit_thread (); | 
|---|
| 342 | } | 
|---|
| 343 | #else | 
|---|
| 344 | /* Nothing fancy, just call the function.  */ | 
|---|
| 345 | result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); | 
|---|
| 346 | #endif | 
|---|
| 347 |  | 
|---|
| 348 | exit (result); | 
|---|
| 349 | } | 
|---|
| 350 |  | 
|---|