This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] 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.

2019-06-27  Florian Weimer  <fweimer@redhat.com>

	[BZ #24741]
	* elf/dl-lookup.c (do_lookup_x): Do not fail if there is a soname
	mismatch in a versioned symbol reference.
	(_dl_lookup_symbol_x): Do not report soname mismatch failures.
	* elf/Makefile [$(build-shared)] (tests): Add tst-sonamemove,
	tst-sonamemove-dlopen.
	(module-names): Add tst-sonamemove-linkmod1,
	tst-sonamemove-runmod1, tst-sonamemove-runmod2.
	(LDFLAGS-tst-sonamemove-linkmod1.so): Set.
	(LDFLAGS-tst-sonamemove-runmod1.so): Likewise.
	(LDFLAGS-tst-sonamemove-runmod2.so): Likewise.
	(tst-sonamemove-runmod1.so): Link against
	tst-sonamemove-runmod2.so.
	(tst-sonamemove): Link against tst-sonamemove-linkmod1.so.
	(tst-sonamemove.out): Depend on tst-sonamemove-runmod1.so,
	tst-sonamemove-runmod2.so.
	(tst-sonamemove-dlopen.out): Likewise.
	* elf/tst-sonamemove.c: New file.
	* elf/tst-sonamemove-dlopen.c: Likewise.
	* elf/tst-sonamemove-linkmod1.c: Likewise.
	* elf/tst-sonamemove-linkmod1.map: Likewise.
	* elf/tst-sonamemove-runmod1.c: Likewise.
	* elf/tst-sonamemove-runmod1.map: Likewise.
	* elf/tst-sonamemove-runmod2.c: Likewise.
	* elf/tst-sonamemove-runmod2.map: Likewise.
	* support/xdlfcn.h (xdlvsym): Declare function.
	* support/xdlfcn.c (xdlvsym): Define funciton.

diff --git a/NEWS b/NEWS
index 8a2fecef47..8cea9f5825 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,12 @@ Major new features:
   pointer subtraction within the allocated object, where results might
   overflow the ptrdiff_t type.
 
+* The dynamic linker no longer refuses to load objects which reference
+  versioned symbols whose implementation has moved to a different soname
+  since the object has been linked.  The old error message, symbol
+  FUNCTION-NAME, version SYMBOL-VERSION not defined in file DSO-NAME with
+  link time reference, is gone.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The functions clock_gettime, clock_getres, clock_settime,
diff --git a/elf/Makefile b/elf/Makefile
index 27a2fa8c14..76b0565054 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -191,7 +191,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 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-unwind-ctor tst-unwind-main tst-audit13
+	 tst-unwind-ctor tst-unwind-main tst-audit13 \
+	 tst-sonamemove tst-sonamemove-dlopen
 #	 reldep9
 tests-internal += loadtest unload unload2 circleload1 \
 	 neededtest neededtest2 neededtest3 neededtest4 \
@@ -281,7 +282,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		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-unwind-ctor-lib \
-		tst-audit13mod1
+		tst-audit13mod1 tst-sonamemove-linkmod1 \
+		tst-sonamemove-runmod1 tst-sonamemove-runmod2
 # Most modules build with _ISOMAC defined, but those filtered out
 # depend on internal headers.
 modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\
@@ -1410,6 +1412,28 @@ $(objpfx)tst-audit13.out: $(objpfx)tst-audit13mod1.so
 LDFLAGS-tst-audit13mod1.so = -Wl,-z,lazy
 tst-audit13-ENV = LD_AUDIT=$(objpfx)tst-audit13mod1.so
 
+# 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: $(objpfx)tst-sonamemove-linkmod1.so
+$(objpfx)tst-sonamemove.out: \
+  $(objpfx)tst-sonamemove-runmod1.so \
+  $(objpfx)tst-sonamemove-runmod2.so
+$(objpfx)tst-sonamemove-dlopen: $(libdl)
+$(objpfx)tst-sonamemove.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 e3f42a1efb..eb23cca4e3 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,
-			     &current_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,
+		     &current_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 0000000000..c496705044
--- /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-linkmod1.c b/elf/tst-sonamemove-linkmod1.c
new file mode 100644
index 0000000000..b8a354e5e3
--- /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 0000000000..8fe5904018
--- /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 0000000000..5c409e2289
--- /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 0000000000..2ea81c6e6f
--- /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 0000000000..b5e482eff5
--- /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 0000000000..8fe5904018
--- /dev/null
+++ b/elf/tst-sonamemove-runmod2.map
@@ -0,0 +1,3 @@
+SONAME_MOVE {
+  global: moved_function;
+};
diff --git a/elf/tst-sonamemove.c b/elf/tst-sonamemove.c
new file mode 100644
index 0000000000..a80ebcb36f
--- /dev/null
+++ b/elf/tst-sonamemove.c
@@ -0,0 +1,30 @@
+/* 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/>.  */
+
+/* moved_function is linked against tst-sonamemove-runmod1.so, but the
+   actual implementation is in tst-sonamemove-runmod1.so. */
+void moved_function (void);
+
+static int
+do_test (void)
+{
+  moved_function ();
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/xdlfcn.c b/support/xdlfcn.c
index b2e5c21134..11fe4896d1 100644
--- a/support/xdlfcn.c
+++ b/support/xdlfcn.c
@@ -51,6 +51,26 @@ xdlsym (void *handle, const char *symbol)
   return sym;
 }
 
+void *
+xdlvsym (void *handle, const char *symbol, const char *version)
+{
+  /* Clear any pending errors.  */
+  dlerror ();
+
+  void *sym = dlvsym (handle, symbol, version);
+
+  if (sym == NULL)
+    {
+      const char *error = dlerror ();
+      if (error != NULL)
+        FAIL_EXIT1 ("error: dlvsym: %s\n", error);
+      /* If there was no error, we found a NULL symbol.  Return the
+         NULL value in this case.  */
+    }
+
+  return sym;
+}
+
 void
 xdlclose (void *handle)
 {
diff --git a/support/xdlfcn.h b/support/xdlfcn.h
index c9cd810a8a..7f8d4930fc 100644
--- a/support/xdlfcn.h
+++ b/support/xdlfcn.h
@@ -27,6 +27,7 @@ __BEGIN_DECLS
 void *xdlopen (const char *filename, int flags);
 void *xdlmopen (Lmid_t lmid, const char *filename, int flags);
 void *xdlsym (void *handle, const char *symbol);
+void *xdlvsym (void *handle, const char *symbol, const char *version);
 void xdlclose (void *handle);
 
 __END_DECLS


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]