Switch to main malloc after final ld.so self-relocation

- Backport: elf: rtld_multiple_ref is always true
- Backport: elf: Do not define consider_profiling, consider_symbind as
  macros
- Backport: elf: Introduce _dl_relocate_object_no_relro
- Backport: elf: Switch to main malloc after final ld.so
  self-relocation
- Backport: elf: Second ld.so relocation only if libc.so has been
  loaded
- Backport: elf: Minimize library dependencies of tst-nolink-libc.c
- Backport: elf: Add missing DSO dependencies for
  tst-rtld-no-malloc-{audit,preload}

Resolves: RHEL-48820
This commit is contained in:
Frédéric Bérat 2025-06-18 14:59:47 +02:00
parent 9d355805b4
commit 7a4b319108
8 changed files with 749 additions and 1 deletions

120
glibc-RHEL-48820-1.patch Normal file
View File

@ -0,0 +1,120 @@
commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: rtld_multiple_ref is always true
For a long time, libc.so.6 has dependend on ld.so, which
means that there is a reference to ld.so in all processes,
and rtld_multiple_ref is always true. In fact, if
rtld_multiple_ref were false, some of the ld.so setup code
would not run.
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts:
elf/rtld.c (
- prelink support not removed downstream
- "elf: Add _dl_find_object function" not ported
downstream
)
diff --git a/elf/rtld.c b/elf/rtld.c
index d02ecc834c9a4d43..711bb77d70da6563 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2002,43 +2002,37 @@ dl_main (const ElfW(Phdr) *phdr,
if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map))
break;
- bool rtld_multiple_ref = false;
- if (__glibc_likely (i < main_map->l_searchlist.r_nlist))
- {
- /* Some DT_NEEDED entry referred to the interpreter object itself, so
- put it back in the list of visible objects. We insert it into the
- chain in symbol search order because gdb uses the chain's order as
- its symbol search order. */
- rtld_multiple_ref = true;
+ /* Insert the link map for the dynamic loader into the chain in
+ symbol search order because gdb uses the chain's order as its
+ symbol search order. */
- GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
- if (__glibc_likely (state.mode == rtld_mode_normal))
- {
- GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
- ? main_map->l_searchlist.r_list[i + 1]
- : NULL);
+ GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
+ if (__glibc_likely (state.mode == rtld_mode_normal))
+ {
+ GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
+ ? main_map->l_searchlist.r_list[i + 1]
+ : NULL);
#ifdef NEED_DL_SYSINFO_DSO
- if (GLRO(dl_sysinfo_map) != NULL
- && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
- && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
- GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
+ if (GLRO(dl_sysinfo_map) != NULL
+ && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map)
+ && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map))
+ GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map);
#endif
- }
- else
- /* In trace mode there might be an invisible object (which we
- could not find) after the previous one in the search list.
- In this case it doesn't matter much where we put the
- interpreter object, so we just initialize the list pointer so
- that the assertion below holds. */
- GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
-
- assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
- GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
- if (GL(dl_rtld_map).l_next != NULL)
- {
- assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
- GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
- }
+ }
+ else
+ /* In trace mode there might be an invisible object (which we
+ could not find) after the previous one in the search list.
+ In this case it doesn't matter much where we put the
+ interpreter object, so we just initialize the list pointer so
+ that the assertion below holds. */
+ GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next;
+
+ assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next);
+ GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map);
+ if (GL(dl_rtld_map).l_next != NULL)
+ {
+ assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev);
+ GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map);
}
/* Now let us see whether all libraries are available in the
@@ -2212,8 +2206,7 @@ dl_main (const ElfW(Phdr) *phdr,
}
}
- if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
- && rtld_multiple_ref)
+ if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
{
/* Mark the link map as not yet relocated again. */
GL(dl_rtld_map).l_relocated = 0;
@@ -2500,10 +2493,9 @@ dl_main (const ElfW(Phdr) *phdr,
/* Make sure no new search directories have been added. */
assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
- if (! prelinked && rtld_multiple_ref)
+ if (! prelinked)
{
- /* There was an explicit ref to the dynamic linker as a shared lib.
- Re-relocate ourselves with user-controlled symbol definitions.
+ /* Re-relocate ourselves with user-controlled symbol definitions.
We must do this after TLS initialization in case after this
re-relocation, we might call a user-supplied function

52
glibc-RHEL-48820-2.patch Normal file
View File

@ -0,0 +1,52 @@
commit a79642204537dec8a1e1c58d1e0a074b3c624f46
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: Do not define consider_profiling, consider_symbind as macros
This avoids surprises when refactoring the code if these identifiers
are re-used later in the file.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 0254e589c06fbf4c..ded506da9e180eac 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -207,8 +207,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
int lazy = reloc_mode & RTLD_LAZY;
int skip_ifunc = reloc_mode & __RTLD_NOIFUNC;
-#ifdef SHARED
bool consider_symbind = false;
+#ifdef SHARED
/* If we are auditing, install the same handlers we need for profiling. */
if ((reloc_mode & __RTLD_AUDIT) == 0)
{
@@ -227,9 +227,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
}
#elif defined PROF
/* Never use dynamic linker profiling for gprof profiling code. */
-# define consider_profiling 0
-#else
-# define consider_symbind 0
+ consider_profiling = 0;
#endif
/* If DT_BIND_NOW is set relocate all references in this object. We
@@ -287,7 +285,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc);
-#ifndef PROF
if ((consider_profiling || consider_symbind)
&& l->l_info[DT_PLTRELSZ] != NULL)
{
@@ -308,7 +305,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
_dl_fatal_printf (errstring, RTLD_PROGNAME, l->l_name);
}
}
-#endif
}
/* Mark the object so we know this work has been done. */

77
glibc-RHEL-48820-3.patch Normal file
View File

@ -0,0 +1,77 @@
commit f2326c2ec0a0a8db7bc7f4db8cce3002768fc3b6
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: Introduce _dl_relocate_object_no_relro
And make _dl_protect_relro apply RELRO conditionally.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index ded506da9e180eac..239f5505f805b008 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -189,12 +189,9 @@ _dl_nothread_init_static_tls (struct link_map *map)
#include "dynamic-link.h"
void
-_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
- int reloc_mode, int consider_profiling)
+_dl_relocate_object_no_relro (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;
@@ -325,17 +322,24 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
textrels = textrels->next;
}
-
- /* In case we can protect the data now that the relocations are
- done, do it. */
- if (l->l_relro_size != 0)
- _dl_protect_relro (l);
}
+void
+_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
+{
+ if (l->l_relocated)
+ return;
+ _dl_relocate_object_no_relro (l, scope, reloc_mode, consider_profiling);
+ _dl_protect_relro (l);
+}
void
_dl_protect_relro (struct link_map *l)
{
+ if (l->l_relro_size == 0)
+ return;
+
ElfW(Addr) start = ALIGN_DOWN((l->l_addr
+ l->l_relro_addr),
GLRO(dl_pagesize));
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 537d1293c7b5543b..dc4e0555e4ed7f3c 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1073,6 +1073,13 @@ extern void _dl_relocate_object (struct link_map *map,
int reloc_mode, int consider_profiling)
attribute_hidden;
+/* Perform relocation, but do not apply RELRO. Does not check
+ L->relocated. Otherwise the same as _dl_relocate_object. */
+void _dl_relocate_object_no_relro (struct link_map *map,
+ struct r_scope_elem *scope[],
+ int reloc_mode, int consider_profiling)
+ attribute_hidden;
+
/* Protect PT_GNU_RELRO area. */
extern void _dl_protect_relro (struct link_map *map) attribute_hidden;

203
glibc-RHEL-48820-4.patch Normal file
View File

@ -0,0 +1,203 @@
commit c1560f3f75c0e892b5522c16f91b4e303f677094
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 6 10:33:44 2024 +0100
elf: Switch to main malloc after final ld.so self-relocation
Before commit ee1ada1bdb8074de6e1bdc956ab19aef7b6a7872
("elf: Rework exception handling in the dynamic loader
[BZ #25486]"), the previous order called the main calloc
to allocate a shadow GOT/PLT array for auditing support.
This happened before libc.so.6 ELF constructors were run, so
a user malloc could run without libc.so.6 having been
initialized fully. One observable effect was that
environ was NULL at this point.
It does not seem to be possible at present to trigger such
an allocation, but it seems more robust to delay switching
to main malloc after ld.so self-relocation is complete.
The elf/tst-rtld-no-malloc-audit test case fails with a
2.34-era glibc that does not have this fix.
Reviewed-by: DJ Delorie <dj@redhat.com>
Conflicts:
elf/Makefile (fixup context)
elf/rtld.c (Align change with glibc-RHEL-48820-1)
diff --git a/elf/Makefile b/elf/Makefile
index 41adea8d1c6d13ca..0c8e0d794bac640f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -439,6 +439,9 @@ tests += \
tst-recursive-tls \
tst-relsort1 \
tst-ro-dynamic \
+ tst-rtld-no-malloc \
+ tst-rtld-no-malloc-audit \
+ tst-rtld-no-malloc-preload \
tst-rtld-run-static \
tst-single_threaded \
tst-single_threaded-pthread \
@@ -2896,3 +2899,9 @@ tst-tls22-mod2.so-no-z-defs = yes
tst-tls22-mod2-gnu2.so-no-z-defs = yes
$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
+
+# Reuse an audit module which provides ample debug logging.
+tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+# Any shared object should do.
+tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 1fea55c443505890..00abc2d8056c78b0 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -353,8 +353,7 @@ _dl_non_dynamic_init (void)
}
/* Setup relro on the binary itself. */
- if (_dl_main_map.l_relro_size != 0)
- _dl_protect_relro (&_dl_main_map);
+ _dl_protect_relro (&_dl_main_map);
}
#ifdef DL_SYSINFO_IMPLEMENTATION
diff --git a/elf/rtld.c b/elf/rtld.c
index 711bb77d70da6563..3436dd918e699080 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2495,26 +2495,23 @@ dl_main (const ElfW(Phdr) *phdr,
if (! prelinked)
{
- /* Re-relocate ourselves with user-controlled symbol definitions.
-
- We must do this after TLS initialization in case after this
- re-relocation, we might call a user-supplied function
- (e.g. calloc from _dl_relocate_object) that uses TLS data. */
-
- /* The malloc implementation has been relocated, so resolving
- its symbols (and potentially calling IFUNC resolvers) is safe
- at this point. */
- __rtld_malloc_init_real (main_map);
-
/* Likewise for the locking implementation. */
__rtld_mutex_init ();
+ /* Re-relocate ourselves with user-controlled symbol definitions. */
+
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
- /* Mark the link map as not yet relocated again. */
- GL(dl_rtld_map).l_relocated = 0;
- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+
+ /* The malloc implementation has been relocated, so resolving
+ its symbols (and potentially calling IFUNC resolvers) is safe
+ at this point. */
+ __rtld_malloc_init_real (main_map);
+
+ if (GL(dl_rtld_map).l_relro_size != 0)
+ _dl_protect_relro (&GL(dl_rtld_map));
rtld_timer_accum (&relocate_time, start);
}
diff --git a/elf/tst-rtld-no-malloc-audit.c b/elf/tst-rtld-no-malloc-audit.c
new file mode 100644
index 0000000000000000..a028377ad1fea027
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-audit.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc-preload.c b/elf/tst-rtld-no-malloc-preload.c
new file mode 100644
index 0000000000000000..a028377ad1fea027
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-preload.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc.c b/elf/tst-rtld-no-malloc.c
new file mode 100644
index 0000000000000000..5f24d4bd72c4af0c
--- /dev/null
+++ b/elf/tst-rtld-no-malloc.c
@@ -0,0 +1,76 @@
+/* Test that program loading does not call malloc.
+ Copyright (C) 2024 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>
+#include <unistd.h>
+
+static void
+print (const char *s)
+{
+ const char *end = s + strlen (s);
+ while (s < end)
+ {
+ ssize_t ret = write (STDOUT_FILENO, s, end - s);
+ if (ret <= 0)
+ _exit (2);
+ s += ret;
+ }
+}
+
+static void __attribute__ ((noreturn))
+unexpected_call (const char *function)
+{
+ print ("error: unexpected call to ");
+ print (function);
+ print ("\n");
+ _exit (1);
+}
+
+/* These are the malloc functions implement in elf/dl-minimal.c. */
+
+void
+free (void *ignored)
+{
+ unexpected_call ("free");
+}
+
+void *
+calloc (size_t ignored1, size_t ignored2)
+{
+ unexpected_call ("calloc");
+}
+
+void *
+malloc (size_t ignored)
+{
+ unexpected_call ("malloc");
+}
+
+void *
+realloc (void *ignored1, size_t ignored2)
+{
+ unexpected_call ("realloc");
+}
+
+int
+main (void)
+{
+ /* Do not use the test wrapper, to avoid spurious malloc calls from it. */
+ return 0;
+}

228
glibc-RHEL-48820-5.patch Normal file
View File

@ -0,0 +1,228 @@
commit 706209867f1ba89c458033408d419e92d8055f58
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Jan 7 09:18:07 2025 +0100
elf: Second ld.so relocation only if libc.so has been loaded
Commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf:
rtld_multiple_ref is always true”) removed some code that happened
to enable compatibility with programs that do not link against
libc.so. Such programs cannot call dlopen or any dynamic linker
functions (except __tls_get_addr), so this is not really useful.
Still ld.so should not crash with a null-pointer dereference
or undefined symbol reference in these cases.
In the main relocation loop, call _dl_relocate_object unconditionally
because it already checks if the object has been relocated.
If libc.so was loaded, self-relocate ld.so against it and call
__rtld_mutex_init and __rtld_malloc_init_real to activate the full
implementations. Those are available only if libc.so is there,
so skip these initialization steps if libc.so is absent. Without
libc.so, the global scope can be completely empty. This can cause
ld.so self-relocation to fail because if it uses symbol-based
relocations, which is why the second ld.so self-relocation is not
performed if libc.so is missing.
The previous concern regarding GOT updates through self-relocation
no longer applies because function pointers are updated
explicitly through __rtld_mutex_init and __rtld_malloc_init_real,
and not through relocation. However, the second ld.so self-relocation
is still delayed, in case there are other symbols being used.
Fixes commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf:
rtld_multiple_ref is always true”).
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
elf/Makefile (fixup context)
elf/rtld.c (
- Patch off due to prelink code
- "elf: Move _dl_rtld_map, _dl_rtld_audit_state out of GL" not
ported downstream
)
diff --git a/elf/Makefile b/elf/Makefile
index 0c8e0d794bac640f..d30f7f67e73a646e 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -2905,3 +2905,20 @@ tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
# Any shared object should do.
tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
+
+# These rules link and run the special elf/tst-nolink-libc-* tests if
+# a port adds them to the tests variables. Neither test variant is
+# linked against libc.so, but tst-nolink-libc-1 is linked against
+# ld.so. The test is always run directly, not under the dynamic
+# linker.
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
+$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so
+$(objpfx)tst-nolink-libc-1.out: $(objpfx)tst-nolink-libc-1 $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-linker=$(objpfx)ld.so
+$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
diff --git a/elf/rtld.c b/elf/rtld.c
index 3436dd918e699080..d3d9e6b904ac78fd 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2410,25 +2410,25 @@ dl_main (const ElfW(Phdr) *phdr,
}
else
{
- /* Now we have all the objects loaded. Relocate them all except for
- the dynamic linker itself. We do this in reverse order so that copy
- relocs of earlier objects overwrite the data written by later
- 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 relocations.
- Likewise for libc, which is relocated early to ensure that IFUNC
- resolvers in libc work. */
+ /* Now we have all the objects loaded. */
int consider_profiling = GLRO(dl_profile) != NULL;
/* If we are profiling we also must do lazy reloaction. */
GLRO(dl_lazy) |= consider_profiling;
+ /* If libc.so has been loaded, relocate it early, after the dynamic
+ loader itself. The initial self-relocation of ld.so should be
+ sufficient for IFUNC resolvers in libc.so. */
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);
+ {
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
+ _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);
+ rtld_timer_accum (&relocate_time, start);
+ }
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
@@ -2450,9 +2450,8 @@ dl_main (const ElfW(Phdr) *phdr,
/* Also allocated with the fake malloc(). */
l->l_free_initfini = 0;
- if (l != &GL(dl_rtld_map))
- _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
- consider_profiling);
+ _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
+ consider_profiling);
/* Add object to slot information data if necessasy. */
if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called)
@@ -2495,25 +2494,22 @@ dl_main (const ElfW(Phdr) *phdr,
if (! prelinked)
{
- /* Likewise for the locking implementation. */
- __rtld_mutex_init ();
-
- /* Re-relocate ourselves with user-controlled symbol definitions. */
-
- RTLD_TIMING_VAR (start);
- rtld_timer_start (&start);
-
- _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
-
- /* The malloc implementation has been relocated, so resolving
- its symbols (and potentially calling IFUNC resolvers) is safe
- at this point. */
- __rtld_malloc_init_real (main_map);
+ /* If libc.so was loaded, relocate ld.so against it. Complete ld.so
+ initialization with mutex symbols from libc.so and malloc symbols
+ from the global scope. */
+ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
+ {
+ RTLD_TIMING_VAR (start);
+ rtld_timer_start (&start);
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ rtld_timer_accum (&relocate_time, start);
- if (GL(dl_rtld_map).l_relro_size != 0)
- _dl_protect_relro (&GL(dl_rtld_map));
+ __rtld_mutex_init ();
+ __rtld_malloc_init_real (main_map);
+ }
- rtld_timer_accum (&relocate_time, start);
+ /* All ld.so initialization is complete. Apply RELRO. */
+ _dl_protect_relro (&GL(dl_rtld_map));
}
/* Relocation is complete. Perform early libc initialization. This
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 460ba54a8afcc515..94eb2665b27371a4 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -393,7 +393,15 @@ libof-lddlibc4 = lddlibc4
others += pldd
install-bin += pldd
$(objpfx)pldd: $(objpfx)xmalloc.o
+
+test-internal-extras += tst-nolink-libc
+ifeq ($(run-built-tests),yes)
+tests-special += \
+ $(objpfx)tst-nolink-libc-1.out \
+ $(objpfx)tst-nolink-libc-2.out \
+ # tests-special
endif
+endif # $(subdir) == elf
ifeq ($(subdir),rt)
CFLAGS-mq_send.c += -fexceptions
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile
index 32db854cbd6bdfd6..ab7ced85408ee515 100644
--- a/sysdeps/unix/sysv/linux/arm/Makefile
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
@@ -1,5 +1,8 @@
ifeq ($(subdir),elf)
sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
+# The test uses INTERNAL_SYSCALL_CALL. In thumb mode, this uses
+# an undefined reference to __libc_do_syscall.
+CFLAGS-tst-nolink-libc.c += -marm
endif
ifeq ($(subdir),misc)
diff --git a/sysdeps/unix/sysv/linux/tst-nolink-libc.c b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
new file mode 100644
index 0000000000000000..817f37784b4080f9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
@@ -0,0 +1,25 @@
+/* Test program not linked against libc.so and not using any glibc functions.
+ Copyright (C) 2024 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 <sysdep.h>
+
+void
+_start (void)
+{
+ INTERNAL_SYSCALL_CALL (exit_group, 0);
+}

28
glibc-RHEL-48820-6.patch Normal file
View File

@ -0,0 +1,28 @@
commit 39183f47d8bc9eda711c9797b18d69d7a02af91c
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Jan 8 16:55:31 2025 +0100
elf: Minimize library dependencies of tst-nolink-libc.c
On 32-bit Arm, -fasynchronous-unwind-tables creates a reference
to the symbol __aeabi_unwind_cpp_pr0. Compile the tests without
this flag even if it is passed as part of CC, to avoid linker
failures.
diff --git a/elf/Makefile b/elf/Makefile
index d30f7f67e73a646e..dc93f631a682a006 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -2910,8 +2910,10 @@ tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
# a port adds them to the tests variables. Neither test variant is
# linked against libc.so, but tst-nolink-libc-1 is linked against
# ld.so. The test is always run directly, not under the dynamic
-# linker.
-CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
+# linker. It is necessary to minimize run-time dependencies, by
+# disabling stack protection and unwinding.
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector) \
+ -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
$(LINK.o) -nostdlib -nostartfiles -o $@ $< \
-Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so

30
glibc-RHEL-48820-7.patch Normal file
View File

@ -0,0 +1,30 @@
commit d30f41d2c9031b0540641af692e56002eab5599f
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Jun 26 11:38:00 2025 +0200
elf: Add missing DSO dependencies for tst-rtld-no-malloc-{audit,preload}
Fixes commit c1560f3f75c0e892b5522c16f91b4e303f677094
("elf: Switch to main malloc after final ld.so self-relocation").
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
Conflicts:
elf/Makefile (fixup context)
diff --git a/elf/Makefile b/elf/Makefile
index dc93f631a682a006..15bec14364266c77 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -2902,9 +2902,11 @@ $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
# Reuse an audit module which provides ample debug logging.
tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+$(objpfx)tst-rtld-no-malloc-audit.out: $(objpfx)tst-auditmod1.so
# Any shared object should do.
tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
+$(objpfx)tst-rtld-no-malloc-preload.out: $(objpfx)tst-auditmod1.so
# These rules link and run the special elf/tst-nolink-libc-* tests if
# a port adds them to the tests variables. Neither test variant is

View File

@ -157,7 +157,7 @@ end \
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
Release: 207%{?dist}
Release: 208%{?dist}
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
# libraries.
@ -1245,6 +1245,13 @@ Patch936: glibc-RHEL-77082-5.patch
Patch937: glibc-RHEL-95546-1.patch
Patch938: glibc-RHEL-95546-2.patch
Patch939: glibc-RHEL-95546-3.patch
Patch940: glibc-RHEL-48820-1.patch
Patch941: glibc-RHEL-48820-2.patch
Patch942: glibc-RHEL-48820-3.patch
Patch943: glibc-RHEL-48820-4.patch
Patch944: glibc-RHEL-48820-5.patch
Patch945: glibc-RHEL-48820-6.patch
Patch946: glibc-RHEL-48820-7.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -3242,6 +3249,9 @@ update_gconv_modules_cache ()
%endif
%changelog
* Thu Jun 26 2025 Frédéric Bérat <fberat@redhat.com> - 2.34-208
- Switch to main malloc after final ld.so self-relocation. (RHEL-48820)
* Tue Jun 24 2025 Frédéric Bérat <fberat@redhat.com> - 2.34-207
- CVE-2025-5702 glibc: Vector register overwrite bug in glibc (RHEL-95546)