From patchwork Wed May 16 17:11:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivek Dasmohapatra X-Patchwork-Id: 27299 Received: (qmail 60928 invoked by alias); 16 May 2018 17:11:38 -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 60776 invoked by uid 89); 16 May 2018 17:11:37 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 spammy=2450, auditing, Protect, directions X-HELO: bhuna.collabora.co.uk From: =?UTF-8?q?Vivek=20Das=C2=A0Mohapatra?= To: libc-alpha@sourceware.org Cc: =?UTF-8?q?Vivek=20Das=C2=A0Mohapatra?= Subject: [RFC][PATCH v1 5/5] elf/dl-fini.c: Handle cloned link_map entries in the shutdown path Date: Wed, 16 May 2018 18:11:24 +0100 Message-Id: <20180516171124.24962-6-vivek@collabora.com> In-Reply-To: <20180516171124.24962-1-vivek@collabora.com> References: <20180516171124.24962-1-vivek@collabora.com> MIME-Version: 1.0 From: Vivek Das Mohapatra When cleaning up before exit we should not call destructors or otherwise free [most of] the contents of a cloned link_map entry since they share [most of] their contents with the LM_ID_BASE object from which they were cloned. Instead we do the minimal cleanup necessary and remove them from the namespace linked list(s) before the main cleanup code path is triggered: This prevemts double-frees and double-invocation of any destructors (which might not be idempotent). --- elf/dl-fini.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 3cfc262400..643a68504e 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -24,6 +24,50 @@ /* Type of the constructor functions. */ typedef void (*fini_t) (void); +/* Remove (and free) cloned entries from the namespace specifid by `ns'. */ +void +_dl_forget_clones (Lmid_t ns) +{ +#ifdef SHARED /* Obviously none of this applies if */ + struct link_map *clone; + struct link_map *next; + + if (ns < 0 || ns >= DL_NNS) + return; + + for (clone = GL(dl_ns)[ns]._ns_loaded; clone != NULL; clone = next) + { + next = clone->l_next; + + /* Not actually clone, don't care. */ + if (!clone->l_clone) + continue; + + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) + _dl_debug_printf ("\nclone removed %s [%lu]\n", clone->l_name, ns); + + /* If item is a clone, slice it out of the linked list. */ + if (clone == GL(dl_ns)[ns]._ns_loaded) + GL(dl_ns)[ns]._ns_loaded = clone->l_next; + else + clone->l_prev->l_next = clone->l_next; + + /* Remember to fix up the links in both directions. */ + if (clone->l_next) + clone->l_next->l_prev = clone->l_prev; + + /* Don't need to do most destructor handling for clones. */ + if (clone->l_free_initfini) + free (clone->l_initfini); + + /* Do need to fix the global load count which is updated in + _dl_add_to_namespace_list. */ + GL(dl_ns)[ns]._ns_nloaded--; + + free (clone); + } +#endif +} void _dl_fini (void) @@ -52,6 +96,12 @@ _dl_fini (void) /* Protect against concurrent loads and unloads. */ __rtld_lock_lock_recursive (GL(dl_load_lock)); + /* We need to remove any pointers to cloned entries (link_map + structs that are copied from one namespace to another to + implement RTLD_SHARED semantics) before the regular cleanup + code gets to them. */ + _dl_forget_clones (ns); + unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded; /* No need to do anything for empty namespaces or those used for auditing DSOs. */