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.
343 lines
13 KiB
343 lines
13 KiB
9 months ago
|
commit f0b2132b35248c1f4a80f62a2c38cddcc802aa8c
|
||
|
Author: Florian Weimer <fweimer@redhat.com>
|
||
|
Date: Fri Jun 28 10:12:50 2019 +0200
|
||
|
|
||
|
ld.so: Support moving versioned symbols between sonames [BZ #24741]
|
||
|
|
||
|
This change should be fully backwards-compatible because the old
|
||
|
code aborted the load if a soname mismatch was encountered
|
||
|
(instead of searching further for a matching symbol). This means
|
||
|
that no different symbols are found.
|
||
|
|
||
|
The soname check was explicitly disabled for the skip_map != NULL
|
||
|
case. However, this only happens with dl(v)sym and RTLD_NEXT,
|
||
|
and those lookups do not come with a verneed entry that could be used
|
||
|
for the check.
|
||
|
|
||
|
The error check was already explicitly disabled for the skip_map !=
|
||
|
NULL case, that is, when dl(v)sym was called with RTLD_NEXT. But
|
||
|
_dl_vsym always sets filename in the struct r_found_version argument
|
||
|
to NULL, so the check was not active anyway. This means that
|
||
|
symbol lookup results for the skip_map != NULL case do not change,
|
||
|
either.
|
||
|
|
||
|
Conflicts:
|
||
|
elf/Makefile
|
||
|
(usual missing backports)
|
||
|
|
||
|
diff --git a/elf/Makefile b/elf/Makefile
|
||
|
index 29aa3a96738e4176..73f9e25ea5efd63a 100644
|
||
|
--- a/elf/Makefile
|
||
|
+++ b/elf/Makefile
|
||
|
@@ -187,7 +187,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||
|
tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
|
||
|
tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
|
||
|
tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
|
||
|
- tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note
|
||
|
+ tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
|
||
|
+ tst-sonamemove-link tst-sonamemove-dlopen
|
||
|
# reldep9
|
||
|
tests-internal += loadtest unload unload2 circleload1 \
|
||
|
neededtest neededtest2 neededtest3 neededtest4 \
|
||
|
@@ -275,7 +276,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||
|
tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
|
||
|
tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
|
||
|
tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
|
||
|
- tst-absolute-zero-lib tst-big-note-lib
|
||
|
+ tst-absolute-zero-lib tst-big-note-lib \
|
||
|
+ tst-sonamemove-linkmod1 \
|
||
|
+ tst-sonamemove-runmod1 tst-sonamemove-runmod2
|
||
|
|
||
|
ifeq (yes,$(have-mtls-dialect-gnu2))
|
||
|
tests += tst-gnu2-tls1
|
||
|
@@ -1374,6 +1377,28 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so
|
||
|
$(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so
|
||
|
LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map
|
||
|
|
||
|
+# tst-sonamemove links against an older implementation of the library.
|
||
|
+LDFLAGS-tst-sonamemove-linkmod1.so = \
|
||
|
+ -Wl,--version-script=tst-sonamemove-linkmod1.map \
|
||
|
+ -Wl,-soname,tst-sonamemove-runmod1.so
|
||
|
+LDFLAGS-tst-sonamemove-runmod1.so = -Wl,--no-as-needed \
|
||
|
+ -Wl,--version-script=tst-sonamemove-runmod1.map \
|
||
|
+ -Wl,-soname,tst-sonamemove-runmod1.so
|
||
|
+LDFLAGS-tst-sonamemove-runmod2.so = \
|
||
|
+ -Wl,--version-script=tst-sonamemove-runmod2.map \
|
||
|
+ -Wl,-soname,tst-sonamemove-runmod2.so
|
||
|
+$(objpfx)tst-sonamemove-runmod1.so: $(objpfx)tst-sonamemove-runmod2.so
|
||
|
+# Link against the link module, but depend on the run-time modules
|
||
|
+# for execution.
|
||
|
+$(objpfx)tst-sonamemove-link: $(objpfx)tst-sonamemove-linkmod1.so
|
||
|
+$(objpfx)tst-sonamemove-link.out: \
|
||
|
+ $(objpfx)tst-sonamemove-runmod1.so \
|
||
|
+ $(objpfx)tst-sonamemove-runmod2.so
|
||
|
+$(objpfx)tst-sonamemove-dlopen: $(libdl)
|
||
|
+$(objpfx)tst-sonamemove-dlopen.out: \
|
||
|
+ $(objpfx)tst-sonamemove-runmod1.so \
|
||
|
+ $(objpfx)tst-sonamemove-runmod2.so
|
||
|
+
|
||
|
# Override -z defs, so that we can reference an undefined symbol.
|
||
|
# Force lazy binding for the same reason.
|
||
|
LDFLAGS-tst-latepthreadmod.so = \
|
||
|
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
|
||
|
index 68ecc6179f608547..1d046caf017b582b 100644
|
||
|
--- a/elf/dl-lookup.c
|
||
|
+++ b/elf/dl-lookup.c
|
||
|
@@ -536,11 +536,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
|
||
|
}
|
||
|
|
||
|
skip:
|
||
|
- /* If this current map is the one mentioned in the verneed entry
|
||
|
- and we have not found a weak entry, it is a bug. */
|
||
|
- if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
|
||
|
- && __glibc_unlikely (_dl_name_match_p (version->filename, map)))
|
||
|
- return -1;
|
||
|
+ ;
|
||
|
}
|
||
|
while (++i < n);
|
||
|
|
||
|
@@ -810,34 +806,10 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
|
||
|
|
||
|
/* Search the relevant loaded objects for a definition. */
|
||
|
for (size_t start = i; *scope != NULL; start = 0, ++scope)
|
||
|
- {
|
||
|
- int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
|
||
|
- ¤t_value, *scope, start, version, flags,
|
||
|
- skip_map, type_class, undef_map);
|
||
|
- if (res > 0)
|
||
|
- break;
|
||
|
-
|
||
|
- if (__glibc_unlikely (res < 0) && skip_map == NULL)
|
||
|
- {
|
||
|
- /* Oh, oh. The file named in the relocation entry does not
|
||
|
- contain the needed symbol. This code is never reached
|
||
|
- for unversioned lookups. */
|
||
|
- assert (version != NULL);
|
||
|
- const char *reference_name = undef_map ? undef_map->l_name : "";
|
||
|
- struct dl_exception exception;
|
||
|
- /* XXX We cannot translate the message. */
|
||
|
- _dl_exception_create_format
|
||
|
- (&exception, DSO_FILENAME (reference_name),
|
||
|
- "symbol %s version %s not defined in file %s"
|
||
|
- " with link time reference%s",
|
||
|
- undef_name, version->name, version->filename,
|
||
|
- res == -2 ? " (no version symbols)" : "");
|
||
|
- _dl_signal_cexception (0, &exception, N_("relocation error"));
|
||
|
- _dl_exception_free (&exception);
|
||
|
- *ref = NULL;
|
||
|
- return 0;
|
||
|
- }
|
||
|
- }
|
||
|
+ if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
|
||
|
+ ¤t_value, *scope, start, version, flags,
|
||
|
+ skip_map, type_class, undef_map) != 0)
|
||
|
+ break;
|
||
|
|
||
|
if (__glibc_unlikely (current_value.s == NULL))
|
||
|
{
|
||
|
diff --git a/elf/tst-sonamemove-dlopen.c b/elf/tst-sonamemove-dlopen.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..c496705044cdd53c
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-dlopen.c
|
||
|
@@ -0,0 +1,35 @@
|
||
|
+/* Check that a moved versioned symbol can be found using dlsym, dlvsym.
|
||
|
+ Copyright (C) 2019 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
|
||
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+#include <stddef.h>
|
||
|
+#include <support/check.h>
|
||
|
+#include <support/xdlfcn.h>
|
||
|
+
|
||
|
+static int
|
||
|
+do_test (void)
|
||
|
+{
|
||
|
+ /* tst-sonamemove-runmod1.so does not define moved_function, but it
|
||
|
+ depends on tst-sonamemove-runmod2.so, which does. */
|
||
|
+ void *handle = xdlopen ("tst-sonamemove-runmod1.so", RTLD_NOW);
|
||
|
+ TEST_VERIFY (xdlsym (handle, "moved_function") != NULL);
|
||
|
+ TEST_VERIFY (xdlvsym (handle, "moved_function", "SONAME_MOVE") != NULL);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+#include <support/test-driver.c>
|
||
|
diff --git a/elf/tst-sonamemove-link.c b/elf/tst-sonamemove-link.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..4bc3bf32f88f97a9
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-link.c
|
||
|
@@ -0,0 +1,41 @@
|
||
|
+/* Check that a versioned symbol can move from one library to another.
|
||
|
+ Copyright (C) 2019 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
|
||
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* At link time, moved_function is bound to the symbol version
|
||
|
+ SONAME_MOVE in tst-sonamemove-runmod1.so, using the
|
||
|
+ tst-sonamemove-linkmod1.so stub object.
|
||
|
+
|
||
|
+ At run time, the process loads the real tst-sonamemove-runmod1.so,
|
||
|
+ which depends on tst-sonamemove-runmod2.so.
|
||
|
+ tst-sonamemove-runmod1.so does not define moved_function, but
|
||
|
+ tst-sonamemove-runmod2.so does.
|
||
|
+
|
||
|
+ The net effect is that the versioned symbol
|
||
|
+ moved_function@SONAME_MOVE moved from the soname
|
||
|
+ tst-sonamemove-linkmod1.so at link time to the soname
|
||
|
+ tst-sonamemove-linkmod2.so at run time. */
|
||
|
+void moved_function (void);
|
||
|
+
|
||
|
+static int
|
||
|
+do_test (void)
|
||
|
+{
|
||
|
+ moved_function ();
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+#include <support/test-driver.c>
|
||
|
diff --git a/elf/tst-sonamemove-linkmod1.c b/elf/tst-sonamemove-linkmod1.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..b8a354e5e394f566
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-linkmod1.c
|
||
|
@@ -0,0 +1,25 @@
|
||
|
+/* Link interface for (lack of) soname matching in versioned symbol refs.
|
||
|
+ Copyright (C) 2019 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
|
||
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* This function moved from tst-sonamemove-runmod1.so. This module is
|
||
|
+ intended for linking only, to simulate an old application which was
|
||
|
+ linked against an older version of the library. */
|
||
|
+void
|
||
|
+moved_function (void)
|
||
|
+{
|
||
|
+}
|
||
|
diff --git a/elf/tst-sonamemove-linkmod1.map b/elf/tst-sonamemove-linkmod1.map
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..8fe5904018972009
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-linkmod1.map
|
||
|
@@ -0,0 +1,3 @@
|
||
|
+SONAME_MOVE {
|
||
|
+ global: moved_function;
|
||
|
+};
|
||
|
diff --git a/elf/tst-sonamemove-runmod1.c b/elf/tst-sonamemove-runmod1.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..5c409e22898bc836
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-runmod1.c
|
||
|
@@ -0,0 +1,23 @@
|
||
|
+/* Run-time module whose moved_function moved to a library dependency.
|
||
|
+ Copyright (C) 2019 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
|
||
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* Dummy function to add the required symbol version. */
|
||
|
+void
|
||
|
+other_function (void)
|
||
|
+{
|
||
|
+}
|
||
|
diff --git a/elf/tst-sonamemove-runmod1.map b/elf/tst-sonamemove-runmod1.map
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..2ea81c6e6ffae2be
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-runmod1.map
|
||
|
@@ -0,0 +1,3 @@
|
||
|
+SONAME_MOVE {
|
||
|
+ global: other_function;
|
||
|
+};
|
||
|
diff --git a/elf/tst-sonamemove-runmod2.c b/elf/tst-sonamemove-runmod2.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..b5e482eff57d7d83
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-runmod2.c
|
||
|
@@ -0,0 +1,24 @@
|
||
|
+/* Run-time module with the actual implementation of moved_function.
|
||
|
+ Copyright (C) 2019 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
|
||
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* In the test scenario, this function was originally in
|
||
|
+ tst-sonamemove-runmod1.so. */
|
||
|
+void
|
||
|
+moved_function (void)
|
||
|
+{
|
||
|
+}
|
||
|
diff --git a/elf/tst-sonamemove-runmod2.map b/elf/tst-sonamemove-runmod2.map
|
||
|
new file mode 100644
|
||
|
index 0000000000000000..8fe5904018972009
|
||
|
--- /dev/null
|
||
|
+++ b/elf/tst-sonamemove-runmod2.map
|
||
|
@@ -0,0 +1,3 @@
|
||
|
+SONAME_MOVE {
|
||
|
+ global: moved_function;
|
||
|
+};
|