|
|
8a8cfb |
commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23
|
|
|
8a8cfb |
Author: Florian Weimer <fweimer@redhat.com>
|
|
|
8a8cfb |
Date: Thu Oct 31 19:30:19 2019 +0100
|
|
|
8a8cfb |
|
|
|
8a8cfb |
Block signals during the initial part of dlopen
|
|
|
8a8cfb |
|
|
|
8a8cfb |
Lazy binding in a signal handler that interrupts a dlopen sees
|
|
|
8a8cfb |
intermediate dynamic linker state. This has likely been always
|
|
|
8a8cfb |
unsafe, but with the new pending NODELETE state, this is clearly
|
|
|
8a8cfb |
incorrect. Other threads are excluded via the loader lock, but the
|
|
|
8a8cfb |
current thread is not. Blocking signals until right before ELF
|
|
|
8a8cfb |
constructors run is the safe thing to do.
|
|
|
8a8cfb |
|
|
|
8a8cfb |
Change-Id: Iad079080ebe7442c13313ba11dc2797953faef35
|
|
|
8a8cfb |
|
|
|
8a8cfb |
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
|
|
8a8cfb |
index 79c6e4c8ed1c9dfa..25838b073ac1edaf 100644
|
|
|
8a8cfb |
--- a/elf/dl-open.c
|
|
|
8a8cfb |
+++ b/elf/dl-open.c
|
|
|
8a8cfb |
@@ -34,6 +34,7 @@
|
|
|
8a8cfb |
#include <atomic.h>
|
|
|
8a8cfb |
#include <libc-internal.h>
|
|
|
8a8cfb |
#include <array_length.h>
|
|
|
8a8cfb |
+#include <internal-signals.h>
|
|
|
8a8cfb |
|
|
|
8a8cfb |
#include <dl-dst.h>
|
|
|
8a8cfb |
#include <dl-prop.h>
|
|
|
8a8cfb |
@@ -52,6 +53,10 @@ struct dl_open_args
|
|
|
8a8cfb |
/* Namespace ID. */
|
|
|
8a8cfb |
Lmid_t nsid;
|
|
|
8a8cfb |
|
|
|
8a8cfb |
+ /* Original signal mask. Used for unblocking signal handlers before
|
|
|
8a8cfb |
+ running ELF constructors. */
|
|
|
8a8cfb |
+ sigset_t original_signal_mask;
|
|
|
8a8cfb |
+
|
|
|
8a8cfb |
/* Original value of _ns_global_scope_pending_adds. Set by
|
|
|
8a8cfb |
dl_open_worker. Only valid if nsid is a real namespace
|
|
|
8a8cfb |
(non-negative). */
|
|
|
8a8cfb |
@@ -524,12 +529,16 @@ dl_open_worker (void *a)
|
|
|
8a8cfb |
if (new == NULL)
|
|
|
8a8cfb |
{
|
|
|
8a8cfb |
assert (mode & RTLD_NOLOAD);
|
|
|
8a8cfb |
+ __libc_signal_restore_set (&args->original_signal_mask);
|
|
|
8a8cfb |
return;
|
|
|
8a8cfb |
}
|
|
|
8a8cfb |
|
|
|
8a8cfb |
if (__glibc_unlikely (mode & __RTLD_SPROF))
|
|
|
8a8cfb |
- /* This happens only if we load a DSO for 'sprof'. */
|
|
|
8a8cfb |
- return;
|
|
|
8a8cfb |
+ {
|
|
|
8a8cfb |
+ /* This happens only if we load a DSO for 'sprof'. */
|
|
|
8a8cfb |
+ __libc_signal_restore_set (&args->original_signal_mask);
|
|
|
8a8cfb |
+ return;
|
|
|
8a8cfb |
+ }
|
|
|
8a8cfb |
|
|
|
8a8cfb |
/* This object is directly loaded. */
|
|
|
8a8cfb |
++new->l_direct_opencount;
|
|
|
8a8cfb |
@@ -565,6 +574,7 @@ dl_open_worker (void *a)
|
|
|
8a8cfb |
|
|
|
8a8cfb |
assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
|
|
|
8a8cfb |
|
|
|
8a8cfb |
+ __libc_signal_restore_set (&args->original_signal_mask);
|
|
|
8a8cfb |
return;
|
|
|
8a8cfb |
}
|
|
|
8a8cfb |
|
|
|
8a8cfb |
@@ -745,6 +755,10 @@ dl_open_worker (void *a)
|
|
|
8a8cfb |
if (mode & RTLD_GLOBAL)
|
|
|
8a8cfb |
add_to_global_resize (new);
|
|
|
8a8cfb |
|
|
|
8a8cfb |
+ /* Unblock signals. Data structures are now consistent, and
|
|
|
8a8cfb |
+ application code may run. */
|
|
|
8a8cfb |
+ __libc_signal_restore_set (&args->original_signal_mask);
|
|
|
8a8cfb |
+
|
|
|
8a8cfb |
/* Run the initializer functions of new objects. Temporarily
|
|
|
8a8cfb |
disable the exception handler, so that lazy binding failures are
|
|
|
8a8cfb |
fatal. */
|
|
|
8a8cfb |
@@ -834,6 +848,10 @@ no more namespaces available for dlmopen()"));
|
|
|
8a8cfb |
args.argv = argv;
|
|
|
8a8cfb |
args.env = env;
|
|
|
8a8cfb |
|
|
|
8a8cfb |
+ /* Recursive lazy binding during manipulation of the dynamic loader
|
|
|
8a8cfb |
+ structures may result in incorrect behavior. */
|
|
|
8a8cfb |
+ __libc_signal_block_all (&args.original_signal_mask);
|
|
|
8a8cfb |
+
|
|
|
8a8cfb |
struct dl_exception exception;
|
|
|
8a8cfb |
int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
|
|
|
8a8cfb |
|
|
|
8a8cfb |
@@ -874,10 +892,16 @@ no more namespaces available for dlmopen()"));
|
|
|
8a8cfb |
|
|
|
8a8cfb |
_dl_close_worker (args.map, true);
|
|
|
8a8cfb |
|
|
|
8a8cfb |
+ /* Restore the signal mask. In the success case, this
|
|
|
8a8cfb |
+ happens inside dl_open_worker. */
|
|
|
8a8cfb |
+ __libc_signal_restore_set (&args.original_signal_mask);
|
|
|
8a8cfb |
+
|
|
|
8a8cfb |
/* All link_map_nodelete_pending objects should have been
|
|
|
8a8cfb |
deleted at this point, which is why it is not necessary
|
|
|
8a8cfb |
to reset the flag here. */
|
|
|
8a8cfb |
}
|
|
|
8a8cfb |
+ else
|
|
|
8a8cfb |
+ __libc_signal_restore_set (&args.original_signal_mask);
|
|
|
8a8cfb |
|
|
|
8a8cfb |
assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
|
|
|
8a8cfb |
|