[PATCH] elf: Add initial flag argument to __libc_early_init

Carlos O'Donell carlos@redhat.com
Wed Apr 29 13:30:09 GMT 2020


On 4/27/20 8:31 AM, Florian Weimer wrote:
> 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).

Yes, __libc_multiple_libcs tells you if there are multiple libcs present,
but doesn't tell you which is the first, and which should be initialized,
so you have to pipe that down from early startup which knows which is the
first.

In the case we extend this following Vivek's code to add proxy object for
libc into subsequent namespaces it will continue to work because the base
libc is initialized and then exposed into the later namespaces via a linkmap
that is a proxy. We might have to adjust this a bit because
libc_map->l_ns == LM_ID_BASE will be true in all namespaces because the
libc_map will be a proxy for the runtime into all namespaces to facilitate
coordination of TLS and other parameters (in the case where dlmopen supports
isolation *beyond* the core runtime). It should be straight forward though,
since Vivek added a "is this a proxy" parameter to the link map which we
can check.

OK for master.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> Tested on i686-linux-gnu and x86_64-linux-gnu (although the new flag
> is currently not used).
> 
> -----
>  csu/libc-start.c              |  3 ++-
>  elf/dl-call-libc-early-init.c |  4 ++--
>  elf/dl-open.c                 | 17 +++++++++++++++--
>  elf/libc-early-init.h         | 11 +++++++----
>  elf/libc_early_init.c         |  2 +-
>  elf/rtld.c                    |  6 ++++--
>  6 files changed, 31 insertions(+), 12 deletions(-)
> 
> diff --git a/csu/libc-start.c b/csu/libc-start.c
> index ccc743c9d1..4005caf84a 100644
> --- a/csu/libc-start.c
> +++ b/csu/libc-start.c
> @@ -23,6 +23,7 @@
>  #include <exit-thread.h>
>  #include <libc-internal.h>
>  #include <elf/libc-early-init.h>
> +#include <stdbool.h>
>  
>  #include <elf/dl-tunables.h>
>  
> @@ -241,7 +242,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
>  #ifndef SHARED
>    /* Perform early initialization.  In the shared case, this function
>       is called from the dynamic loader as early as possible.  */
> -  __libc_early_init ();
> +  __libc_early_init (true);

OK, in LIBC_START_MAIN we are the first libc.

>  
>    /* 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
> diff --git a/elf/dl-call-libc-early-init.c b/elf/dl-call-libc-early-init.c
> index 41e9ad9aad..9a84680a1c 100644
> --- a/elf/dl-call-libc-early-init.c
> +++ b/elf/dl-call-libc-early-init.c
> @@ -23,7 +23,7 @@
>  #include <stddef.h>
>  
>  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.  */
>    if (libc_map == NULL)
> @@ -37,5 +37,5 @@ _dl_call_libc_early_init (struct link_map *libc_map)
>    assert (sym != NULL);
>    __typeof (__libc_early_init) *early_init
>      = DL_SYMBOL_ADDRESS (libc_map, sym);
> -  early_init ();
> +  early_init (initial);

OK. Pass parameter to early_init() function which we looked up in libc.

>  }
> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index ac7ab495e4..7bf1144e93 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -748,9 +748,22 @@ dl_open_worker (void *a)
>      LIBC_PROBE (reloc_complete, 3, args->nsid, r, new);
>  
>    /* If libc.so was not there before, attempt to call its early
> -     initialization routine.  */
> +     initialization routine.  Indicate to the initialization routine
> +     whether thie libc being initialized is the one in the base
> +     namespace.  */
>    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;

OK. In the shared case we must be in the base namespace, as that insures
that this is the first loaded libc.

> +#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;

OK. In the static case it's a secondary libc.

> +#endif
> +      _dl_call_libc_early_init (libc_map, initial);
> +    }
>  
>  #ifndef SHARED
>    DL_STATIC_INIT (new);
> diff --git a/elf/libc-early-init.h b/elf/libc-early-init.h
> index 5185fa8895..8f7836dcea 100644
> --- a/elf/libc-early-init.h
> +++ b/elf/libc-early-init.h
> @@ -22,14 +22,17 @@
>  struct link_map;
>  
>  /* If LIBC_MAP is not NULL, look up the __libc_early_init symbol in it
> -   and call this function.  */
> -void _dl_call_libc_early_init (struct link_map *libc_map) attribute_hidden;
> +   and call this function, with INITIAL as the argument.  */
> +void _dl_call_libc_early_init (struct link_map *libc_map, _Bool initial)
> +  attribute_hidden;

OK.

>  
>  /* 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
>     of a new loaded libc.so, but before user-defined ELF constructors
>     run.  In the static case, this function is called directly from the
> -   startup code.  */
> -void __libc_early_init (void);
> +   startup code.  If INITIAL is true, the libc being initialized is
> +   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);

OK.

>  
>  #endif /* _LIBC_EARLY_INIT_H */
> diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c
> index 7f4ca332b8..e6c64fb526 100644
> --- a/elf/libc_early_init.c
> +++ b/elf/libc_early_init.c
> @@ -20,7 +20,7 @@
>  #include <libc-early-init.h>
>  
>  void
> -__libc_early_init (void)
> +__libc_early_init (_Bool initial)

OK. Add bool to definition.

>  {
>    /* Initialize ctype data.  */
>    __ctype_init ();
> diff --git a/elf/rtld.c b/elf/rtld.c
> index 0016db86a7..5ccc3c2dbb 100644
> --- a/elf/rtld.c
> +++ b/elf/rtld.c
> @@ -2373,8 +2373,10 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
>        rtld_timer_accum (&relocate_time, start);
>      }
>  
> -  /* Relocation is complete.  Perform early libc initialization.  */
> -  _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map);
> +  /* Relocation is complete.  Perform early libc initialization.  This
> +     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);

OK. This is dl_main so this is always the initial libc initialization point *if*
we entered through the dynamic loader.

>  
>    /* Do any necessary cleanups for the startup OS interface code.
>       We do these now so that no calls are made after rtld re-relocation
> 


-- 
Cheers,
Carlos.



More information about the Libc-alpha mailing list