summaryrefslogtreecommitdiff
path: root/sigchainlib
diff options
context:
space:
mode:
authorJosh Gao <jmgao@google.com>2018-09-04 14:33:23 -0700
committerJosh Gao <jmgao@google.com>2018-09-04 15:54:59 -0700
commit3bef527cb9a42bcb2b251c072deb433e2bf8e2c6 (patch)
treed319a9fb331c47a467b2c922ac9e856d4c705980 /sigchainlib
parent4a25727eba333c19dc6eacc35950c526c11041d4 (diff)
sigchain: fix EnsureFrontOfChain on 32-bit.
On 32-bit, bionic's sigaction forwards to sigaction64, which gets interposed by libsigchain's sigaction64, which returns the user's signal handler, not the actual one. This leads to EnsureFrontOfChain's check for whether it should reregister the signal handler to falsely return true, which leads to explosions. Bug: http://b/112677822 Test: /data/nativetest/art/arm/art_sigchain_tests/sigchain_test Test: /data/nativetest64/art/arm64/art_sigchain_tests/sigchain_test Change-Id: Ifbaa4448580d763f5ffd575fa2e77113a8108de6
Diffstat (limited to 'sigchainlib')
-rw-r--r--sigchainlib/sigchain.cc5
-rw-r--r--sigchainlib/sigchain_test.cc57
2 files changed, 60 insertions, 2 deletions
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index 2e5f46ca69..cbc3ff8483 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -490,8 +490,13 @@ extern "C" void EnsureFrontOfChain(int signal) {
}
// Read the current action without looking at the chain, it should be the expected action.
+#if defined(__BIONIC__)
+ struct sigaction64 current_action;
+ linked_sigaction64(signal, nullptr, &current_action);
+#else
struct sigaction current_action;
linked_sigaction(signal, nullptr, &current_action);
+#endif
// If the sigactions don't match then we put the current action on the chain and make ourself as
// the main action.
diff --git a/sigchainlib/sigchain_test.cc b/sigchainlib/sigchain_test.cc
index 9584ded65f..53e1e40454 100644
--- a/sigchainlib/sigchain_test.cc
+++ b/sigchainlib/sigchain_test.cc
@@ -26,7 +26,8 @@
* SUCH DAMAGE.
*/
-
+#include <dlfcn.h>
+#include <pthread.h>
#include <signal.h>
#include <sys/syscall.h>
@@ -63,10 +64,25 @@ class SigchainTest : public ::testing::Test {
}
art::SigchainAction action = {
- .sc_sigaction = [](int, siginfo_t*, void*) { return true; },
+ .sc_sigaction = [](int, siginfo_t* info, void*) -> bool {
+ return info->si_value.sival_ptr;
+ },
.sc_mask = {},
.sc_flags = 0,
};
+
+ protected:
+ void RaiseHandled() {
+ sigval_t value;
+ value.sival_ptr = &value;
+ pthread_sigqueue(pthread_self(), SIGSEGV, value);
+ }
+
+ void RaiseUnhandled() {
+ sigval_t value;
+ value.sival_ptr = nullptr;
+ pthread_sigqueue(pthread_self(), SIGSEGV, value);
+ }
};
@@ -185,3 +201,40 @@ TEST_F(SigchainTest, sigsetmask) {
}
#endif
+
+// Make sure that we properly put ourselves back in front if we get circumvented.
+TEST_F(SigchainTest, EnsureFrontOfChain) {
+#if defined(__BIONIC__)
+ constexpr char kLibcSoName[] = "libc.so";
+#elif defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ == 6
+ constexpr char kLibcSoName[] = "libc.so.6";
+#else
+ #error Unknown libc
+#endif
+ void* libc = dlopen(kLibcSoName, RTLD_LAZY | RTLD_NOLOAD);
+ ASSERT_TRUE(libc);
+
+ static sig_atomic_t called = 0;
+ struct sigaction action = {};
+ action.sa_flags = SA_SIGINFO;
+ action.sa_sigaction = [](int, siginfo_t*, void*) { called = 1; };
+
+ ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
+
+ // Try before EnsureFrontOfChain.
+ RaiseHandled();
+ ASSERT_EQ(0, called);
+
+ RaiseUnhandled();
+ ASSERT_EQ(1, called);
+ called = 0;
+
+ // ...and after.
+ art::EnsureFrontOfChain(SIGSEGV);
+ ASSERT_EQ(0, called);
+ called = 0;
+
+ RaiseUnhandled();
+ ASSERT_EQ(1, called);
+ called = 0;
+}