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:
parent
9d355805b4
commit
7a4b319108
120
glibc-RHEL-48820-1.patch
Normal file
120
glibc-RHEL-48820-1.patch
Normal 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
52
glibc-RHEL-48820-2.patch
Normal 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
77
glibc-RHEL-48820-3.patch
Normal 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
203
glibc-RHEL-48820-4.patch
Normal 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
228
glibc-RHEL-48820-5.patch
Normal 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
28
glibc-RHEL-48820-6.patch
Normal 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
30
glibc-RHEL-48820-7.patch
Normal 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
|
||||
12
glibc.spec
12
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 <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)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user