From 4843c186340585eaf20610d2538f85234cc63174 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Mon, 27 Aug 2018 14:52:33 -0700 Subject: [PATCH 1/2] debuggerd_handler: receive abort messages via sigqueue(DEBUGGER_SIGNAL). Make it possible for code such as fdsan that generates debugging tombstones via raise(DEBUGGER_SIGNAL) to pass an abort message as well. Bug: http://b/112770187 Test: debuggerd_test Change-Id: Idc34263241c18033573e466da3a45aa6f716ddb3 --- debuggerd/handler/debuggerd_handler.cpp | 28 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index 91e6f7111..15557b6d8 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -457,14 +457,14 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c info = nullptr; } - struct siginfo si = {}; + struct siginfo dummy_info = {}; if (!info) { - memset(&si, 0, sizeof(si)); - si.si_signo = signal_number; - si.si_code = SI_USER; - si.si_pid = __getpid(); - si.si_uid = getuid(); - info = &si; + memset(&dummy_info, 0, sizeof(dummy_info)); + dummy_info.si_signo = signal_number; + dummy_info.si_code = SI_USER; + dummy_info.si_pid = __getpid(); + dummy_info.si_uid = getuid(); + info = &dummy_info; } else if (info->si_code >= 0 || info->si_code == SI_TKILL) { // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels // that contain commit 66dd34a (3.9+). The manpage claims to only allow @@ -473,8 +473,18 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c } void* abort_message = nullptr; - if (signal_number != DEBUGGER_SIGNAL && g_callbacks.get_abort_message) { - abort_message = g_callbacks.get_abort_message(); + if (signal_number == DEBUGGER_SIGNAL) { + if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) { + // Allow for the abort message to be explicitly specified via the sigqueue value. + // Keep the bottom bit intact for representing whether we want a backtrace or a tombstone. + uintptr_t value = reinterpret_cast(info->si_ptr); + abort_message = reinterpret_cast(value & ~1); + info->si_ptr = reinterpret_cast(value & 1); + } + } else { + if (g_callbacks.get_abort_message) { + abort_message = g_callbacks.get_abort_message(); + } } // If sival_int is ~0, it means that the fallback handler has been called From bf06a40a0d8e61f2926bca9a645126fe46990051 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Mon, 27 Aug 2018 16:34:01 -0700 Subject: [PATCH 2/2] debuggerd_test: add test for fdsan abort message. Bug: http://b/112770187 Test: debuggerd_test Test: bionic-unit-tests Change-Id: Ia93761e89074aea4629b8d0f232c580d6f0f249c --- debuggerd/debuggerd_test.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index dfb7a6a7c..e2ea480e5 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -801,6 +802,31 @@ TEST_F(CrasherTest, competing_tracer) { AssertDeath(SIGABRT); } +TEST_F(CrasherTest, fdsan_warning_abort_message) { + int intercept_result; + unique_fd output_fd; + + StartProcess([]() { + android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE); + unique_fd fd(open("/dev/null", O_RDONLY | O_CLOEXEC)); + if (fd == -1) { + abort(); + } + close(fd.get()); + _exit(0); + }); + + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(0); + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + ASSERT_MATCH(result, "Abort message: 'attempted to close"); +} + TEST(crash_dump, zombie) { pid_t forkpid = fork();