From 7a4b3191082ae16e83e29b7c2c600159a1b825e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20B=C3=A9rat?= Date: Wed, 18 Jun 2025 14:59:47 +0200 Subject: [PATCH] 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 --- glibc-RHEL-48820-1.patch | 120 +++++++++++++++++++++ glibc-RHEL-48820-2.patch | 52 +++++++++ glibc-RHEL-48820-3.patch | 77 +++++++++++++ glibc-RHEL-48820-4.patch | 203 ++++++++++++++++++++++++++++++++++ glibc-RHEL-48820-5.patch | 228 +++++++++++++++++++++++++++++++++++++++ glibc-RHEL-48820-6.patch | 28 +++++ glibc-RHEL-48820-7.patch | 30 ++++++ glibc.spec | 12 ++- 8 files changed, 749 insertions(+), 1 deletion(-) create mode 100644 glibc-RHEL-48820-1.patch create mode 100644 glibc-RHEL-48820-2.patch create mode 100644 glibc-RHEL-48820-3.patch create mode 100644 glibc-RHEL-48820-4.patch create mode 100644 glibc-RHEL-48820-5.patch create mode 100644 glibc-RHEL-48820-6.patch create mode 100644 glibc-RHEL-48820-7.patch diff --git a/glibc-RHEL-48820-1.patch b/glibc-RHEL-48820-1.patch new file mode 100644 index 0000000..bddab39 --- /dev/null +++ b/glibc-RHEL-48820-1.patch @@ -0,0 +1,120 @@ +commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f +Author: Florian Weimer +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 + +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 diff --git a/glibc-RHEL-48820-2.patch b/glibc-RHEL-48820-2.patch new file mode 100644 index 0000000..c6e1d07 --- /dev/null +++ b/glibc-RHEL-48820-2.patch @@ -0,0 +1,52 @@ +commit a79642204537dec8a1e1c58d1e0a074b3c624f46 +Author: Florian Weimer +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 + +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. */ diff --git a/glibc-RHEL-48820-3.patch b/glibc-RHEL-48820-3.patch new file mode 100644 index 0000000..79c7805 --- /dev/null +++ b/glibc-RHEL-48820-3.patch @@ -0,0 +1,77 @@ +commit f2326c2ec0a0a8db7bc7f4db8cce3002768fc3b6 +Author: Florian Weimer +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 + +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; + diff --git a/glibc-RHEL-48820-4.patch b/glibc-RHEL-48820-4.patch new file mode 100644 index 0000000..5933759 --- /dev/null +++ b/glibc-RHEL-48820-4.patch @@ -0,0 +1,203 @@ +commit c1560f3f75c0e892b5522c16f91b4e303f677094 +Author: Florian Weimer +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 + +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 ++ . */ ++ ++ ++#include ++#include ++ ++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; ++} diff --git a/glibc-RHEL-48820-5.patch b/glibc-RHEL-48820-5.patch new file mode 100644 index 0000000..7db94b9 --- /dev/null +++ b/glibc-RHEL-48820-5.patch @@ -0,0 +1,228 @@ +commit 706209867f1ba89c458033408d419e92d8055f58 +Author: Florian Weimer +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 + +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 ++ . */ ++ ++#include ++ ++void ++_start (void) ++{ ++ INTERNAL_SYSCALL_CALL (exit_group, 0); ++} diff --git a/glibc-RHEL-48820-6.patch b/glibc-RHEL-48820-6.patch new file mode 100644 index 0000000..5229bdb --- /dev/null +++ b/glibc-RHEL-48820-6.patch @@ -0,0 +1,28 @@ +commit 39183f47d8bc9eda711c9797b18d69d7a02af91c +Author: Florian Weimer +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 diff --git a/glibc-RHEL-48820-7.patch b/glibc-RHEL-48820-7.patch new file mode 100644 index 0000000..aa53365 --- /dev/null +++ b/glibc-RHEL-48820-7.patch @@ -0,0 +1,30 @@ +commit d30f41d2c9031b0540641af692e56002eab5599f +Author: Florian Weimer +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 + +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 diff --git a/glibc.spec b/glibc.spec index 135026b..7709b19 100644 --- a/glibc.spec +++ b/glibc.spec @@ -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 - 2.34-208 +- Switch to main malloc after final ld.so self-relocation. (RHEL-48820) + * Tue Jun 24 2025 Frédéric Bérat - 2.34-207 - CVE-2025-5702 glibc: Vector register overwrite bug in glibc (RHEL-95546)