summaryrefslogtreecommitdiffstats
path: root/sigchainlib
diff options
context:
space:
mode:
authorDave Allison <dallison@google.com>2014-05-14 15:41:25 -0700
committerDave Allison <dallison@google.com>2014-05-29 08:22:38 -0700
commitf4b80bcc7190fe75023b983d56a795b440a0c515 (patch)
treef2858dab6a756444755b79e36467d6c9e15060f1 /sigchainlib
parentc774bd435e95e537ca578486f687651fabe97008 (diff)
downloadart-f4b80bcc7190fe75023b983d56a795b440a0c515.zip
art-f4b80bcc7190fe75023b983d56a795b440a0c515.tar.gz
art-f4b80bcc7190fe75023b983d56a795b440a0c515.tar.bz2
Make use of sigchainlib for signal chaining for implicit checks
This adds a preload library that overrides sigaction and sigprocmask to implement signal chaining. Signal chaining allows us to chain any signal so that the ART runtime receives it before any signal handler registered in native code by an application. If the ART signal handler doesn't want it, it will pass it on to the user's handler. ART uses signals for null pointer checks, stack overflow checks and suspend points. Also adds an OAT test to test this in isolation. Change-Id: I9545f9f7343774c091410eb810504d9855fd399f
Diffstat (limited to 'sigchainlib')
-rw-r--r--sigchainlib/Android.mk29
-rw-r--r--sigchainlib/sigchain.cc183
-rw-r--r--sigchainlib/sigchain.h29
3 files changed, 241 insertions, 0 deletions
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
new file mode 100644
index 0000000..cb1778d
--- /dev/null
+++ b/sigchainlib/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include art/build/Android.common.mk
+
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+LOCAL_SRC_FILES := sigchain.cc
+LOCAL_MODULE:= libsigchain
+LOCAL_SHARED_LIBRARIES += liblog libdl
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_SHARED_LIBRARY)
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
new file mode 100644
index 0000000..26e7d31
--- /dev/null
+++ b/sigchainlib/sigchain.cc
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/log.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace art {
+
+class SignalAction {
+ public:
+ SignalAction() : claimed_(false) {
+ }
+
+ // Claim the signal and keep the action specified.
+ void Claim(const struct sigaction& action) {
+ action_ = action;
+ claimed_ = true;
+ }
+
+ // Unclaim the signal and restore the old action.
+ void Unclaim(int signal) {
+ claimed_ = false;
+ sigaction(signal, &action_, NULL); // Restore old action.
+ }
+
+ // Get the action associated with this signal.
+ const struct sigaction& GetAction() const {
+ return action_;
+ }
+
+ // Is the signal claimed?
+ bool IsClaimed() const {
+ return claimed_;
+ }
+
+ // Change the recorded action to that specified.
+ void SetAction(const struct sigaction& action) {
+ action_ = action;
+ }
+
+ private:
+ struct sigaction action_; // Action to be performed.
+ bool claimed_; // Whether signal is claimed or not.
+};
+
+// User's signal handlers
+static SignalAction user_sigactions[_NSIG];
+
+static void log(const char* format, ...) {
+ char buf[256];
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buf, sizeof(buf), format, ap);
+ __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
+ va_end(ap);
+}
+
+static void CheckSignalValid(int signal) {
+ if (signal <= 0 || signal >= _NSIG) {
+ log("Invalid signal %d", signal);
+ abort();
+ }
+}
+
+// Claim a signal chain for a particular signal.
+void ClaimSignalChain(int signal, struct sigaction* oldaction) {
+ CheckSignalValid(signal);
+ user_sigactions[signal].Claim(*oldaction);
+}
+
+void UnclaimSignalChain(int signal) {
+ CheckSignalValid(signal);
+
+ user_sigactions[signal].Unclaim(signal);
+}
+
+// Invoke the user's signal handler.
+void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
+ // Check the arguments.
+ CheckSignalValid(sig);
+
+ // The signal must have been claimed in order to get here. Check it.
+ if (!user_sigactions[sig].IsClaimed()) {
+ abort();
+ }
+
+ const struct sigaction& action = user_sigactions[sig].GetAction();
+
+ // Only deliver the signal if the signal was not masked out.
+ if (sigismember(&action.sa_mask, sig)) {
+ return;
+ }
+ if ((action.sa_flags & SA_SIGINFO) == 0) {
+ if (action.sa_handler != NULL) {
+ action.sa_handler(sig);
+ }
+ } else {
+ if (action.sa_sigaction != NULL) {
+ action.sa_sigaction(sig, info, context);
+ }
+ }
+}
+
+extern "C" {
+// These functions are C linkage since they replace the functions in libc.
+
+int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
+ // If this signal has been claimed as a signal chain, record the user's
+ // action but don't pass it on to the kernel.
+ // Note that we check that the signal number is in range here. An out of range signal
+ // number should behave exactly as the libc sigaction.
+ if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) {
+ if (old_action != NULL) {
+ *old_action = user_sigactions[signal].GetAction();
+ }
+ if (new_action != NULL) {
+ user_sigactions[signal].SetAction(*new_action);
+ }
+ return 0;
+ }
+
+ // 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) {
+ log("Unable to find next sigaction in signal chain");
+ abort();
+ }
+
+ typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
+ SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym);
+ return linked_sigaction(signal, new_action, old_action);
+}
+
+
+int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
+ const sigset_t* new_set_ptr = bionic_new_set;
+ sigset_t tmpset;
+ if (bionic_new_set != NULL) {
+ tmpset = *bionic_new_set;
+
+ if (how == SIG_BLOCK) {
+ // Don't allow claimed signals in the mask. If a signal chain has been claimed
+ // we can't allow the user to block that signal.
+ for (int i = 0 ; i < _NSIG; ++i) {
+ if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
+ sigdelset(&tmpset, i);
+ }
+ }
+ }
+ new_set_ptr = &tmpset;
+ }
+
+ void* linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
+ 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*);
+ SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
+ return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
+}
+} // extern "C"
+} // namespace art
+
diff --git a/sigchainlib/sigchain.h b/sigchainlib/sigchain.h
new file mode 100644
index 0000000..f6f2253
--- /dev/null
+++ b/sigchainlib/sigchain.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SIGCHAINLIB_SIGCHAIN_H_
+#define ART_SIGCHAINLIB_SIGCHAIN_H_
+
+#include <signal.h>
+namespace art {
+
+void ClaimSignalChain(int signal, struct sigaction* oldaction);
+void UnclaimSignalChain(int signal);
+void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context);
+
+} // namespace art
+
+#endif // ART_SIGCHAINLIB_SIGCHAIN_H_