aboutsummaryrefslogtreecommitdiff
path: root/elf/dl-open.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2019-11-27 16:20:47 +0100
committerFlorian Weimer <fweimer@redhat.com>2019-11-27 20:55:35 +0100
commit79e0cd7b3c997e211fad44a81fd839dc5b2546e8 (patch)
tree2de9e1bc730bae922d592fa1521aab4f9d65ef01 /elf/dl-open.c
parent446997ff1433d33452b81dfa9e626b8dccf101a4 (diff)
downloadglibc-79e0cd7b3c997e211fad44a81fd839dc5b2546e8.zip
glibc-79e0cd7b3c997e211fad44a81fd839dc5b2546e8.tar.gz
glibc-79e0cd7b3c997e211fad44a81fd839dc5b2546e8.tar.bz2
Lazy binding failures during dlopen/dlclose must be fatal [BZ #24304]
If a lazy binding failure happens during the execution of an ELF constructor or destructor, the dynamic loader catches the error and reports it using the dlerror mechanism. This is undesirable because there could be other constructors and destructors that need processing (which are skipped), and the process is in an inconsistent state at this point. Therefore, we have to issue a fatal dynamic loader error error and terminate the process. Note that the _dl_catch_exception in _dl_open is just an inner catch, to roll back some state locally. If called from dlopen, there is still an outer catch, which is why calling _dl_init via call_dl_init and a no-exception is required and cannot be avoiding by moving the _dl_init call directly into _dl_open. _dl_fini does not need changes because it does not install an error handler, so errors are already fatal there. Change-Id: I6b1addfe2e30f50a1781595f046f44173db9491a
Diffstat (limited to 'elf/dl-open.c')
-rw-r--r--elf/dl-open.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 8d699d3..533fb96 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -177,6 +177,23 @@ _dl_find_dso_for_object (const ElfW(Addr) addr)
}
rtld_hidden_def (_dl_find_dso_for_object);
+/* struct dl_init_args and call_dl_init are used to call _dl_init with
+ exception handling disabled. */
+struct dl_init_args
+{
+ struct link_map *new;
+ int argc;
+ char **argv;
+ char **env;
+};
+
+static void
+call_dl_init (void *closure)
+{
+ struct dl_init_args *args = closure;
+ _dl_init (args->new, args->argc, args->argv, args->env);
+}
+
static void
dl_open_worker (void *a)
{
@@ -509,8 +526,19 @@ TLS generation counter wrapped! Please report this."));
DL_STATIC_INIT (new);
#endif
- /* Run the initializer functions of new objects. */
- _dl_init (new, args->argc, args->argv, args->env);
+ /* Run the initializer functions of new objects. Temporarily
+ disable the exception handler, so that lazy binding failures are
+ fatal. */
+ {
+ struct dl_init_args init_args =
+ {
+ .new = new,
+ .argc = args->argc,
+ .argv = args->argv,
+ .env = args->env
+ };
+ _dl_catch_exception (NULL, call_dl_init, &init_args);
+ }
/* Now we can make the new map available in the global scope. */
if (mode & RTLD_GLOBAL)