From 4d2825a3559d21e7c02e4c087b9b53f27207a65f Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Mon, 8 Jul 2024 16:10:58 -0300 Subject: [PATCH] elf: Use RTLD_NODELETE is more places * On dlopen dependencies for objects opened with RTLD_NODELETE (since it does not make sense to unload a dependency of a RTLD_NODELETE object); * For the main map executable. * For the main map DT_NEEDED dependencies. * On __libc_unwind_link_get for libgcc_s.so (used for backtrace and unwind). Checked on x86_64-linux-gnu. --- elf/dl-open.c | 3 ++- elf/rtld.c | 6 +++--- include/dlfcn.h | 2 ++ misc/unwind-link.c | 5 +++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/elf/dl-open.c b/elf/dl-open.c index c378da16c0..076b32b977 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -636,7 +636,8 @@ dl_open_worker_begin (void *a) /* Load that object's dependencies. */ _dl_map_object_deps (new, NULL, 0, 0, - mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); + mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT + | RTLD_NODELETE)); /* So far, so good. Now check the versions. */ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) diff --git a/elf/rtld.c b/elf/rtld.c index bfdf632e77..1090d89bfe 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -811,7 +811,7 @@ do_preload (const char *fname, struct link_map *main_map, const char *where) args.str = fname; args.loader = main_map; - args.mode = __RTLD_SECURE; + args.mode = __RTLD_SECURE | RTLD_NODELETE; unsigned int old_nloaded = GL(dl_ns)[LM_ID_BASE]._ns_nloaded; @@ -1638,7 +1638,7 @@ dl_main (const ElfW(Phdr) *phdr, /* Create a link_map for the executable itself. This will be what dlopen on "" returns. */ main_map = _dl_new_object ((char *) "", "", lt_executable, NULL, - __RTLD_OPENEXEC, LM_ID_BASE); + __RTLD_OPENEXEC | RTLD_NODELETE, LM_ID_BASE); assert (main_map != NULL); main_map->l_phdr = phdr; main_map->l_phnum = phnum; @@ -1966,7 +1966,7 @@ dl_main (const ElfW(Phdr) *phdr, RTLD_TIMING_VAR (start); rtld_timer_start (&start); _dl_map_object_deps (main_map, preloads, npreloads, - state.mode == rtld_mode_trace, 0); + state.mode == rtld_mode_trace, RTLD_NODELETE); rtld_timer_accum (&load_time, start); } diff --git a/include/dlfcn.h b/include/dlfcn.h index f49ee1b0c9..06e2ecbdd2 100644 --- a/include/dlfcn.h +++ b/include/dlfcn.h @@ -50,6 +50,8 @@ extern char **__libc_argv attribute_hidden; better error handling semantics for the library. */ #define __libc_dlopen(name) \ __libc_dlopen_mode (name, RTLD_NOW | __RTLD_DLOPEN) +#define __libc_dlopen_nodelete(name) \ + __libc_dlopen_mode (name, RTLD_NODELETE | RTLD_NOW | __RTLD_DLOPEN) extern void *__libc_dlopen_mode (const char *__name, int __mode) attribute_hidden; extern void *__libc_dlsym (void *__map, const char *__name) diff --git a/misc/unwind-link.c b/misc/unwind-link.c index 213a0162a4..7267ecbec3 100644 --- a/misc/unwind-link.c +++ b/misc/unwind-link.c @@ -48,7 +48,7 @@ __libc_unwind_link_get (void) /* Initialize a copy of the data, so that we do not need about unlocking in case the dynamic loader somehow triggers unwinding. */ - void *local_libgcc_handle = __libc_dlopen (LIBGCC_S_SO); + void *local_libgcc_handle = __libc_dlopen_nodelete (LIBGCC_S_SO); if (local_libgcc_handle == NULL) { __libc_lock_unlock (lock); @@ -100,7 +100,8 @@ __libc_unwind_link_get (void) __libc_lock_lock (lock); if (atomic_load_relaxed (&global_libgcc_handle) != NULL) - /* This thread lost the race. Clean up. */ + /* This thread lost the race. Drop the l_direct_opencount and issue + the debug log. */ __libc_dlclose (local_libgcc_handle); else {