[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