You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
8.4 KiB
225 lines
8.4 KiB
5 months ago
|
commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec
|
||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||
|
Date: Mon Nov 27 11:28:13 2023 +0100
|
||
|
|
||
|
elf: Relocate libc.so early during startup and dlmopen (bug 31083)
|
||
|
|
||
|
This makes it more likely that objects without dependencies can
|
||
|
use IFUNC resolvers in libc.so.
|
||
|
|
||
|
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||
|
|
||
|
Conflicts:
|
||
|
elf/Makefile
|
||
|
(test backport differences)
|
||
|
elf/rtld.c
|
||
|
(prelink support was removed upstream)
|
||
|
|
||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||
|
index 8e1f91bcd917fd4e..7b7c6c171ce23247 100644
|
||
|
--- a/elf/Makefile
|
||
|
+++ b/elf/Makefile
|
||
|
@@ -419,6 +419,8 @@ tests += \
|
||
|
tst-nodelete2 \
|
||
|
tst-nodelete-dlclose \
|
||
|
tst-nodelete-opened \
|
||
|
+ tst-nodeps1 \
|
||
|
+ tst-nodeps2 \
|
||
|
tst-noload \
|
||
|
tst-null-argv \
|
||
|
tst-relsort1 \
|
||
|
@@ -777,6 +779,8 @@ modules-names = \
|
||
|
tst-nodelete-dlclose-dso \
|
||
|
tst-nodelete-dlclose-plugin \
|
||
|
tst-nodelete-opened-lib \
|
||
|
+ tst-nodeps1-mod \
|
||
|
+ tst-nodeps2-mod \
|
||
|
tst-null-argv-lib \
|
||
|
tst-relsort1mod1 \
|
||
|
tst-relsort1mod2 \
|
||
|
@@ -931,8 +935,15 @@ extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
|
||
|
|
||
|
# filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special
|
||
|
# rules.
|
||
|
-modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod \
|
||
|
- tst-audit24bmod1 tst-audit24bmod2
|
||
|
+modules-names-nobuild += \
|
||
|
+ filtmod1 \
|
||
|
+ tst-audit24bmod1 \
|
||
|
+ tst-audit24bmod2 \
|
||
|
+ tst-big-note-lib \
|
||
|
+ tst-nodeps1-mod \
|
||
|
+ tst-nodeps2-mod \
|
||
|
+ tst-ro-dynamic-mod \
|
||
|
+ # modules-names-nobuild
|
||
|
|
||
|
tests += $(tests-static)
|
||
|
|
||
|
@@ -2684,3 +2695,18 @@ LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed
|
||
|
$(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so
|
||
|
$(objpfx)tst-dlclose-lazy.out: \
|
||
|
$(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so
|
||
|
+
|
||
|
+# The object tst-nodeps1-mod.so has no explicit dependencies on libc.so.
|
||
|
+$(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os
|
||
|
+ $(LINK.o) -nostartfiles -nostdlib -shared -o $@ $^
|
||
|
+tst-nodeps1.so-no-z-defs = yes
|
||
|
+# Link libc.so before the test module with the IFUNC resolver reference.
|
||
|
+LDFLAGS-tst-nodeps1 = $(common-objpfx)libc.so $(objpfx)tst-nodeps1-mod.so
|
||
|
+$(objpfx)tst-nodeps1: $(objpfx)tst-nodeps1-mod.so
|
||
|
+# Reuse the tst-nodeps1 module. Link libc.so before the test module
|
||
|
+# with the IFUNC resolver reference.
|
||
|
+$(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \
|
||
|
+ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.os
|
||
|
+ $(LINK.o) -Wl,--no-as-needed -nostartfiles -nostdlib -shared -o $@ $^
|
||
|
+$(objpfx)tst-nodeps2.out: \
|
||
|
+ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so
|
||
|
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||
|
index cf3baccccb461878..4b58bdd668634130 100644
|
||
|
--- a/elf/dl-open.c
|
||
|
+++ b/elf/dl-open.c
|
||
|
@@ -705,6 +705,17 @@ dl_open_worker_begin (void *a)
|
||
|
them. However, such relocation dependencies in IFUNC resolvers
|
||
|
are undefined anyway, so this is not a problem. */
|
||
|
|
||
|
+ /* Ensure that libc is relocated first. This helps with the
|
||
|
+ execution of IFUNC resolvers in libc, and matters only to newly
|
||
|
+ created dlmopen namespaces. Do not do this for static dlopen
|
||
|
+ because libc has relocations against ld.so, which may not have
|
||
|
+ been relocated at this point. */
|
||
|
+#ifdef SHARED
|
||
|
+ if (GL(dl_ns)[args->nsid].libc_map != NULL)
|
||
|
+ _dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map,
|
||
|
+ reloc_mode, &relocation_in_progress);
|
||
|
+#endif
|
||
|
+
|
||
|
for (unsigned int i = last; i-- > first; )
|
||
|
_dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode,
|
||
|
&relocation_in_progress);
|
||
|
diff --git a/elf/rtld.c b/elf/rtld.c
|
||
|
index 9de53ccaed420a57..a638d14e77745baa 100644
|
||
|
--- a/elf/rtld.c
|
||
|
+++ b/elf/rtld.c
|
||
|
@@ -2421,11 +2421,17 @@ dl_main (const ElfW(Phdr) *phdr,
|
||
|
objects. We do not re-relocate the dynamic linker itself in this
|
||
|
loop because that could result in the GOT entries for functions we
|
||
|
call being changed, and that would break us. It is safe to relocate
|
||
|
- the dynamic linker out of order because it has no copy relocs (we
|
||
|
- know that because it is self-contained). */
|
||
|
+ the dynamic linker out of order because it has no copy relocations.
|
||
|
+ Likewise for libc, which is relocated early to ensure that IFUNC
|
||
|
+ resolvers in libc work. */
|
||
|
|
||
|
int consider_profiling = GLRO(dl_profile) != NULL;
|
||
|
|
||
|
+ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL)
|
||
|
+ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map,
|
||
|
+ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope,
|
||
|
+ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling);
|
||
|
+
|
||
|
/* If we are profiling we also must do lazy reloaction. */
|
||
|
GLRO(dl_lazy) |= consider_profiling;
|
||
|
|
||
|
diff --git a/elf/tst-nodeps1-mod.c b/elf/tst-nodeps1-mod.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..45c8e3c631251a89
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-nodeps1-mod.c
|
||
|
@@ -0,0 +1,25 @@
|
||
|
+/* Test module with no libc.so dependency and string function references.
|
||
|
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
|
+ This file is part of the GNU C Library.
|
||
|
+
|
||
|
+ The GNU C Library is free software; you can redistribute it and/or
|
||
|
+ modify it under the terms of the GNU Lesser General Public
|
||
|
+ License as published by the Free Software Foundation; either
|
||
|
+ version 2.1 of the License, or (at your option) any later version.
|
||
|
+
|
||
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ Lesser General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU Lesser General Public
|
||
|
+ License along with the GNU C Library; if not, see
|
||
|
+ <https://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+/* Some references to libc symbols which are likely to have IFUNC
|
||
|
+ resolvers. If they do not, this module does not exercise bug 31083. */
|
||
|
+void *memcpy_pointer = memcpy;
|
||
|
+void *memmove_pointer = memmove;
|
||
|
+void *memset_pointer = memset;
|
||
|
diff --git a/elf/tst-nodeps1.c b/elf/tst-nodeps1.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..1a8bde36cdb71446
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-nodeps1.c
|
||
|
@@ -0,0 +1,23 @@
|
||
|
+/* Test initially loaded module with implicit libc.so dependency (bug 31083).
|
||
|
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
|
+ This file is part of the GNU C Library.
|
||
|
+
|
||
|
+ The GNU C Library is free software; you can redistribute it and/or
|
||
|
+ modify it under the terms of the GNU Lesser General Public
|
||
|
+ License as published by the Free Software Foundation; either
|
||
|
+ version 2.1 of the License, or (at your option) any later version.
|
||
|
+
|
||
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ Lesser General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU Lesser General Public
|
||
|
+ License along with the GNU C Library; if not, see
|
||
|
+ <https://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* Testing happens before main. */
|
||
|
+int
|
||
|
+main (void)
|
||
|
+{
|
||
|
+}
|
||
|
diff --git a/elf/tst-nodeps2-mod.c b/elf/tst-nodeps2-mod.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..4913feee9b56e0e1
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-nodeps2-mod.c
|
||
|
@@ -0,0 +1 @@
|
||
|
+/* Empty test module which depends on tst-nodeps1-mod.so. */
|
||
|
diff --git a/elf/tst-nodeps2.c b/elf/tst-nodeps2.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..0bdc8eeb8cba3a99
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-nodeps2.c
|
||
|
@@ -0,0 +1,29 @@
|
||
|
+/* Test dlmopen with implicit libc.so dependency (bug 31083).
|
||
|
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||
|
+ This file is part of the GNU C Library.
|
||
|
+
|
||
|
+ The GNU C Library is free software; you can redistribute it and/or
|
||
|
+ modify it under the terms of the GNU Lesser General Public
|
||
|
+ License as published by the Free Software Foundation; either
|
||
|
+ version 2.1 of the License, or (at your option) any later version.
|
||
|
+
|
||
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ Lesser General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU Lesser General Public
|
||
|
+ License along with the GNU C Library; if not, see
|
||
|
+ <https://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+#include <support/xdlfcn.h>
|
||
|
+
|
||
|
+static int
|
||
|
+do_test (void)
|
||
|
+{
|
||
|
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-nodeps2-mod.so", RTLD_NOW);
|
||
|
+ xdlclose (handle);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+#include <support/test-driver.c>
|