elf: Relocate libc.so early during startup and dlmopen (bug 31083)

This makes it more likely that objects without dependencies can
use IFUNC resolvers in libc.so.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Florian Weimer 2023-11-27 11:28:13 +01:00
parent a74c2e1cbc
commit 78ca44da01
7 changed files with 118 additions and 2 deletions

View File

@ -433,6 +433,8 @@ tests += \
tst-nodelete-dlclose \ tst-nodelete-dlclose \
tst-nodelete-opened \ tst-nodelete-opened \
tst-nodelete2 \ tst-nodelete2 \
tst-nodeps1 \
tst-nodeps2 \
tst-noload \ tst-noload \
tst-non-directory-path \ tst-non-directory-path \
tst-null-argv \ tst-null-argv \
@ -863,6 +865,8 @@ modules-names += \
tst-nodelete-dlclose-plugin \ tst-nodelete-dlclose-plugin \
tst-nodelete-opened-lib \ tst-nodelete-opened-lib \
tst-nodelete2mod \ tst-nodelete2mod \
tst-nodeps1-mod \
tst-nodeps2-mod \
tst-non-directory-mod \ tst-non-directory-mod \
tst-null-argv-lib \ tst-null-argv-lib \
tst-p_alignmod-base \ tst-p_alignmod-base \
@ -1030,6 +1034,8 @@ modules-names-nobuild += \
tst-audit24bmod1 \ tst-audit24bmod1 \
tst-audit24bmod2 \ tst-audit24bmod2 \
tst-big-note-lib \ tst-big-note-lib \
tst-nodeps1-mod \
tst-nodeps2-mod \
tst-ro-dynamic-mod \ tst-ro-dynamic-mod \
# modules-names-nobuild # 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. # Reuse a module with a SONAME, to specific as the LD_PROFILE.
$(objpfx)tst-env-setuid: $(objpfx)tst-sonamemove-runmod2.so $(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 $@ $^
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
# 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

View File

@ -708,6 +708,17 @@ dl_open_worker_begin (void *a)
them. However, such relocation dependencies in IFUNC resolvers them. However, such relocation dependencies in IFUNC resolvers
are undefined anyway, so this is not a problem. */ 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);
#endif
for (unsigned int i = last; i-- > first; ) for (unsigned int i = last; i-- > first; )
_dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode, _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode,
&relocation_in_progress); &relocation_in_progress);

View File

@ -2272,11 +2272,17 @@ dl_main (const ElfW(Phdr) *phdr,
objects. We do not re-relocate the dynamic linker itself in this objects. We do not re-relocate the dynamic linker itself in this
loop because that could result in the GOT entries for functions we 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 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 the dynamic linker out of order because it has no copy relocations.
know that because it is self-contained). */ Likewise for libc, which is relocated early to ensure that IFUNC
resolvers in libc work. */
int consider_profiling = GLRO(dl_profile) != NULL; 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);
/* If we are profiling we also must do lazy reloaction. */ /* If we are profiling we also must do lazy reloaction. */
GLRO(dl_lazy) |= consider_profiling; GLRO(dl_lazy) |= consider_profiling;

25
elf/tst-nodeps1-mod.c Normal file
View File

@ -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;

23
elf/tst-nodeps1.c Normal file
View File

@ -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)
{
}

1
elf/tst-nodeps2-mod.c Normal file
View File

@ -0,0 +1 @@
/* Empty test module which depends on tst-nodeps1-mod.so. */

29
elf/tst-nodeps2.c Normal file
View File

@ -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);
xdlclose (handle);
return 0;
}
#include <support/test-driver.c>