summaryrefslogtreecommitdiff
path: root/debuggerd/debuggerd_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debuggerd/debuggerd_test.cpp')
-rw-r--r--debuggerd/debuggerd_test.cpp90
1 files changed, 89 insertions, 1 deletions
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 013c5723e..46342831c 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -15,6 +15,7 @@
*/
#include <dirent.h>
+#include <dlfcn.h>
#include <err.h>
#include <fcntl.h>
#include <malloc.h>
@@ -30,6 +31,7 @@
#include <chrono>
#include <regex>
+#include <string>
#include <thread>
#include <android/fdsan.h>
@@ -274,7 +276,7 @@ void CrasherTest::AssertDeath(int signo) {
}
if (signo == 0) {
- ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
ASSERT_EQ(0, WEXITSTATUS(signo));
} else {
ASSERT_FALSE(WIFEXITED(status));
@@ -517,6 +519,38 @@ TEST_P(SizeParamCrasherTest, mte_uaf) {
#endif
}
+TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
+#if defined(__aarch64__)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([&]() {
+ SetTagCheckingLevelSync();
+ volatile int* p = (volatile int*)malloc(GetParam());
+ free((void *)p);
+ p[-1] = 42;
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
+ ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
+#else
+ GTEST_SKIP() << "Requires aarch64";
+#endif
+}
+
TEST_P(SizeParamCrasherTest, mte_overflow) {
#if defined(__aarch64__)
if (!mte_supported()) {
@@ -1515,6 +1549,60 @@ TEST_F(CrasherTest, stack_overflow) {
ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
}
+static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
+ std::string test_lib(testing::internal::GetArgvs()[0]);
+ auto const value = test_lib.find_last_of('/');
+ if (value == std::string::npos) {
+ test_lib = "./";
+ } else {
+ test_lib = test_lib.substr(0, value + 1) + "./";
+ }
+ test_lib += "libcrash_test.so";
+
+ *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
+ std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
+
+ // Copy the shared so to a tempory directory.
+ return system(cp_cmd.c_str()) == 0;
+}
+
+TEST_F(CrasherTest, unreadable_elf) {
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([]() {
+ TemporaryDir td;
+ std::string tmp_so_name;
+ if (!CopySharedLibrary(td.path, &tmp_so_name)) {
+ _exit(1);
+ }
+ void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
+ if (handle == nullptr) {
+ _exit(1);
+ }
+ // Delete the original shared library so that we get the warning
+ // about unreadable elf files.
+ if (unlink(tmp_so_name.c_str()) == -1) {
+ _exit(1);
+ }
+ void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
+ if (crash_func == nullptr) {
+ _exit(1);
+ }
+ crash_func();
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ FinishIntercept(&intercept_result);
+
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
+}
+
TEST(tombstoned, proto) {
const pid_t self = getpid();
unique_fd tombstoned_socket, text_fd, proto_fd;