From patchwork Mon May 8 14:25:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 68912 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 654A63858005 for ; Mon, 8 May 2023 14:27:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 654A63858005 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1683556023; bh=IGVNnEBaRJpDBlUFAZ6YtJOXBKJmw2kTkHR6k/y10r0=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=A9QsF0J7X8yC8v9X7tB9nFzTNpa/+v+ff29Ga5M4SDnpT6vAZJHwWOhHoRQxBRflN MQiEhxLXPPa/WsbNyHQNjNwuQGqtrYWLfaTuet3+ZOBZnHMfEo6XHPjnCXcDG53BB/ KMybN4diRHCdJPSBYm0joX4Yak1HnLw9MBS8re8M= 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.133.124]) by sourceware.org (Postfix) with ESMTPS id 32493385783F for ; Mon, 8 May 2023 14:26:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 32493385783F Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-182-H5f4wAykMhyM52rCyJDs9w-1; Mon, 08 May 2023 10:26:00 -0400 X-MC-Unique: H5f4wAykMhyM52rCyJDs9w-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 96FC7100F64F for ; Mon, 8 May 2023 14:26:00 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.2.16.35]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EE638492C13 for ; Mon, 8 May 2023 14:25:59 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH v4 1/3] elf: Introduce separate _r_debug_array variable In-Reply-To: References: X-From-Line: 81a27471520093571d644eb7533fa5357f7395e7 Mon Sep 17 00:00:00 2001 Message-Id: <81a27471520093571d644eb7533fa5357f7395e7.1683555718.git.fweimer@redhat.com> Date: Mon, 08 May 2023 16:25:58 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" It replaces the ns_debug member of the namespaces. Previously, the base namespace had an unused ns_debug member. This change also fixes a concurrency issue: Now _dl_debug_initialize only updates r_next of the previous namespace's r_debug after the new r_debug is initialized, so that only the initialized version is observed. (Client code accessing _r_debug will benefit from load dependency tracking in CPUs even without explicit barriers.) --- elf/dl-debug.c | 91 +++++++++++++++++++++----------------- sysdeps/generic/ldsodefs.h | 2 - 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/elf/dl-debug.c b/elf/dl-debug.c index bd7b1cc8f7..88cccfa756 100644 --- a/elf/dl-debug.c +++ b/elf/dl-debug.c @@ -30,17 +30,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr) && VERIFY_MEMBER (l_prev)) ? 1 : -1]; +#ifdef SHARED +/* r_debug structs for secondary namespaces. The first namespace is + handled separately because its r_debug structure must overlap with + the public _r_debug symbol, so the first array element corresponds + to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */ +struct r_debug_extended _r_debug_array[DL_NNS - 1]; + +/* Return the r_debug object for the namespace NS. */ +static inline struct r_debug_extended * +get_rdebug (Lmid_t ns) +{ + if (ns == LM_ID_BASE) + return &_r_debug_extended; + else + return &_r_debug_array[ns - 1]; +} +#else /* !SHARED */ +static inline struct r_debug_extended * +get_rdebug (Lmid_t ns) +{ + return &_r_debug_extended; /* There is just one namespace. */ +} +#endif /* !SHARED */ + /* Update the `r_map' member and return the address of `struct r_debug' of the namespace NS. */ struct r_debug * _dl_debug_update (Lmid_t ns) { - struct r_debug_extended *r; - if (ns == LM_ID_BASE) - r = &_r_debug_extended; - else - r = &GL(dl_ns)[ns]._ns_debug; + struct r_debug_extended *r = get_rdebug (ns); if (r->base.r_map == NULL) atomic_store_release (&r->base.r_map, (void *) GL(dl_ns)[ns]._ns_loaded); @@ -54,34 +74,7 @@ _dl_debug_update (Lmid_t ns) struct r_debug * _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) { - struct r_debug_extended *r, **pp = NULL; - - if (ns == LM_ID_BASE) - { - r = &_r_debug_extended; - /* Initialize r_version to 1. */ - if (_r_debug_extended.base.r_version == 0) - _r_debug_extended.base.r_version = 1; - } - else if (DL_NNS > 1) - { - r = &GL(dl_ns)[ns]._ns_debug; - if (r->base.r_brk == 0) - { - /* Add the new namespace to the linked list. After a namespace - is initialized, r_brk becomes non-zero. A namespace becomes - empty (r_map == NULL) when it is unused. But it is never - removed from the linked list. */ - struct r_debug_extended *p; - for (pp = &_r_debug_extended.r_next; - (p = *pp) != NULL; - pp = &p->r_next) - ; - - r->base.r_version = 2; - } - } - + struct r_debug_extended *r = get_rdebug (ns); if (r->base.r_brk == 0) { /* Tell the debugger where to find the map of loaded objects. @@ -89,20 +82,36 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) only once. */ r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase; r->base.r_brk = (ElfW(Addr)) &_dl_debug_state; - r->r_next = NULL; + +#ifdef SHARED + /* Add the new namespace to the linked list. This assumes that + namespaces are allocated in increasing order. After a + namespace is initialized, r_brk becomes non-zero. A + namespace becomes empty (r_map == NULL) when it is unused. + But it is never removed from the linked list. */ + + if (ns != LM_ID_BASE) + { + r->base.r_version = 2; + if (ns - 1 == LM_ID_BASE) + { + atomic_store_release (&_r_debug_extended.r_next, r); + /* Now there are multiple namespaces. */ + atomic_store_release (&_r_debug_extended.base.r_version, 2); + } + else + /* Update r_debug_extended of the previous namespace. */ + atomic_store_release (&_r_debug_array[ns - 2].r_next, r); + } + else +#endif /* SHARED */ + r->base.r_version = 1; } if (r->base.r_map == NULL) atomic_store_release (&r->base.r_map, (void *) GL(dl_ns)[ns]._ns_loaded); - if (pp != NULL) - { - atomic_store_release (pp, r); - /* Bump r_version to 2 for the new namespace. */ - atomic_store_release (&_r_debug_extended.base.r_version, 2); - } - return &r->base; } diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index ba53176296..1c0593465d 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -350,8 +350,6 @@ struct rtld_global size_t n_elements; void (*free) (void *); } _ns_unique_sym_table; - /* Keep track of changes to each namespace' list. */ - struct r_debug_extended _ns_debug; } _dl_ns[DL_NNS]; /* One higher than index of last used namespace. */ EXTERN size_t _dl_nns; From patchwork Mon May 8 14:26:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 68913 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 48D33385843E for ; Mon, 8 May 2023 14:27:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 48D33385843E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1683556065; bh=T/KkUK3bymtzIKLuTxkYZdeO8yba8iD7gIHo466r6nU=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=HkL3Yi9dWO3yXp71DysZ0iqyluGAlxWqcs4vsDDQzgl6+rqlG1w94cvcTKsrfsuNf 4QR2L2vP0v6i8RABkx5DZwN+jv8Rylzh3VA79YwyyXH9GH51O7hJJ2V7V4VTlutdmZ mX63yCy00Undw6gjy+Qu1+O2G8bPse27Is/lOoWQ= 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 ESMTPS id D79C63858417 for ; Mon, 8 May 2023 14:26:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D79C63858417 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-529-Jue5wjIxMRmOwlha2fRhtw-1; Mon, 08 May 2023 10:26:04 -0400 X-MC-Unique: Jue5wjIxMRmOwlha2fRhtw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4B4C287DC10 for ; Mon, 8 May 2023 14:26:04 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.2.16.35]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 989F81121315 for ; Mon, 8 May 2023 14:26:03 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH v4 2/3] elf: Introduce _dl_debug_change_state In-Reply-To: References: X-From-Line: 9a2226dafe3df761df61c19b77d7c7f2191ecac6 Mon Sep 17 00:00:00 2001 Message-Id: <9a2226dafe3df761df61c19b77d7c7f2191ecac6.1683555718.git.fweimer@redhat.com> Date: Mon, 08 May 2023 16:26:01 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" It combines updating r_state with the debugger notification. The change to _dl_open introduces an additional debugger notification for dlmopen, but debuggers are expected to ignore it. --- elf/dl-close.c | 6 ++---- elf/dl-debug.c | 7 +++++++ elf/dl-load.c | 3 +-- elf/dl-open.c | 5 ++--- elf/rtld.c | 6 ++---- sysdeps/generic/ldsodefs.h | 14 ++++++++++++-- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/elf/dl-close.c b/elf/dl-close.c index b887a44888..27fd187385 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -420,8 +420,7 @@ _dl_close_worker (struct link_map *map, bool force) /* Notify the debugger we are about to remove some loaded objects. */ struct r_debug *r = _dl_debug_update (nsid); - r->r_state = RT_DELETE; - _dl_debug_state (); + _dl_debug_change_state (r, RT_DELETE); LIBC_PROBE (unmap_start, 2, nsid, r); if (unload_global) @@ -725,8 +724,7 @@ _dl_close_worker (struct link_map *map, bool force) while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL); /* Notify the debugger those objects are finalized and gone. */ - r->r_state = RT_CONSISTENT; - _dl_debug_state (); + _dl_debug_change_state (r, RT_CONSISTENT); LIBC_PROBE (unmap_complete, 2, nsid, r); /* Recheck if we need to retry, release the lock. */ diff --git a/elf/dl-debug.c b/elf/dl-debug.c index 88cccfa756..9d05e553d7 100644 --- a/elf/dl-debug.c +++ b/elf/dl-debug.c @@ -67,6 +67,13 @@ _dl_debug_update (Lmid_t ns) return &r->base; } +void +_dl_debug_change_state (struct r_debug *r, int state) +{ + atomic_store_release (&r->r_state, state); + _dl_debug_state (); +} + /* Initialize _r_debug_extended for the namespace NS. LDBASE is the run-time load address of the dynamic linker, to be put in _r_debug_extended.r_ldbase. Return the address of _r_debug. */ diff --git a/elf/dl-load.c b/elf/dl-load.c index 9a0e40c0e9..8364f6532c 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1498,8 +1498,7 @@ cannot enable executable stack as shared object requires"); /* Notify the debugger we have added some objects. We need to call _dl_debug_initialize in a static program in case dynamic linking has not been used before. */ - r->r_state = RT_ADD; - _dl_debug_state (); + _dl_debug_change_state (r, RT_ADD); LIBC_PROBE (map_start, 2, nsid, r); } else diff --git a/elf/dl-open.c b/elf/dl-open.c index 2d985e21d8..02235f7e0b 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -619,8 +619,7 @@ dl_open_worker_begin (void *a) /* Notify the debugger all new objects are now ready to go. */ struct r_debug *r = _dl_debug_update (args->nsid); - r->r_state = RT_CONSISTENT; - _dl_debug_state (); + _dl_debug_change_state (r, RT_CONSISTENT); LIBC_PROBE (map_complete, 3, args->nsid, r, new); _dl_open_check (new); @@ -853,7 +852,7 @@ no more namespaces available for dlmopen()")); } GL(dl_ns)[nsid].libc_map = NULL; - _dl_debug_update (nsid)->r_state = RT_CONSISTENT; + _dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT); } /* Never allow loading a DSO in a namespace which is empty. Such direct placements is only causing problems. Also don't allow diff --git a/elf/rtld.c b/elf/rtld.c index c1e383b055..edb1749d72 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1826,8 +1826,7 @@ dl_main (const ElfW(Phdr) *phdr, elf_setup_debug_entry (main_map, r); /* We start adding objects. */ - r->r_state = RT_ADD; - _dl_debug_state (); + _dl_debug_change_state (r, RT_ADD); LIBC_PROBE (init_start, 2, LM_ID_BASE, r); /* Auditing checkpoint: we are ready to signal that the initial map @@ -2394,8 +2393,7 @@ dl_main (const ElfW(Phdr) *phdr, /* Notify the debugger all new objects are now ready to go. We must re-get the address since by now the variable might be in another object. */ r = _dl_debug_update (LM_ID_BASE); - r->r_state = RT_CONSISTENT; - _dl_debug_state (); + _dl_debug_change_state (r, RT_CONSISTENT); LIBC_PROBE (init_complete, 2, LM_ID_BASE, r); #if defined USE_LDCONFIG && !defined MAP_COPY diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 1c0593465d..44fd37b1b5 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1058,8 +1058,14 @@ extern void _dl_debug_state (void); rtld_hidden_proto (_dl_debug_state) /* Initialize `struct r_debug_extended' for the namespace NS. LDBASE - is the run-time load address of the dynamic linker, to be put in the - `r_ldbase' member. Return the address of the structure. */ + is the run-time load address of the dynamic linker, to be put in + the `r_ldbase' member. + + This function returns the address of the r_debug structure for the + namespace. This is not merely a convenience or optimization, but + it is necessary for the LIBC_PROBE Systemtap/debugger probes to + work reliably: direct variable access can create probes that tools + cannot consume. */ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) attribute_hidden; @@ -1067,6 +1073,10 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) of the namespace NS. */ extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden; +/* Updates R->r_state to STATE and notifies the debugger by calling + _dl_debug_state. */ +void _dl_debug_change_state (struct r_debug *r, int state) attribute_hidden; + /* Initialize the basic data structure for the search paths. SOURCE is either "LD_LIBRARY_PATH" or "--library-path". GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to From patchwork Mon May 8 14:26:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 68914 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 67B563858416 for ; Mon, 8 May 2023 14:28:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 67B563858416 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1683556107; bh=nXb1mlhDw6o9sd1Cp74yLJOcSpgFDas68Z2ZYOAaT9k=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=HmBNVPF3H8V9BVF2lTaU1FzfoVOB/+fzLjWG1kdowzD2L2vOEFepL+G7A0jXbq66M hTqJTMEUl9WyAlNoLky/KBxWMphrXPNspy7wdzKeY2vLnvl8RWsWXVlw9ZSg0Bo90H h/9ltwWJI2KzsOfuRXhs4w6NuQjQ9+gXmCEdvhxQ= 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 ESMTPS id B3C493858C53 for ; Mon, 8 May 2023 14:26:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B3C493858C53 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-31-cCaeHtghNPunHLsIkLmDTg-1; Mon, 08 May 2023 10:26:08 -0400 X-MC-Unique: cCaeHtghNPunHLsIkLmDTg-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 13B52800047 for ; Mon, 8 May 2023 14:26:08 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.2.16.35]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8AFEB35453 for ; Mon, 8 May 2023 14:26:07 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH v4 3/3] elf: Restore support for _r_debug interpositions and copy relocations In-Reply-To: References: X-From-Line: 691d71e8f159c8424ce54537d6f21048e0150bce Mon Sep 17 00:00:00 2001 Message-Id: <691d71e8f159c8424ce54537d6f21048e0150bce.1683555718.git.fweimer@redhat.com> Date: Mon, 08 May 2023 16:26:05 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" The changes in commit a93d9e03a31ec14405cb3a09aa95413b67067380 ("Extend struct r_debug to support multiple namespaces [BZ #15971]") break the dyninst dynamic instrumentation tool. It brings its own definition of _r_debug (rather than a declaration). Furthermore, it turns out it is rather hard to use the proposed handshake for accessing _r_debug via DT_DEBUG. If applications want to access _r_debug, they can do so directly if the relevant code has been built as PIC. To protect against harm from accidental copy relocations due to linker relaxations, this commit restores copy relocation support by adjusting both copies if interposition or copy relocations are in play. --- elf/Makefile | 9 +++++++ elf/dl-debug.c | 52 +++++++++++++++++++++++++++++++++++--- elf/rtld.c | 3 +++ elf/tst-dlmopen4-nonpic.c | 2 ++ elf/tst-dlmopen4-pic.c | 2 ++ elf/tst-dlmopen4.c | 22 ++++++++++++++++ sysdeps/generic/ldsodefs.h | 4 +++ 7 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 elf/tst-dlmopen4-nonpic.c create mode 100644 elf/tst-dlmopen4-pic.c diff --git a/elf/Makefile b/elf/Makefile index 396ec51424..68fc6a45ad 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -398,6 +398,8 @@ tests += \ tst-dlmopen1 \ tst-dlmopen3 \ tst-dlmopen4 \ + tst-dlmopen4-nonpic \ + tst-dlmopen4-pic \ tst-dlmopen-dlerror \ tst-dlmopen-gethostbyname \ tst-dlmopen-twice \ @@ -1991,6 +1993,13 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so $(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so +CFLAGS-tst-dlmopen4-pic.c += -fPIC +$(objpfx)tst-dlmopen4-pic.out: $(objpfx)tst-dlmopen1mod.so + +CFLAGS-tst-dlmopen4-nonpic.c += -fno-pie +tst-dlmopen4-nonpic-no-pie = yes +$(objpfx)tst-dlmopen4-nonpic.out: $(objpfx)tst-dlmopen1mod.so + $(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so diff --git a/elf/dl-debug.c b/elf/dl-debug.c index 9d05e553d7..6b5e591619 100644 --- a/elf/dl-debug.c +++ b/elf/dl-debug.c @@ -16,6 +16,7 @@ License along with the GNU C Library; if not, see . */ +#include #include @@ -37,6 +38,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr) to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */ struct r_debug_extended _r_debug_array[DL_NNS - 1]; +/* If not null, pointer to the _r_debug in the main executable. */ +static struct r_debug *_r_debug_main; + +void +_dl_debug_post_relocate (struct link_map *main_map) +{ + /* Perform a full symbol search in all objects, to maintain + compatibility if interposed _r_debug definitions. The lookup + cannot faul because there is a definition in ld.so. */ + const ElfW(Sym) *sym = NULL; + lookup_t result =_dl_lookup_symbol_x ("_r_debug", main_map, &sym, + main_map->l_scope, NULL, 0, 0, NULL); + assert (sym != NULL); + if (sym->st_size >= sizeof (struct r_debug)) + { + struct r_debug *main_r_debug = DL_SYMBOL_ADDRESS (result, sym); + if (main_r_debug != &_r_debug_extended.base) + { + /* The extended version of the struct is not available in + the main executable because a copy relocation has been + used. r_map etc. have already been copied as part of the + copy relocation processing. */ + main_r_debug->r_version = 1; + + /* Record that dual updates of the initial link map are + required. */ + _r_debug_main = main_r_debug; + } + } +} + /* Return the r_debug object for the namespace NS. */ static inline struct r_debug_extended * get_rdebug (Lmid_t ns) @@ -71,6 +103,11 @@ void _dl_debug_change_state (struct r_debug *r, int state) { atomic_store_release (&r->r_state, state); +#ifdef SHARED + if (r == &_r_debug_extended.base && _r_debug_main != NULL) + /* Update the copy-relocation of _r_debug. */ + atomic_store_release (&_r_debug_main->r_state, state); +#endif _dl_debug_state (); } @@ -103,7 +140,9 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) if (ns - 1 == LM_ID_BASE) { atomic_store_release (&_r_debug_extended.r_next, r); - /* Now there are multiple namespaces. */ + /* Now there are multiple namespaces. Note that this + deliberately does not update the copy in the main + executable (if it exists). */ atomic_store_release (&_r_debug_extended.base.r_version, 2); } else @@ -116,8 +155,15 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) } if (r->base.r_map == NULL) - atomic_store_release (&r->base.r_map, - (void *) GL(dl_ns)[ns]._ns_loaded); + { + struct link_map_public *l = (void *) GL(dl_ns)[ns]._ns_loaded; + atomic_store_release (&r->base.r_map, l); +#ifdef SHARED + if (ns == LM_ID_BASE && _r_debug_main != NULL) + /* Update the copy-relocation of _r_debug. */ + atomic_store_release (&_r_debug_main->r_map, l); +#endif + } return &r->base; } diff --git a/elf/rtld.c b/elf/rtld.c index edb1749d72..7de8e2a433 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2325,6 +2325,9 @@ dl_main (const ElfW(Phdr) *phdr, /* We must prepare the profiling. */ _dl_start_profile (); + /* Update _r_debug if necessary. */ + _dl_debug_post_relocate (main_map); + if ((!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0) || count_modids != _dl_count_modids ()) ++GL(dl_tls_generation); diff --git a/elf/tst-dlmopen4-nonpic.c b/elf/tst-dlmopen4-nonpic.c new file mode 100644 index 0000000000..ad4e409953 --- /dev/null +++ b/elf/tst-dlmopen4-nonpic.c @@ -0,0 +1,2 @@ +#define BUILD_FOR_NONPIC +#include "tst-dlmopen4.c" diff --git a/elf/tst-dlmopen4-pic.c b/elf/tst-dlmopen4-pic.c new file mode 100644 index 0000000000..919fa85c25 --- /dev/null +++ b/elf/tst-dlmopen4-pic.c @@ -0,0 +1,2 @@ +#define BUILD_FOR_PIC +#include "tst-dlmopen4.c" diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c index abc800daed..e7b73f5302 100644 --- a/elf/tst-dlmopen4.c +++ b/elf/tst-dlmopen4.c @@ -46,6 +46,15 @@ do_test (void) TEST_COMPARE (debug->base.r_version, 1); TEST_VERIFY_EXIT (debug->r_next == NULL); +#ifdef BUILD_FOR_PIC + /* In a PIC build, using _r_debug directly should give us the same + object. */ + TEST_VERIFY (&_r_debug == &debug->base); +#endif +#ifdef BUILD_FOR_NONPIC + TEST_COMPARE (_r_debug.r_version, 1); +#endif + void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so", RTLD_LAZY); @@ -57,6 +66,19 @@ do_test (void) const char *name = basename (debug->r_next->base.r_map->l_name); TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so"); +#ifdef BUILD_FOR_NONPIC + /* If a copy relocation is used, it must be at version 1. */ + if (&_r_debug != &debug->base) + { + TEST_COMPARE (_r_debug.r_version, 1); + TEST_COMPARE ((uintptr_t) _r_debug.r_map, + (uintptr_t) debug->base.r_map); + TEST_COMPARE (_r_debug.r_brk, debug->base.r_brk); + TEST_COMPARE (_r_debug.r_state, debug->base.r_state); + TEST_COMPARE (_r_debug.r_ldbase, debug->base.r_ldbase); + } +#endif + xdlclose (h); return 0; diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 44fd37b1b5..ea09229216 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1069,6 +1069,10 @@ rtld_hidden_proto (_dl_debug_state) extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) attribute_hidden; +/* This is called after relocation processing to handle a potential + copy relocation for _r_debug. */ +void _dl_debug_post_relocate (struct link_map *main_map) attribute_hidden; + /* Update the `r_map' member and return the address of `struct r_debug' of the namespace NS. */ extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;