From patchwork Wed May 4 01:23:26 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Miller X-Patchwork-Id: 11998 Received: (qmail 107915 invoked by alias); 4 May 2016 01:23:43 -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 107902 invoked by uid 89); 4 May 2016 01:23:42 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy=demo, H*F:D*gmx.de, kde, breadth X-HELO: mout.gmx.net Date: Wed, 4 May 2016 03:23:26 +0200 From: Alexander Miller To: Subject: [PATCH] ld.so: Fix local scopes for prelink conflicts Message-ID: <20160504032326.57a639cb.alex.miller@gmx.de> MIME-Version: 1.0 X-UI-Out-Filterresults: notjunk:1; V01:K0:q+q9ltcNC1E=:cCLHkyBI5GAUGDSt9SF/PX dfh32upIAYrBnNUeU/dUh7Z7sJCwHPNxBP3dEFCTciJXl8rbmdO8wIr7TV4wmxMqUukXXw/cB eiERs/TUWetyyIiM49fP1GjyQBzhhQVF0ahGQR0NArRoVIsGWVylrrb7zQ+aG/UmlQVWwmK3e Cvoey75IkcNwaCECupPKlIJSZGPMMArczXoHIpIpN01nyGMFjzzzfsZeDzUVvLcX9sPgHE8O5 YSb8/Cmbq/gldBWIJnR4RCHM6s8W0OQPr86vTmK9AKsZJlM+x3Hvb9Rf7T/e42G2RtBoNKdw5 QMM9o44M0OC7xRm42wux1zC/nNSvFvrM4e5nBXVV3bUo9Zd7FYZ3KnmjNvjBon3ftS+AZIFWd JcMhbkrlbfA0+hLTSI2fIwZRMzPardGDgZy2dnb3SpHjaJ6xKlKsMcYXgNLQ/sYi6FTkVXfj9 y+TKaFgJZQjdOIGHJPKszgPKQoPyVcg2edJdvHJ19qbgZKTUrgTw7rg+BFzAYaZTPIuZVdInG TcMEYU8XECKiO3F/FUzKHDhl5NdffPAnqYJlq/V6FqgUhQhDZiiEUpWUs5hu4fJFWVUu8HHwT cJiqNQNTtoWzHCwzbp4mNrOiprMviHR5xU6A34diftdr1Cf8FnBZ2ULo1AErj1cyBBU/ToNKL k2Ew7mKiKJWNd9SNC0WwOgmlGN55oTrgYluDDiR/s4Jes/3OTuEK5yCBtnyDwOWAX2ciMrinK jpZztGN3ZzOM+X+sauejgjJBhZ0sKwRFLBtna39hkuJEtVtdsvHSsBNghSFAxm/yFsjaImEms UtDcWDY Hello folks, I've been investigating failures to start a KDE session on a prelinked system after updating glibc to version 2.22 [1]. I could track down the issue to a bug in the dynamic loader: the local scope for comparing symbol lookup in global scope vs. library scope when computing conflicts is not in the correct order. When we have the following situation: program +-- libA `-- libB +-- libC | `-- libA `-- libA2 where a symbol is provided by both libA and libA2, the symbol should be resolved to that of libA. When prelinking libB, there is no main program and libA2 precedes libA in the search scope; therefore libB gets prelinked to use libA2's symbol. That means the program needs a conflict fixup. But ld.so erroneously uses depth first search to compute libB's local scope; it sees libA before libA2 and doesn't report a conflict - bummer. I wrote a small example program that demonstrates the problem; it can be found here: The prelinked copy of the program and the original print different messages. (You can make a test case out of this.) Note that the bug has been present in glibc since prelink support was initially added in 2001 or so; the recent failures have been triggered by the conversion of conflicting symbols to IFUNCs. In my case it was fork from libpthread vs. libc. In the prelinked libkdeui, fork was resolved to libpthread's fork_resolve [2] and the fixup was missing for the affected KDE programs due to the bug. Before fork was converted to an IFUNC in libpthread the bug was not noticed. The patch below fixes the issues for me (and a few other people). It has been created against 2.22 but should work for current sources. I've attached it at [1] first and have been asked to post it here for discussion. Cheers, Alex Oh, for the legal stuff: you don't have a copyright assignment from me and I don't think you need one since the code itself is pretty small and trivial. To make it explicit: the patch below and the demo linked above can be used under the terms of CC0 [3]. [1] [2] I don't understand (yet) why this would make sense anyway. [3] -- >8 -- When computing conflict fixups for prelink, ld.so needs to be able to look up symbols in the local scopes of loaded libraries and compare them with the result in the global scope. The old implementation erroneously used depth first search to compute the local scopes. This could lead to conflicts being missed and therefore prelinked binaries malfunctioning. The new code builds the local scopes with breadth first search as required to get the same order that is used when prelinking the dependent libraries themselves. Changelog: * elf/dl-deps.c (_dl_build_local_scope): Use breadth first search to build list, in order to get the same search order that was used to prelink the library. --- glibc-2.22/elf/dl-deps.c +++ glibc-2.22/elf/dl-deps.c @@ -70,18 +70,23 @@ openaux (void *a) static ptrdiff_t internal_function _dl_build_local_scope (struct link_map **list, struct link_map *map) { - struct link_map **p = list; + size_t n = 0; + size_t m; struct link_map **q; - *p++ = map; + list[n++] = map; map->l_reserved = 1; - if (map->l_initfini) - for (q = map->l_initfini + 1; *q; ++q) - if (! (*q)->l_reserved) - p += _dl_build_local_scope (p, *q); - return p - list; + for (m = 0; m < n; ++m) + if (list[m]->l_initfini) + for (q = list[m]->l_initfini + 1; *q; ++q) + if (! (*q)->l_reserved) + { + list[n++] = *q; + (*q)->l_reserved = 1; + } + return n; } /* We use a very special kind of list to track the path