From patchwork Thu Jun 27 14:43:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 1123405 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-103241-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="DUdwtxpx"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45ZN2L3JxMz9s4Y for ; Fri, 28 Jun 2019 00:44:10 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:mime-version :content-type; q=dns; s=default; b=GEQvLN69v3bNZ6IT6Qy3hiFuoQpTP mPdL3KdNXQHtxFTCN1vpieAY00YcCA27kUuHr4HYUJB5/nnYSFdPzmWYZCnNmd6f 0Axn+qp86bFcPrLmIECZzWYRhptBqQMzVCX/ID7Y9p8jIoZfa+MEKt1x1GEKgL6l 7bh3ZIhHzIC+LI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:mime-version :content-type; s=default; bh=h2Z6WkHgGJD+53/D9U+9u28fDsE=; b=DUd wtxpxn8VJQcpOmscIduf/HiwPDmQsPa8DgyJLZV45oqY3orIqruYs2u+dynDi7bd k9UtYuhLAHxkYKX0RNJnL9JMFK8dvBvnTU6DdI1CzCWyaSCjg1Opq9NhzM2e+Slb hoXFfr+3ft/jpUX0FiTdHr1ybFXFvnJTwEcY12O4= Received: (qmail 60944 invoked by alias); 27 Jun 2019 14:44:03 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 60934 invoked by uid 89); 27 Jun 2019 14:44:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-17.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, KAM_STOCKGEN, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=gone X-HELO: mx1.redhat.com From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH] ld.so: Support moving versioned symbols between sonames [BZ #24741] Date: Thu, 27 Jun 2019 16:43:56 +0200 Message-ID: <87woh7t7f7.fsf@oldenburg2.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) MIME-Version: 1.0 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 [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. Reviewed-by: Yann Droneaud Reviewed-by: Carlos O'Donell Reviewed-by: Carlos O'Donell 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, - ¤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 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 + . */ + +#include +#include +#include + +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 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 + . */ + +/* 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 + . */ + +/* 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 + . */ + +/* 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 + . */ + +/* 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 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