diff options
author | Peter Collingbourne <pcc@google.com> | 2020-06-03 18:39:38 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-06-03 18:39:38 +0000 |
commit | 5c5aef1c0b14774fc6a02916693fc15a621ca523 (patch) | |
tree | ca6e5405a832ce4390bc51cdcbfdf380c304afe3 | |
parent | 4f143b9f3d652ccff8a7b647223cbbdcf374e99c (diff) | |
parent | 91740684c29535448db6cdb691e84f7a86a69ba3 (diff) | |
download | bionic-5c5aef1c0b14774fc6a02916693fc15a621ca523.tar.gz |
Handle the alternate signal stack correctly in android_unsafe_frame_pointer_chase. am: 91740684c2
Original change: https://googleplex-android-review.googlesource.com/c/platform/bionic/+/11720548
Change-Id: I46c15e323c1f5a14c8491e628c8be3167c3073f3
-rw-r--r-- | libc/bionic/android_unsafe_frame_pointer_chase.cpp | 6 | ||||
-rw-r--r-- | tests/android_unsafe_frame_pointer_chase_test.cpp | 66 |
2 files changed, 69 insertions, 3 deletions
diff --git a/libc/bionic/android_unsafe_frame_pointer_chase.cpp b/libc/bionic/android_unsafe_frame_pointer_chase.cpp index 0fb086e49..e25867b0e 100644 --- a/libc/bionic/android_unsafe_frame_pointer_chase.cpp +++ b/libc/bionic/android_unsafe_frame_pointer_chase.cpp @@ -57,6 +57,12 @@ __attribute__((no_sanitize("address", "hwaddress"))) size_t android_unsafe_frame auto begin = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); uintptr_t end = __get_thread()->stack_top; + + stack_t ss; + if (sigaltstack(nullptr, &ss) == 0 && (ss.ss_flags & SS_ONSTACK)) { + end = reinterpret_cast<uintptr_t>(ss.ss_sp) + ss.ss_size; + } + size_t num_frames = 0; while (1) { auto* frame = reinterpret_cast<frame_record*>(begin); diff --git a/tests/android_unsafe_frame_pointer_chase_test.cpp b/tests/android_unsafe_frame_pointer_chase_test.cpp index dd04c3377..7fa50e149 100644 --- a/tests/android_unsafe_frame_pointer_chase_test.cpp +++ b/tests/android_unsafe_frame_pointer_chase_test.cpp @@ -18,6 +18,8 @@ #if defined(__BIONIC__) +#include <sys/mman.h> + #include "platform/bionic/android_unsafe_frame_pointer_chase.h" // Prevent tail calls inside recurse. @@ -72,21 +74,25 @@ TEST(android_unsafe_frame_pointer_chase, main_thread) { EXPECT_TRUE(CheckFrames(frames, size)); } -static void *BacktraceThread(void *) { +static const char* tester_func() { size_t size = recurse(kNumFrames, 0, 0); uintptr_t frames[kNumFrames + 2]; size_t size2 = recurse(kNumFrames, frames, kNumFrames + 2); if (size2 != size) { - return (void*)"size2 != size"; + return "size2 != size"; } if (!CheckFrames(frames, size)) { - return (void*)"CheckFrames failed"; + return "CheckFrames failed"; } return nullptr; } +static void* BacktraceThread(void*) { + return (void*)tester_func(); +} + TEST(android_unsafe_frame_pointer_chase, pthread) { pthread_t t; ASSERT_EQ(0, pthread_create(&t, nullptr, BacktraceThread, nullptr)); @@ -95,4 +101,58 @@ TEST(android_unsafe_frame_pointer_chase, pthread) { EXPECT_EQ(nullptr, reinterpret_cast<char*>(retval)); } +static bool g_handler_called; +static const char* g_handler_tester_result; + +static void BacktraceHandler(int) { + g_handler_called = true; + g_handler_tester_result = tester_func(); +} + +static constexpr size_t kStackSize = 16384; + +static void* SignalBacktraceThread(void* sp) { + stack_t ss; + ss.ss_sp = sp; + ss.ss_flags = 0; + ss.ss_size = kStackSize; + sigaltstack(&ss, nullptr); + + struct sigaction s = {}; + s.sa_handler = BacktraceHandler; + s.sa_flags = SA_ONSTACK; + sigaction(SIGRTMIN, &s, nullptr); + + raise(SIGRTMIN); + return nullptr; +} + +TEST(android_unsafe_frame_pointer_chase, sigaltstack) { + // Create threads where the alternate stack appears both after and before the regular stack, and + // call android_unsafe_frame_pointer_chase from a signal handler. Without handling for the + // alternate signal stack, this would cause false negatives or potential false positives in the + // android_unsafe_frame_pointer_chase function. + void* stacks = + mmap(nullptr, kStackSize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + + for (unsigned i = 0; i != 2; ++i) { + pthread_t t; + pthread_attr_t attr; + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<char*>(stacks) + kStackSize * i, + kStackSize)); + + ASSERT_EQ(0, pthread_create(&t, &attr, SignalBacktraceThread, + reinterpret_cast<char*>(stacks) + kStackSize * (1 - i))); + void* retval; + ASSERT_EQ(0, pthread_join(t, &retval)); + + EXPECT_TRUE(g_handler_called); + EXPECT_EQ(nullptr, g_handler_tester_result); + g_handler_called = false; + } + + munmap(stacks, kStackSize * 2); +} + #endif // __BIONIC__ |