mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-29 05:51:10 +00:00
7e31d16651
The 73fc4e28b9
refactor did not add the GL(dl_phdr) and
GL(dl_phnum) for static build, relying on the __ehdr_start symbol,
which is always added by the static linker, to get the correct values.
This is problematic in some ways:
- The segment may see its in-memory size differ from its in-file
size (or the binary may have holes). The Linux has fixed is to
provide concise values for both AT_PHDR and AT_PHNUM (commit
0da1d5002745c - "fs/binfmt_elf: Fix AT_PHDR for unusual ELF files")
- Some archs (alpha for instance) the hidden weak reference is not
correctly pulled by the static linker and __ehdr_start address
end up being 0, which makes GL(dl_phdr) and GL(dl_phnum) have both
invalid values (and triggering a segfault later on libc.so while
accessing TLS variables).
The safer fix is to just restore the previous behavior to setup
GL(dl_phdr) and GL(dl_phnum) for static based on kernel auxv. The
__ehdr_start fallback can also be simplified by not assuming weak
linkage (as for PIE).
The libc-static.c auxv init logic is moved to dl-support.c, since
the later is build without SHARED and then GLRO macro is defined
to access the variables directly.
The _dl_phdr is also assumed to be always non NULL, since an invalid
NULL values does not trigger TLS initialization (which is used in
various libc systems).
Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
395 lines
12 KiB
C
395 lines
12 KiB
C
/* Perform initialization and invoke main.
|
|
Copyright (C) 1998-2023 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
/* Note: This code is only part of the startup code proper for
|
|
statically linked binaries. For dynamically linked binaries, it
|
|
resides in libc.so. */
|
|
|
|
/* Mark symbols hidden in static PIE for early self relocation to work. */
|
|
#if BUILD_PIE_DEFAULT
|
|
# pragma GCC visibility push(hidden)
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <ldsodefs.h>
|
|
#include <libc-diag.h>
|
|
#include <libc-internal.h>
|
|
#include <elf/libc-early-init.h>
|
|
#include <stdbool.h>
|
|
#include <elf-initfini.h>
|
|
#include <shlib-compat.h>
|
|
|
|
#include <elf/dl-tunables.h>
|
|
|
|
extern void __libc_init_first (int argc, char **argv, char **envp);
|
|
|
|
#include <tls.h>
|
|
#ifndef SHARED
|
|
# include <dl-osinfo.h>
|
|
# ifndef THREAD_SET_STACK_GUARD
|
|
/* Only exported for architectures that don't store the stack guard canary
|
|
in thread local area. */
|
|
uintptr_t __stack_chk_guard attribute_relro;
|
|
# endif
|
|
# ifndef THREAD_SET_POINTER_GUARD
|
|
/* Only exported for architectures that don't store the pointer guard
|
|
value in thread local area. */
|
|
uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
|
|
# endif
|
|
#endif
|
|
|
|
#ifndef SHARED
|
|
# include <link.h>
|
|
# include <dl-irel.h>
|
|
|
|
# ifdef ELF_MACHINE_IRELA
|
|
# define IREL_T ElfW(Rela)
|
|
# define IPLT_START __rela_iplt_start
|
|
# define IPLT_END __rela_iplt_end
|
|
# define IREL elf_irela
|
|
# elif defined ELF_MACHINE_IREL
|
|
# define IREL_T ElfW(Rel)
|
|
# define IPLT_START __rel_iplt_start
|
|
# define IPLT_END __rel_iplt_end
|
|
# define IREL elf_irel
|
|
# endif
|
|
|
|
static void
|
|
apply_irel (void)
|
|
{
|
|
# ifdef IREL
|
|
/* We use weak references for these so that we'll still work with a linker
|
|
that doesn't define them. Such a linker doesn't support IFUNC at all
|
|
and so uses won't work, but a statically-linked program that doesn't
|
|
use any IFUNC symbols won't have a problem. */
|
|
extern const IREL_T IPLT_START[] __attribute__ ((weak));
|
|
extern const IREL_T IPLT_END[] __attribute__ ((weak));
|
|
for (const IREL_T *ipltent = IPLT_START; ipltent < IPLT_END; ++ipltent)
|
|
IREL (ipltent);
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef LIBC_START_MAIN
|
|
# ifdef LIBC_START_DISABLE_INLINE
|
|
# define STATIC static
|
|
# else
|
|
# define STATIC static inline __attribute__ ((always_inline))
|
|
# endif
|
|
# define DO_DEFINE_LIBC_START_MAIN_VERSION 0
|
|
#else
|
|
# define STATIC
|
|
# define LIBC_START_MAIN __libc_start_main_impl
|
|
# define DO_DEFINE_LIBC_START_MAIN_VERSION 1
|
|
#endif
|
|
|
|
#ifdef MAIN_AUXVEC_ARG
|
|
/* main gets passed a pointer to the auxiliary. */
|
|
# define MAIN_AUXVEC_DECL , void *
|
|
# define MAIN_AUXVEC_PARAM , auxvec
|
|
#else
|
|
# define MAIN_AUXVEC_DECL
|
|
# define MAIN_AUXVEC_PARAM
|
|
#endif
|
|
|
|
#ifndef ARCH_INIT_CPU_FEATURES
|
|
# define ARCH_INIT_CPU_FEATURES()
|
|
#endif
|
|
|
|
/* Obtain the definition of __libc_start_call_main. */
|
|
#include <libc_start_call_main.h>
|
|
|
|
#ifdef SHARED
|
|
/* Initialization for dynamic executables. Find the main executable
|
|
link map and run its init functions. */
|
|
static void
|
|
call_init (int argc, char **argv, char **env)
|
|
{
|
|
/* Obtain the main map of the executable. */
|
|
struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
|
|
|
/* DT_PREINIT_ARRAY is not processed here. It is already handled in
|
|
_dl_init in elf/dl-init.c. Also see the call_init function in
|
|
the same file. */
|
|
|
|
if (ELF_INITFINI && l->l_info[DT_INIT] != NULL)
|
|
DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr,
|
|
argc, argv, env);
|
|
|
|
ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
|
|
if (init_array != NULL)
|
|
{
|
|
unsigned int jm
|
|
= l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
|
|
ElfW(Addr) *addrs = (void *) (init_array->d_un.d_ptr + l->l_addr);
|
|
for (unsigned int j = 0; j < jm; ++j)
|
|
((dl_init_t) addrs[j]) (argc, argv, env);
|
|
}
|
|
}
|
|
|
|
#else /* !SHARED */
|
|
|
|
/* These magic symbols are provided by the linker. */
|
|
extern void (*__preinit_array_start []) (int, char **, char **)
|
|
attribute_hidden;
|
|
extern void (*__preinit_array_end []) (int, char **, char **)
|
|
attribute_hidden;
|
|
extern void (*__init_array_start []) (int, char **, char **)
|
|
attribute_hidden;
|
|
extern void (*__init_array_end []) (int, char **, char **)
|
|
attribute_hidden;
|
|
extern void (*__fini_array_start []) (void) attribute_hidden;
|
|
extern void (*__fini_array_end []) (void) attribute_hidden;
|
|
|
|
# if ELF_INITFINI
|
|
/* These function symbols are provided for the .init/.fini section entry
|
|
points automagically by the linker. */
|
|
extern void _init (void);
|
|
extern void _fini (void);
|
|
# endif
|
|
|
|
/* Initialization for static executables. There is no dynamic
|
|
segment, so we access the symbols directly. */
|
|
static void
|
|
call_init (int argc, char **argv, char **envp)
|
|
{
|
|
/* For static executables, preinit happens right before init. */
|
|
{
|
|
const size_t size = __preinit_array_end - __preinit_array_start;
|
|
size_t i;
|
|
for (i = 0; i < size; i++)
|
|
(*__preinit_array_start [i]) (argc, argv, envp);
|
|
}
|
|
|
|
# if ELF_INITFINI
|
|
_init ();
|
|
# endif
|
|
|
|
const size_t size = __init_array_end - __init_array_start;
|
|
for (size_t i = 0; i < size; i++)
|
|
(*__init_array_start [i]) (argc, argv, envp);
|
|
}
|
|
|
|
/* Likewise for the destructor. */
|
|
static void
|
|
call_fini (void *unused)
|
|
{
|
|
size_t i = __fini_array_end - __fini_array_start;
|
|
while (i-- > 0)
|
|
(*__fini_array_start [i]) ();
|
|
|
|
# if ELF_INITFINI
|
|
_fini ();
|
|
# endif
|
|
}
|
|
|
|
#endif /* !SHARED */
|
|
|
|
#include <libc-start.h>
|
|
|
|
STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
|
|
MAIN_AUXVEC_DECL),
|
|
int argc,
|
|
char **argv,
|
|
#ifdef LIBC_START_MAIN_AUXVEC_ARG
|
|
ElfW(auxv_t) *auxvec,
|
|
#endif
|
|
__typeof (main) init,
|
|
void (*fini) (void),
|
|
void (*rtld_fini) (void),
|
|
void *stack_end)
|
|
__attribute__ ((noreturn));
|
|
|
|
|
|
/* Note: The init and fini parameters are no longer used. fini is
|
|
completely unused, init is still called if not NULL, but the
|
|
current startup code always passes NULL. (In the future, it would
|
|
be possible to use fini to pass a version code if init is NULL, to
|
|
indicate the link-time glibc without introducing a hard
|
|
incompatibility for new programs with older glibc versions.)
|
|
|
|
For dynamically linked executables, the dynamic segment is used to
|
|
locate constructors and destructors. For statically linked
|
|
executables, the relevant symbols are access directly. */
|
|
STATIC int
|
|
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
|
int argc, char **argv,
|
|
#ifdef LIBC_START_MAIN_AUXVEC_ARG
|
|
ElfW(auxv_t) *auxvec,
|
|
#endif
|
|
__typeof (main) init,
|
|
void (*fini) (void),
|
|
void (*rtld_fini) (void), void *stack_end)
|
|
{
|
|
#ifndef SHARED
|
|
char **ev = &argv[argc + 1];
|
|
|
|
__environ = ev;
|
|
|
|
/* Store the lowest stack address. This is done in ld.so if this is
|
|
the code for the DSO. */
|
|
__libc_stack_end = stack_end;
|
|
|
|
# ifdef HAVE_AUX_VECTOR
|
|
/* First process the auxiliary vector since we need to find the
|
|
program header to locate an eventually present PT_TLS entry. */
|
|
# ifndef LIBC_START_MAIN_AUXVEC_ARG
|
|
ElfW(auxv_t) *auxvec;
|
|
{
|
|
char **evp = ev;
|
|
while (*evp++ != NULL)
|
|
;
|
|
auxvec = (ElfW(auxv_t) *) evp;
|
|
}
|
|
# endif
|
|
_dl_aux_init (auxvec);
|
|
# endif
|
|
|
|
__tunables_init (__environ);
|
|
|
|
ARCH_INIT_CPU_FEATURES ();
|
|
|
|
/* Do static pie self relocation after tunables and cpu features
|
|
are setup for ifunc resolvers. Before this point relocations
|
|
must be avoided. */
|
|
_dl_relocate_static_pie ();
|
|
|
|
/* Perform IREL{,A} relocations. */
|
|
ARCH_SETUP_IREL ();
|
|
|
|
/* The stack guard goes into the TCB, so initialize it early. */
|
|
ARCH_SETUP_TLS ();
|
|
|
|
/* In some architectures, IREL{,A} relocations happen after TLS setup in
|
|
order to let IFUNC resolvers benefit from TCB information, e.g. powerpc's
|
|
hwcap and platform fields available in the TCB. */
|
|
ARCH_APPLY_IREL ();
|
|
|
|
/* Set up the stack checker's canary. */
|
|
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
|
|
# ifdef THREAD_SET_STACK_GUARD
|
|
THREAD_SET_STACK_GUARD (stack_chk_guard);
|
|
# else
|
|
__stack_chk_guard = stack_chk_guard;
|
|
# endif
|
|
|
|
/* Initialize libpthread if linked in. */
|
|
if (__pthread_initialize_minimal != NULL)
|
|
__pthread_initialize_minimal ();
|
|
|
|
/* Set up the pointer guard value. */
|
|
uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random,
|
|
stack_chk_guard);
|
|
# ifdef THREAD_SET_POINTER_GUARD
|
|
THREAD_SET_POINTER_GUARD (pointer_chk_guard);
|
|
# else
|
|
__pointer_chk_guard_local = pointer_chk_guard;
|
|
# endif
|
|
|
|
#endif /* !SHARED */
|
|
|
|
/* Register the destructor of the dynamic linker if there is any. */
|
|
if (__glibc_likely (rtld_fini != NULL))
|
|
__cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
|
|
|
|
#ifndef SHARED
|
|
/* Perform early initialization. In the shared case, this function
|
|
is called from the dynamic loader as early as possible. */
|
|
__libc_early_init (true);
|
|
|
|
/* Call the initializer of the libc. This is only needed here if we
|
|
are compiling for the static library in which case we haven't
|
|
run the constructors in `_dl_start_user'. */
|
|
__libc_init_first (argc, argv, __environ);
|
|
|
|
/* Register the destructor of the statically-linked program. */
|
|
__cxa_atexit (call_fini, NULL, NULL);
|
|
|
|
/* Some security at this point. Prevent starting a SUID binary where
|
|
the standard file descriptors are not opened. We have to do this
|
|
only for statically linked applications since otherwise the dynamic
|
|
loader did the work already. */
|
|
if (__builtin_expect (__libc_enable_secure, 0))
|
|
__libc_check_standard_fds ();
|
|
#endif /* !SHARED */
|
|
|
|
/* Call the initializer of the program, if any. */
|
|
#ifdef SHARED
|
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
|
GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
|
|
|
|
if (init != NULL)
|
|
/* This is a legacy program which supplied its own init
|
|
routine. */
|
|
(*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
|
|
else
|
|
/* This is a current program. Use the dynamic segment to find
|
|
constructors. */
|
|
call_init (argc, argv, __environ);
|
|
|
|
/* Auditing checkpoint: we have a new object. */
|
|
_dl_audit_preinit (GL(dl_ns)[LM_ID_BASE]._ns_loaded);
|
|
|
|
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
|
|
GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
|
|
#else /* !SHARED */
|
|
call_init (argc, argv, __environ);
|
|
|
|
_dl_debug_initialize (0, LM_ID_BASE);
|
|
#endif
|
|
|
|
__libc_start_call_main (main, argc, argv MAIN_AUXVEC_PARAM);
|
|
}
|
|
|
|
/* Starting with glibc 2.34, the init parameter is always NULL. Older
|
|
libcs are not prepared to handle that. The macro
|
|
DEFINE_LIBC_START_MAIN_VERSION creates GLIBC_2.34 alias, so that
|
|
newly linked binaries reflect that dependency. The macros below
|
|
expect that the exported function is called
|
|
__libc_start_main_impl. */
|
|
#ifdef SHARED
|
|
# define DEFINE_LIBC_START_MAIN_VERSION \
|
|
DEFINE_LIBC_START_MAIN_VERSION_1 \
|
|
strong_alias (__libc_start_main_impl, __libc_start_main_alias_2) \
|
|
versioned_symbol (libc, __libc_start_main_alias_2, __libc_start_main, \
|
|
GLIBC_2_34);
|
|
|
|
# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_34)
|
|
# define DEFINE_LIBC_START_MAIN_VERSION_1 \
|
|
strong_alias (__libc_start_main_impl, __libc_start_main_alias_1) \
|
|
compat_symbol (libc, __libc_start_main_alias_1, __libc_start_main, GLIBC_2_0);
|
|
# else
|
|
# define DEFINE_LIBC_START_MAIN_VERSION_1
|
|
# endif
|
|
#else /* !SHARED */
|
|
/* Enable calling the function under its exported name. */
|
|
# define DEFINE_LIBC_START_MAIN_VERSION \
|
|
strong_alias (__libc_start_main_impl, __libc_start_main)
|
|
#endif
|
|
|
|
/* Only define the version information if LIBC_START_MAIN was not set.
|
|
If there is a wrapper file, it must expand
|
|
DEFINE_LIBC_START_MAIN_VERSION on its own. */
|
|
#if DO_DEFINE_LIBC_START_MAIN_VERSION
|
|
DEFINE_LIBC_START_MAIN_VERSION
|
|
#endif
|