Improve compatibility between underlinking and IFUNC resolvers (RHEL-16825)

Resolves: RHEL-16825
This commit is contained in:
Florian Weimer 2023-12-08 14:42:07 +01:00
parent 8bd47ef1b2
commit b76a8ebe01
5 changed files with 428 additions and 1 deletions

35
glibc-RHEL-16825-1.patch Normal file
View File

@ -0,0 +1,35 @@
commit b893410be304ddcea0bd43f537a13e8b18d37cf2
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 27 11:28:07 2023 +0100
elf: In _dl_relocate_object, skip processing if object is relocated
This is just a minor optimization. It also makes it more obvious that
_dl_relocate_object can be called multiple times.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 7d8b2bd2336eecb6..66c9266d7f9d65af 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -165,6 +165,9 @@ void
_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
int reloc_mode, int consider_profiling)
{
+ if (l->l_relocated)
+ return;
+
struct textrels
{
caddr_t start;
@@ -202,9 +205,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
# define consider_symbind 0
#endif
- if (l->l_relocated)
- return;
-
/* If DT_BIND_NOW is set relocate all references in this object. We
do not do this if we are profiling, of course. */
// XXX Correct for auditing?

121
glibc-RHEL-16825-2.patch Normal file
View File

@ -0,0 +1,121 @@
commit a74c2e1cbc8673dd7e97aae2f2705392e2ccc3f6
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 27 11:28:10 2023 +0100
elf: Introduce the _dl_open_relocate_one_object function
It is extracted from dl_open_worker_begin.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 7dfb6b680c108c0b..160451790bb88447 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -466,6 +466,50 @@ activate_nodelete (struct link_map *new)
}
}
+/* Relocate the object L. *RELOCATION_IN_PROGRESS controls whether
+ the debugger is notified of the start of relocation processing. */
+static void
+_dl_open_relocate_one_object (struct dl_open_args *args, struct r_debug *r,
+ struct link_map *l, int reloc_mode,
+ bool *relocation_in_progress)
+{
+ if (l->l_real->l_relocated)
+ return;
+
+ if (!*relocation_in_progress)
+ {
+ /* Notify the debugger that relocations are about to happen. */
+ LIBC_PROBE (reloc_start, 2, args->nsid, r);
+ *relocation_in_progress = true;
+ }
+
+#ifdef SHARED
+ if (__glibc_unlikely (GLRO(dl_profile) != NULL))
+ {
+ /* If this here is the shared object which we want to profile
+ make sure the profile is started. We can find out whether
+ this is necessary or not by observing the `_dl_profile_map'
+ variable. If it was NULL but is not NULL afterwards we must
+ start the profiling. */
+ struct link_map *old_profile_map = GL(dl_profile_map);
+
+ _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1);
+
+ if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
+ {
+ /* We must prepare the profiling. */
+ _dl_start_profile ();
+
+ /* Prevent unloading the object. */
+ GL(dl_profile_map)->l_nodelete_active = true;
+ }
+ }
+ else
+#endif
+ _dl_relocate_object (l, l->l_scope, reloc_mode, 0);
+}
+
+
/* struct dl_init_args and call_dl_init are used to call _dl_init with
exception handling disabled. */
struct dl_init_args
@@ -638,7 +682,7 @@ dl_open_worker_begin (void *a)
}
while (l != NULL);
- int relocation_in_progress = 0;
+ bool relocation_in_progress = false;
/* Perform relocation. This can trigger lazy binding in IFUNC
resolvers. For NODELETE mappings, these dependencies are not
@@ -649,44 +693,8 @@ dl_open_worker_begin (void *a)
are undefined anyway, so this is not a problem. */
for (unsigned int i = last; i-- > first; )
- {
- l = new->l_initfini[i];
-
- if (l->l_real->l_relocated)
- continue;
-
- if (! relocation_in_progress)
- {
- /* Notify the debugger that relocations are about to happen. */
- LIBC_PROBE (reloc_start, 2, args->nsid, r);
- relocation_in_progress = 1;
- }
-
-#ifdef SHARED
- if (__glibc_unlikely (GLRO(dl_profile) != NULL))
- {
- /* If this here is the shared object which we want to profile
- make sure the profile is started. We can find out whether
- this is necessary or not by observing the `_dl_profile_map'
- variable. If it was NULL but is not NULL afterwards we must
- start the profiling. */
- struct link_map *old_profile_map = GL(dl_profile_map);
-
- _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1);
-
- if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
- {
- /* We must prepare the profiling. */
- _dl_start_profile ();
-
- /* Prevent unloading the object. */
- GL(dl_profile_map)->l_nodelete_active = true;
- }
- }
- else
-#endif
- _dl_relocate_object (l, l->l_scope, reloc_mode, 0);
- }
+ _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode,
+ &relocation_in_progress);
/* This only performs the memory allocations. The actual update of
the scopes happens below, after failure is impossible. */

223
glibc-RHEL-16825-3.patch Normal file
View File

@ -0,0 +1,223 @@
commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 27 11:28:13 2023 +0100
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>
Conflicts:
elf/Makefile
(differences in test backports)
elf/rtld.c
(removal of prelink support upstream)
diff --git a/elf/Makefile b/elf/Makefile
index 42dc878209b11d29..ebf46a297d241d8f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -387,6 +387,8 @@ tests += \
tst-nodelete2 \
tst-nodelete-dlclose \
tst-nodelete-opened \
+ tst-nodeps1 \
+ tst-nodeps2 \
tst-noload \
tst-null-argv \
tst-relsort1 \
@@ -743,6 +745,8 @@ modules-names = \
tst-nodelete-dlclose-dso \
tst-nodelete-dlclose-plugin \
tst-nodelete-opened-lib \
+ tst-nodeps1-mod \
+ tst-nodeps2-mod \
tst-null-argv-lib \
tst-relsort1mod1 \
tst-relsort1mod2 \
@@ -889,8 +893,13 @@ modules-execstack-yes = tst-execstack-mod
extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
# filtmod1.so has a special rule
-modules-names-nobuild := filtmod1 \
- tst-audit24bmod1 tst-audit24bmod2
+modules-names-nobuild += \
+ filtmod1 \
+ tst-audit24bmod1 \
+ tst-audit24bmod2 \
+ tst-nodeps1-mod \
+ tst-nodeps2-mod \
+ # modules-names-nobuild
tests += $(tests-static)
@@ -2707,3 +2716,18 @@ $(objpfx)tst-dlclose-lazy: $(libdl)
$(objpfx)tst-dlclose-lazy.out: \
$(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.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: $(libdl)
+$(objpfx)tst-nodeps2.out: \
+ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 160451790bb88447..f32e2fd4ee39db93 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -692,6 +692,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);
+#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 cd2cc4024a3581c2..502d2a1c58505d88 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2414,11 +2414,17 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
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);
+
/* 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 0000000000000000..45c8e3c631251a89
--- /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;
diff --git a/elf/tst-nodeps1.c b/elf/tst-nodeps1.c
new file mode 100644
index 0000000000000000..1a8bde36cdb71446
--- /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 0000000000000000..4913feee9b56e0e1
--- /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 0000000000000000..0bdc8eeb8cba3a99
--- /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);
+ xdlclose (handle);
+ return 0;
+}
+
+#include <support/test-driver.c>

41
glibc-RHEL-16825-4.patch Normal file
View File

@ -0,0 +1,41 @@
commit b3bee76c5f59498b9c189608f0a3132e2013fa1a
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 8 09:51:34 2023 +0100
elf: Initialize GLRO(dl_lazy) before relocating libc in dynamic startup
GLRO(dl_lazy) is used to set the parameters for the early
_dl_relocate_object call, so the consider_profiling setting has to
be applied before the call.
Fixes commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec ("elf: Relocate
libc.so early during startup and dlmopen (bug 31083)").
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/rtld.c
(removal of prelink support upstream)
diff --git a/elf/rtld.c b/elf/rtld.c
index 502d2a1c58505d88..4f317a2a874e6af7 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2420,14 +2420,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
int consider_profiling = GLRO(dl_profile) != NULL;
+ /* If we are profiling we also must do lazy reloaction. */
+ GLRO(dl_lazy) |= consider_profiling;
+
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. */
- GLRO(dl_lazy) |= consider_profiling;
-
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
unsigned i = main_map->l_searchlist.r_nlist;

View File

@ -1,6 +1,6 @@
%define glibcsrcdir glibc-2.28
%define glibcversion 2.28
%define glibcrelease 244%{?dist}
%define glibcrelease 245%{?dist}
# Pre-release tarballs are pulled in from git using a command that is
# effectively:
#
@ -1061,6 +1061,10 @@ Patch873: glibc-RHEL-10481.patch
Patch874: glibc-RHEL-13720-1.patch
Patch875: glibc-RHEL-13720-2.patch
Patch876: glibc-RHEL-15867.patch
Patch877: glibc-RHEL-16825-1.patch
Patch878: glibc-RHEL-16825-2.patch
Patch879: glibc-RHEL-16825-3.patch
Patch880: glibc-RHEL-16825-4.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -2892,6 +2896,9 @@ fi
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
%changelog
* Fri Dec 8 2023 Florian Weimer <fweimer@redhat.com> - 2.28-245
- Improve compatibility between underlinking and IFUNC resolvers (RHEL-16825)
* Fri Nov 24 2023 Florian Weimer <fweimer@redhat.com> - 2.28-244
- Restore <sys/cdefs.h> compatibility with C90 compilers (RHEL-15867)