elf: Add initial flag argument to __libc_early_init

The rseq initialization should happen only for the libc in the base
namespace (in the dynamic case) or the statically linked libc.  The
__libc_multiple_libcs flag does not quite cover this case at present,
so this commit introduces a flag argument to __libc_early_init,
indicating whether the libc being libc is the primary one (of the main
program).

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Florian Weimer 2020-04-29 15:44:03 +02:00
parent 2ad5d0845d
commit 03e187a41d
6 changed files with 31 additions and 12 deletions

View File

@ -23,6 +23,7 @@
#include <exit-thread.h> #include <exit-thread.h>
#include <libc-internal.h> #include <libc-internal.h>
#include <elf/libc-early-init.h> #include <elf/libc-early-init.h>
#include <stdbool.h>
#include <elf/dl-tunables.h> #include <elf/dl-tunables.h>
@ -241,7 +242,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
#ifndef SHARED #ifndef SHARED
/* Perform early initialization. In the shared case, this function /* Perform early initialization. In the shared case, this function
is called from the dynamic loader as early as possible. */ is called from the dynamic loader as early as possible. */
__libc_early_init (); __libc_early_init (true);
/* Call the initializer of the libc. This is only needed here if we /* 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 are compiling for the static library in which case we haven't

View File

@ -23,7 +23,7 @@
#include <stddef.h> #include <stddef.h>
void void
_dl_call_libc_early_init (struct link_map *libc_map) _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
{ {
/* There is nothing to do if we did not actually load libc.so. */ /* There is nothing to do if we did not actually load libc.so. */
if (libc_map == NULL) if (libc_map == NULL)
@ -37,5 +37,5 @@ _dl_call_libc_early_init (struct link_map *libc_map)
assert (sym != NULL); assert (sym != NULL);
__typeof (__libc_early_init) *early_init __typeof (__libc_early_init) *early_init
= DL_SYMBOL_ADDRESS (libc_map, sym); = DL_SYMBOL_ADDRESS (libc_map, sym);
early_init (); early_init (initial);
} }

View File

@ -748,9 +748,22 @@ dl_open_worker (void *a)
LIBC_PROBE (reloc_complete, 3, args->nsid, r, new); LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
/* If libc.so was not there before, attempt to call its early /* If libc.so was not there before, attempt to call its early
initialization routine. */ initialization routine. Indicate to the initialization routine
whether the libc being initialized is the one in the base
namespace. */
if (!args->libc_already_loaded) if (!args->libc_already_loaded)
_dl_call_libc_early_init (GL(dl_ns)[args->nsid].libc_map); {
struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map;
#ifdef SHARED
bool initial = libc_map->l_ns == LM_ID_BASE;
#else
/* In the static case, there is only one namespace, but it
contains a secondary libc (the primary libc is statically
linked). */
bool initial = false;
#endif
_dl_call_libc_early_init (libc_map, initial);
}
#ifndef SHARED #ifndef SHARED
DL_STATIC_INIT (new); DL_STATIC_INIT (new);

View File

@ -22,14 +22,17 @@
struct link_map; struct link_map;
/* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it /* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it
and call this function. */ and call this function, with INITIAL as the argument. */
void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden; void _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
attribute_hidden;
/* In the shared case, this function is defined in libc.so and invoked /* In the shared case, this function is defined in libc.so and invoked
from ld.so (or on the fist static dlopen) after complete relocation from ld.so (or on the fist static dlopen) after complete relocation
of a new loaded libc.so, but before user-defined ELF constructors of a new loaded libc.so, but before user-defined ELF constructors
run. In the static case, this function is called directly from the run. In the static case, this function is called directly from the
startup code. */ startup code. If INITIAL is true, the libc being initialized is
void __libc_early_init (void); the libc for the main program. INITIAL is false for libcs loaded
for audit modules, dlmopen, and static dlopen. */
void __libc_early_init (_Bool initial);
#endif /* _LIBC_EARLY_INIT_H */ #endif /* _LIBC_EARLY_INIT_H */

View File

@ -20,7 +20,7 @@
#include <libc-early-init.h> #include <libc-early-init.h>
void void
__libc_early_init (void) __libc_early_init (_Bool initial)
{ {
/* Initialize ctype data. */ /* Initialize ctype data. */
__ctype_init (); __ctype_init ();

View File

@ -2373,8 +2373,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
rtld_timer_accum (&relocate_time, start); rtld_timer_accum (&relocate_time, start);
} }
/* Relocation is complete. Perform early libc initialization. */ /* Relocation is complete. Perform early libc initialization. This
_dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map); is the initial libc, even if audit modules have been loaded with
other libcs. */
_dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map, true);
/* Do any necessary cleanups for the startup OS interface code. /* Do any necessary cleanups for the startup OS interface code.
We do these now so that no calls are made after rtld re-relocation We do these now so that no calls are made after rtld re-relocation