Upstream commit: fffc2df8a3e2c8cda2991063d23086360268b777 - i386: Provide GLIBC_ABI_GNU_TLS symbol version [BZ #33221] - i386: Update ___tls_get_addr to preserve vector registers - Extend struct r_debug to support multiple namespaces (RHEL-101985) - Fix a potential crash in the dynamic loader when processing specific symbol versions (RHEL-109683) - Signal la_objopen for ld.so with dlmopen (RHEL-109693) - Switch to main malloc after final ld.so self-relocation (RHEL-109703) - Prevent ld.so from asserting and crashing during audited library loads (RHEL-109702) - x86-64: Provide GLIBC_ABI_DT_X86_64_PLT symbol version (RHEL-109621) - x86-64, i386: Provide GLIBC_ABI_GNU2_TLS symbol version (RHEL-109625) - Ensure fallback initialization of ctype TLS data pointers to fix segfaults in programs using dlmopen or auditors (RHEL-72018) - Handle load segment gaps in _dl_find_object (RHEL-104854) - AArch64: Improve codegen in SVE log1p - AArch64: Optimize inverse trig functions - AArch64: Avoid memset ifunc in cpu-features.c [BZ #33112] Resolves: RHEL-109536 Resolves: RHEL-72018 Resolves: RHEL-101985 Resolves: RHEL-104854 Resolves: RHEL-109621 Resolves: RHEL-109625 Resolves: RHEL-109683 Resolves: RHEL-109693 Resolves: RHEL-109702 Resolves: RHEL-109703
224 lines
9.0 KiB
Diff
224 lines
9.0 KiB
Diff
commit 5f5c411132676d4c5eb171354c51b62baea27493
|
|
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>
|
|
(cherry picked from commit 706209867f1ba89c458033408d419e92d8055f58)
|
|
|
|
diff --git a/elf/Makefile b/elf/Makefile
|
|
index 91fd05c9c0e6084a..59de78a5d45bced4 100644
|
|
--- a/elf/Makefile
|
|
+++ b/elf/Makefile
|
|
@@ -3161,3 +3161,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 ff938186738e8a87..809fc807989b285e 100644
|
|
--- a/elf/rtld.c
|
|
+++ b/elf/rtld.c
|
|
@@ -2290,25 +2290,25 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
|
|
_rtld_main_check (main_map, _dl_argv[0]);
|
|
|
|
- /* 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);
|
|
@@ -2331,9 +2331,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)
|
|
@@ -2371,27 +2370,22 @@ dl_main (const ElfW(Phdr) *phdr,
|
|
/* Set up the object lookup structures. */
|
|
_dl_find_object_init ();
|
|
|
|
- /* 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
|
|
is the initial libc, even if audit modules have been loaded with
|
|
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
|
index b0daa44b95db3b72..a4b692febb3e87d9 100644
|
|
--- a/sysdeps/unix/sysv/linux/Makefile
|
|
+++ b/sysdeps/unix/sysv/linux/Makefile
|
|
@@ -657,7 +657,15 @@ install-bin += \
|
|
# install-bin
|
|
|
|
$(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 a73c897f43c9a206..e73ce4f81114e789 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);
|
|
+}
|