From patchwork Sun Sep 29 16:36:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 1990620 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=PpCXFiCy; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XGqby1R4gz1xt9 for ; Mon, 30 Sep 2024 02:37:02 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 103C4385EC25 for ; Sun, 29 Sep 2024 16:37:00 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 44112385C6E3 for ; Sun, 29 Sep 2024 16:36:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 44112385C6E3 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 44112385C6E3 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1727627798; cv=none; b=n4r55scC3vVuaOE5QogEWBThSrtQ8KHBs37iSYAw1TEPvipgXwi6GhJ7nGuV/0SlG4jw7T8w6L9drtbZoDGIrxiwDEjxNp7xDtrDGWr5JhBRxm6OO+uumKCTWNmlESxWmfMvMq513fQrMj+yP8nhVOM/1kZL9muTywoF8zjK8Hw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1727627798; c=relaxed/simple; bh=HyhyzRLBdAYlo4bCIHWLGQrNQXWjqvmoQO89e0yQZ5E=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=n06WA1zBzmuZRI7e+RRw8RJhL834bCMBaEPM+BMqsXIdU2p7fz8Gu3F1gTUmwb1L6MV/HDA/BUfL1ylE2dmkYMR7hoLZh0QG2nA7I5EaV4VX/BG5MsY4jpbokastsfUl/BOwnZYEoSt1sbI2HPtomiiub3ZuhnmrmAYOKHAURCk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1727627796; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=2uMo6qtqvLzNRYS04QYyY3nZF3WngczoZms2ipqvDwA=; b=PpCXFiCyhTO6h8Zrzy5tMTUfcuLg9c1GQoAxCELU+fZiSiLOTLzCJutRPWwOEBHuXkroEE GCBt+1dtcfEkum5AVZAgg/kmGjgHKMwU7XhSWbkIz0qovCCSX+HJx6CaQOCBHzzrNT692R 6JVXOPYONDZr7Nhxklauptoh8E7iaBU= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-307-Gd-PQFSmNcu_jHowPaNbWQ-1; Sun, 29 Sep 2024 12:36:34 -0400 X-MC-Unique: Gd-PQFSmNcu_jHowPaNbWQ-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (unknown [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0179719344C2 for ; Sun, 29 Sep 2024 16:36:34 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.45.224.151]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0E80B19541A0 for ; Sun, 29 Sep 2024 16:36:32 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v3 24/29] elf: Handle ld.so with LOAD segment gaps in _dl_find_object (bug 31943) In-Reply-To: Message-ID: <86de3d1d9e32d296241d5939f1ffe07203672625.1727624528.git.fweimer@redhat.com> References: X-From-Line: 86de3d1d9e32d296241d5939f1ffe07203672625 Mon Sep 17 00:00:00 2001 Date: Sun, 29 Sep 2024 18:36:29 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org If binutils bug 28743 is present (if HAVE_LD_RELRO_LOAD_GAPS is defined), compile in code into ld.so that checks if ld.so has such gaps, and if so, update the _dl_find_object data structures accordingly. Likewise, if the architecture supports multiple page sizes, compile in the same code to support ld.so with gaps. --- elf/dl-find_object.c | 78 ++++++++++++++++++++++++++++---------------- elf/rtld.c | 28 +++++++++++++++- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c index 449302eda3..997cc0078b 100644 --- a/elf/dl-find_object.c +++ b/elf/dl-find_object.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Fallback implementation of _dl_find_object. It uses a linear search, needs locking, and is not async-signal-safe. It is used in @@ -466,6 +467,38 @@ __dl_find_object (void *pc1, struct dl_find_object *result) hidden_def (__dl_find_object) weak_alias (__dl_find_object, _dl_find_object) +/* Subroutine of _dlfo_process_initial to split out noncontigous link + maps. NODELETE is the number of used _dlfo_nodelete_mappings + elements. It is incremented as needed, and the new NODELETE value + is returned. */ +static size_t +_dlfo_process_initial_noncontiguous_map (struct link_map *map, + size_t nodelete) +{ + struct dl_find_object_internal dlfo; + _dl_find_object_from_map (map, &dlfo); + + /* PT_LOAD segments for a non-contiguous link map are added to the + non-closeable mappings. */ + const ElfW(Phdr) *ph = map->l_phdr; + const ElfW(Phdr) *ph_end = map->l_phdr + map->l_phnum; + for (; ph < ph_end; ++ph) + if (ph->p_type == PT_LOAD) + { + if (_dlfo_nodelete_mappings != NULL) + { + /* Second pass only. */ + _dlfo_nodelete_mappings[nodelete] = dlfo; + _dlfo_nodelete_mappings[nodelete].map_start + = ph->p_vaddr + map->l_addr; + _dlfo_nodelete_mappings[nodelete].map_end + = _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz; + } + ++nodelete; + } + return nodelete; +} + /* _dlfo_process_initial is called twice. First to compute the array sizes from the initial loaded mappings. Second to fill in the bases and infos arrays with the (still unsorted) data. Returns the @@ -477,29 +510,8 @@ _dlfo_process_initial (void) size_t nodelete = 0; if (!main_map->l_contiguous) - { - struct dl_find_object_internal dlfo; - _dl_find_object_from_map (main_map, &dlfo); - - /* PT_LOAD segments for a non-contiguous are added to the - non-closeable mappings. */ - for (const ElfW(Phdr) *ph = main_map->l_phdr, - *ph_end = main_map->l_phdr + main_map->l_phnum; - ph < ph_end; ++ph) - if (ph->p_type == PT_LOAD) - { - if (_dlfo_nodelete_mappings != NULL) - { - /* Second pass only. */ - _dlfo_nodelete_mappings[nodelete] = dlfo; - _dlfo_nodelete_mappings[nodelete].map_start - = ph->p_vaddr + main_map->l_addr; - _dlfo_nodelete_mappings[nodelete].map_end - = _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz; - } - ++nodelete; - } - } + /* Contiguous case already handled in _dl_find_object_init. */ + nodelete = _dlfo_process_initial_noncontiguous_map (main_map, nodelete); size_t loaded = 0; for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns) @@ -511,11 +523,21 @@ _dlfo_process_initial (void) /* lt_library link maps are implicitly NODELETE. */ if (l->l_type == lt_library || l->l_nodelete_active) { - if (_dlfo_nodelete_mappings != NULL) - /* Second pass only. */ - _dl_find_object_from_map - (l, _dlfo_nodelete_mappings + nodelete); - ++nodelete; +#if defined SHARED && (defined HAVE_LD_RELRO_LOAD_GAPS \ + || PAGE_SIZE_MIN != PAGE_SIZE_MAX) + /* The kernel may have loaded ld.so with gaps. */ + if (!l->l_contiguous && l == &GL(dl_rtld_map)) + nodelete + = _dlfo_process_initial_noncontiguous_map (l, nodelete); + else +#endif /* HAVE_LD_RELRO_LOAD_GAPS */ + { + if (_dlfo_nodelete_mappings != NULL) + /* Second pass only. */ + _dl_find_object_from_map + (l, _dlfo_nodelete_mappings + nodelete); + ++nodelete; + } } else if (l->l_type == lt_loaded) { diff --git a/elf/rtld.c b/elf/rtld.c index 50c01b9bb4..ac64e38346 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -1262,7 +1263,7 @@ rtld_setup_main_map (struct link_map *main_map) /* Set up the program header information for the dynamic linker itself. It can be accessed via _r_debug and dl_iterate_phdr - callbacks. */ + callbacks, and it is used by _dl_find_object. */ static void rtld_setup_phdr (void) { @@ -1279,6 +1280,31 @@ rtld_setup_phdr (void) GL(dl_rtld_map).l_phdr = rtld_phdr; GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum; + GL(dl_rtld_map).l_contiguous = 1; +#if defined HAVE_LD_RELRO_LOAD_GAPS || PAGE_SIZE_MIN != PAGE_SIZE_MAX + /* The linker may not have produced a contiguous object. The kernel + will load the object with actual gaps (unlike the glibc loader + for shared objects, which always produces a contiguous mapping). + See similar logic in rtld_setup_main_map above. */ + { + ElfW(Addr) expected_load_address = 0; + for (const ElfW(Phdr) *ph = rtld_phdr; ph < &rtld_phdr[rtld_ehdr->e_phnum]; + ++ph) + if (ph->p_type == PT_LOAD) + { + ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1); + if (GL(dl_rtld_map).l_contiguous && expected_load_address != 0 + && expected_load_address != mapstart) + GL(dl_rtld_map).l_contiguous = 0; + ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz; + /* The next expected address is the page following this load + segment. */ + expected_load_address = ((allocend + GLRO(dl_pagesize) - 1) + & ~(GLRO(dl_pagesize) - 1)); + } + } +#endif /* HAVE_LD_RELRO_LOAD_GAPS */ + /* PT_GNU_RELRO is usually the last phdr. */ size_t cnt = rtld_ehdr->e_phnum; while (cnt-- > 0)