[PATCH 3/3] elf: Relocate libc.so early during startup and dlmopen (bug 31083)

Carlos O'Donell carlos@redhat.com
Fri Nov 24 17:04:46 GMT 2023


On 11/24/23 07:56, Florian Weimer wrote:
> This makes it more likely that objects without dependencies can
> use IFUNC resolvers in libc.so.

LGTM.

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

> ---
>  elf/Makefile          | 21 +++++++++++++++++++++
>  elf/dl-open.c         | 11 +++++++++++
>  elf/rtld.c            | 10 ++++++++--
>  elf/tst-nodeps1-mod.c | 25 +++++++++++++++++++++++++
>  elf/tst-nodeps1.c     | 23 +++++++++++++++++++++++
>  elf/tst-nodeps2-mod.c |  1 +
>  elf/tst-nodeps2.c     | 29 +++++++++++++++++++++++++++++
>  7 files changed, 118 insertions(+), 2 deletions(-)
>  create mode 100644 elf/tst-nodeps1-mod.c
>  create mode 100644 elf/tst-nodeps1.c
>  create mode 100644 elf/tst-nodeps2-mod.c
>  create mode 100644 elf/tst-nodeps2.c
> 
> diff --git a/elf/Makefile b/elf/Makefile
> index 3f7f89508e..afec7be084 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -433,6 +433,8 @@ tests += \
>    tst-nodelete-dlclose \
>    tst-nodelete-opened \
>    tst-nodelete2 \
> +  tst-nodeps1 \
> +  tst-nodeps2 \

OK. Two new test.

>    tst-noload \
>    tst-non-directory-path \
>    tst-null-argv \
> @@ -863,6 +865,8 @@ modules-names += \
>    tst-nodelete-dlclose-plugin \
>    tst-nodelete-opened-lib \
>    tst-nodelete2mod \
> +  tst-nodeps1-mod \
> +  tst-nodeps2-mod \

OK. Two new modules.

>    tst-non-directory-mod \
>    tst-null-argv-lib \
>    tst-p_alignmod-base \
> @@ -1030,6 +1034,8 @@ modules-names-nobuild += \
>    tst-audit24bmod1 \
>    tst-audit24bmod2 \
>    tst-big-note-lib \
> +  tst-nodeps1-mod \
> +  tst-nodeps2-mod \

OK. Add modules.

>    tst-ro-dynamic-mod \
>    # modules-names-nobuild
>  
> @@ -3009,3 +3015,18 @@ tst-env-setuid-ARGS = -- $(host-test-program-cmd)
>  
>  # Reuse a module with a SONAME, to specific as the LD_PROFILE.
>  $(objpfx)tst-env-setuid: $(objpfx)tst-sonamemove-runmod2.so
> +
> +# The object tst-nodeps1-mod.so has no explicit dependencies on libc.so.
> +$(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os
> +	$(LINK.o) -nostartfiles -nostdlib -shared -o $@ $^

OK.

> +tst-nodeps1.so-no-z-defs = yes
> +# Link libc.so before the test module with the IFUNC resolver reference.
> +LDFLAGS-tst-nodeps1 = $(common-objpfx)libc.so $(objpfx)tst-nodeps1-mod.so
> +$(objpfx)tst-nodeps1: $(objpfx)tst-nodeps1-mod.so

OK.

> +# Reuse the tst-nodeps1 module.  Link libc.so before the test module
> +# with the IFUNC resolver reference.
> +$(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \
> +  $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.os
> +	$(LINK.o) -Wl,--no-as-needed -nostartfiles -nostdlib -shared -o $@ $^
> +$(objpfx)tst-nodeps2.out: \
> +  $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so

OK.

> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index 417d2fb948..b748c278ac 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -708,6 +708,17 @@ dl_open_worker_begin (void *a)
>       them.  However, such relocation dependencies in IFUNC resolvers
>       are undefined anyway, so this is not a problem.  */
>  
> +  /* Ensure that libc is relocated first.  This helps with the
> +     execution of IFUNC resolvers in libc, and matters only to newly
> +     created dlmopen namespaces.  Do not do this for static dlopen
> +     because libc has relocations against ld.so, which may not have
> +     been relocated at this point.  */
> +#ifdef SHARED
> +  if (GL(dl_ns)[args->nsid].libc_map != NULL)
> +    _dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map,
> +				  reloc_mode, &relocation_in_progress);

OK. Relocate libc first... in the right namespace.

> +#endif
> +
>    for (unsigned int i = last; i-- > first; )
>      _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode,
>  				  &relocation_in_progress);
> diff --git a/elf/rtld.c b/elf/rtld.c
> index 0553c05edb..19bedcd4a6 100644
> --- a/elf/rtld.c
> +++ b/elf/rtld.c
> @@ -2272,11 +2272,17 @@ dl_main (const ElfW(Phdr) *phdr,
>       objects.  We do not re-relocate the dynamic linker itself in this
>       loop because that could result in the GOT entries for functions we
>       call being changed, and that would break us.  It is safe to relocate
> -     the dynamic linker out of order because it has no copy relocs (we
> -     know that because it is self-contained).  */
> +     the dynamic linker out of order because it has no copy relocations.
> +     Likewise for libc, which is relocated early to ensure that IFUNC
> +     resolvers in libc work.  */
>  
>    int consider_profiling = GLRO(dl_profile) != NULL;
>  
> +  if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
> +    _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
> +			 GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
> +			 GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);

OK. Relocate libc early... always in the base namespace.

> +
>    /* If we are profiling we also must do lazy reloaction.  */
>    GLRO(dl_lazy) |= consider_profiling;
>  
> diff --git a/elf/tst-nodeps1-mod.c b/elf/tst-nodeps1-mod.c
> new file mode 100644
> index 0000000000..45c8e3c631
> --- /dev/null
> +++ b/elf/tst-nodeps1-mod.c
> @@ -0,0 +1,25 @@
> +/* Test module with no libc.so dependency and string function references.
> +   Copyright (C) 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/>.  */
> +
> +#include <string.h>
> +
> +/* Some references to libc symbols which are likely to have IFUNC
> +   resolvers.  If they do not, this module does not exercise bug 31083.  */
> +void *memcpy_pointer = memcpy;
> +void *memmove_pointer = memmove;
> +void *memset_pointer = memset;

OK. I don't have a better answer here either, other than some internal access to the
IFUNC impl list and see what's in that list as a cross check here. This is good for now.

> diff --git a/elf/tst-nodeps1.c b/elf/tst-nodeps1.c
> new file mode 100644
> index 0000000000..1a8bde36cd
> --- /dev/null
> +++ b/elf/tst-nodeps1.c
> @@ -0,0 +1,23 @@
> +/* Test initially loaded module with implicit libc.so dependency (bug 31083).
> +   Copyright (C) 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/>.  */
> +
> +/* Testing happens before main.  */
> +int
> +main (void)
> +{
> +}
> diff --git a/elf/tst-nodeps2-mod.c b/elf/tst-nodeps2-mod.c
> new file mode 100644
> index 0000000000..4913feee9b
> --- /dev/null
> +++ b/elf/tst-nodeps2-mod.c
> @@ -0,0 +1 @@
> +/* Empty test module which depends on tst-nodeps1-mod.so.  */
> diff --git a/elf/tst-nodeps2.c b/elf/tst-nodeps2.c
> new file mode 100644
> index 0000000000..0bdc8eeb8c
> --- /dev/null
> +++ b/elf/tst-nodeps2.c
> @@ -0,0 +1,29 @@
> +/* Test dlmopen with implicit libc.so dependency (bug 31083).
> +   Copyright (C) 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/>.  */
> +
> +#include <support/xdlfcn.h>
> +
> +static int
> +do_test (void)
> +{
> +  void *handle = xdlmopen (LM_ID_NEWLM, "tst-nodeps2-mod.so", RTLD_NOW);

OK. tst-nodeps2-mod.so -> {libc.so.6, tst-nodeps1-mod.so}

> +  xdlclose (handle);
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

-- 
Cheers,
Carlos.



More information about the Libc-alpha mailing list