summaryrefslogtreecommitdiffstats
path: root/sigchainlib
diff options
context:
space:
mode:
authorDave Allison <dallison@google.com>2014-09-16 10:01:01 -0700
committerDave Allison <dallison@google.com>2014-09-16 10:11:17 -0700
commitcefcea838729287a04174664a76514dd793dd77d (patch)
tree1feb269b6224d0448f15502eb09da4a97dc67b24 /sigchainlib
parent5733b35c23792834f3a2374003c109301a48867c (diff)
downloadart-cefcea838729287a04174664a76514dd793dd77d.zip
art-cefcea838729287a04174664a76514dd793dd77d.tar.gz
art-cefcea838729287a04174664a76514dd793dd77d.tar.bz2
Don't call dlsym from signal context in signal chain
It is dangerous to call dlsym from within a signal context since it takes a lock and can lead to a mutex reentry attempt if timing is bad. This change adds an initialization function to the signal chain that calls dlsym for sigaction and sigprocmask from outside the signal context (from Runtime::Init()). The results are cached in a static variable and used from within the signal context if necessary. However, tests don't necessarily call Runtime::Init() so we also need to deal with the case where the signal chain is not initialized and perform a lazy initialization from inside sigaction or sigprocmask. This is always outside a signal context since we have not initialized the runtime. Bug: 17498571 Change-Id: I59eebfc67cc91c6f1d781a73e5d432ca5269ee48
Diffstat (limited to 'sigchainlib')
-rw-r--r--sigchainlib/sigchain.cc82
-rw-r--r--sigchainlib/sigchain.h2
2 files changed, 63 insertions, 21 deletions
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index 7539990..74bfb7e 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -26,6 +26,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include "sigchain.h"
+
#if defined(__APPLE__)
#define _NSIG NSIG
#define sighandler_t sig_t
@@ -81,6 +83,9 @@ class SignalAction {
// User's signal handlers
static SignalAction user_sigactions[_NSIG];
+static bool initialized;
+static void* linked_sigaction_sym;
+static void* linked_sigprocmask_sym;
static void log(const char* format, ...) {
char buf[256];
@@ -102,6 +107,7 @@ static void CheckSignalValid(int signal) {
}
}
+
// Claim a signal chain for a particular signal.
void ClaimSignalChain(int signal, struct sigaction* oldaction) {
CheckSignalValid(signal);
@@ -163,14 +169,17 @@ int sigaction(int signal, const struct sigaction* new_action, struct sigaction*
// Will only get here if the signal chain has not been claimed. We want
// to pass the sigaction on to the kernel via the real sigaction in libc.
- void* linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
if (linked_sigaction_sym == nullptr) {
- linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
- if (linked_sigaction_sym == nullptr ||
- linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
- log("Unable to find next sigaction in signal chain");
- abort();
- }
+ // Perform lazy initialization.
+ // This will only occur outside of a signal context since we have
+ // not been initialized and therefore cannot be within the ART
+ // runtime.
+ InitializeSignalChain();
+ }
+
+ if (linked_sigaction_sym == nullptr) {
+ log("Unable to find next sigaction in signal chain");
+ abort();
}
typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
@@ -198,14 +207,14 @@ sighandler_t signal(int signal, sighandler_t handler) {
// Will only get here if the signal chain has not been claimed. We want
// to pass the sigaction on to the kernel via the real sigaction in libc.
- void* linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
if (linked_sigaction_sym == nullptr) {
- linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
- if (linked_sigaction_sym == nullptr ||
- linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
- log("Unable to find next sigaction in signal chain");
- abort();
- }
+ // Perform lazy initialization.
+ InitializeSignalChain();
+ }
+
+ if (linked_sigaction_sym == nullptr) {
+ log("Unable to find next sigaction in signal chain");
+ abort();
}
typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
@@ -235,14 +244,14 @@ int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_se
new_set_ptr = &tmpset;
}
- void* linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
if (linked_sigprocmask_sym == nullptr) {
- linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
- if (linked_sigprocmask_sym == nullptr ||
- linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
- log("Unable to find next sigprocmask in signal chain");
- abort();
- }
+ // Perform lazy initialization.
+ InitializeSignalChain();
+ }
+
+ if (linked_sigprocmask_sym == nullptr) {
+ log("Unable to find next sigprocmask in signal chain");
+ abort();
}
typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
@@ -250,5 +259,36 @@ int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_se
return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
}
} // extern "C"
+
+void InitializeSignalChain() {
+ // Warning.
+ // Don't call this from within a signal context as it makes calls to
+ // dlsym. Calling into the dynamic linker will result in locks being
+ // taken and if it so happens that a signal occurs while one of these
+ // locks is already taken, dlsym will block trying to reenter a
+ // mutex and we will never get out of it.
+ if (initialized) {
+ // Don't initialize twice.
+ return;
+ }
+ linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
+ if (linked_sigaction_sym == nullptr) {
+ linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
+ if (linked_sigaction_sym == nullptr ||
+ linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
+ linked_sigaction_sym = nullptr;
+ }
+ }
+
+ linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
+ if (linked_sigprocmask_sym == nullptr) {
+ linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
+ if (linked_sigprocmask_sym == nullptr ||
+ linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
+ linked_sigprocmask_sym = nullptr;
+ }
+ }
+ initialized = true;
+}
} // namespace art
diff --git a/sigchainlib/sigchain.h b/sigchainlib/sigchain.h
index a4ce81c..5bc4026 100644
--- a/sigchainlib/sigchain.h
+++ b/sigchainlib/sigchain.h
@@ -21,6 +21,8 @@
namespace art {
+void InitializeSignalChain();
+
void ClaimSignalChain(int signal, struct sigaction* oldaction);
void UnclaimSignalChain(int signal);