| 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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -0,0 +1,3 @@ |
| +SONAME_MOVE { |
| + global: moved_function; |
| +}; |