diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 6dc6675ac..ca881aaf0 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -195,3 +195,7 @@ cc_binary { init_rc: ["tombstoned/tombstoned.rc"] } + +subdirs = [ + "crasher", +] diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp new file mode 100644 index 000000000..47278940e --- /dev/null +++ b/debuggerd/crasher/Android.bp @@ -0,0 +1,81 @@ +cc_defaults { + name: "crasher-defaults", + + cppflags: [ + "-std=gnu++14", + "-W", + "-Wall", + "-Wextra", + "-Wunused", + "-Werror", + "-O0", + "-fstack-protector-all", + "-Wno-free-nonheap-object", + "-Wno-date-time", + ], + srcs: ["crasher.cpp"], + arch: { + arm: { + srcs: ["arm/crashglue.S"], + + armv7_a_neon: { + asflags: ["-DHAS_VFP_D32"], + }, + }, + arm64: { + srcs: ["arm64/crashglue.S"], + }, + mips: { + srcs: ["mips/crashglue.S"], + }, + mips64: { + srcs: ["mips64/crashglue.S"], + }, + x86: { + srcs: ["x86/crashglue.S"], + }, + x86_64: { + srcs: ["x86_64/crashglue.S"], + }, + }, + compile_multilib: "both", +} + +cc_binary { + name: "crasher", + + defaults: ["crasher-defaults"], + shared_libs: [ + "libbase", + "liblog", + ], + multilib: { + lib32: { + stem: "crasher", + }, + lib64: { + stem: "crasher64", + }, + }, +} + +cc_binary { + name: "static_crasher", + + defaults: ["crasher-defaults"], + cppflags: ["-DSTATIC_CRASHER"], + static_executable: true, + static_libs: [ + "libdebuggerd_handler", + "libbase", + "liblog", + ], + multilib: { + lib32: { + stem: "static_crasher", + }, + lib64: { + stem: "static_crasher64", + }, + }, +} diff --git a/debuggerd/crasher/Android.mk b/debuggerd/crasher/Android.mk deleted file mode 100644 index b8b786be0..000000000 --- a/debuggerd/crasher/Android.mk +++ /dev/null @@ -1,66 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -crasher_cppflags := \ - -std=gnu++14 \ - -W \ - -Wall \ - -Wextra \ - -Wunused \ - -Werror \ - -O0 \ - -fstack-protector-all \ - -Wno-free-nonheap-object \ - -Wno-date-time - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := crasher.cpp -LOCAL_SRC_FILES_arm := arm/crashglue.S -LOCAL_SRC_FILES_arm64 := arm64/crashglue.S -LOCAL_SRC_FILES_mips := mips/crashglue.S -LOCAL_SRC_FILES_mips64 := mips64/crashglue.S -LOCAL_SRC_FILES_x86 := x86/crashglue.S -LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := optional -LOCAL_CPPFLAGS := $(crasher_cppflags) -LOCAL_SHARED_LIBRARIES := libbase liblog - -# The arm emulator has VFP but not VFPv3-D32. -ifeq ($(ARCH_ARM_HAVE_VFP_D32),true) -LOCAL_ASFLAGS_arm += -DHAS_VFP_D32 -endif - -LOCAL_MODULE := crasher -LOCAL_MODULE_STEM_32 := crasher -LOCAL_MODULE_STEM_64 := crasher64 -LOCAL_MULTILIB := both - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := crasher.cpp -LOCAL_SRC_FILES_arm := arm/crashglue.S -LOCAL_SRC_FILES_arm64 := arm64/crashglue.S -LOCAL_SRC_FILES_mips := mips/crashglue.S -LOCAL_SRC_FILES_mips64 := mips64/crashglue.S -LOCAL_SRC_FILES_x86 := x86/crashglue.S -LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := optional -LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_SHARED_LIBRARIES := libbase liblog - -# The arm emulator has VFP but not VFPv3-D32. -ifeq ($(ARCH_ARM_HAVE_VFP_D32),true) -LOCAL_ASFLAGS_arm += -DHAS_VFP_D32 -endif - -LOCAL_MODULE := static_crasher -LOCAL_MODULE_STEM_32 := static_crasher -LOCAL_MODULE_STEM_64 := static_crasher64 -LOCAL_MULTILIB := both - -LOCAL_STATIC_LIBRARIES := libdebuggerd_handler libbase liblog - -include $(BUILD_EXECUTABLE) diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp index 288f1165e..64a38dd8c 100644 --- a/debuggerd/crasher/crasher.cpp +++ b/debuggerd/crasher/crasher.cpp @@ -36,6 +36,19 @@ #include "debuggerd/handler.h" #endif +#if defined(__arm__) +// See https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt for details. +#define __kuser_helper_version (*(int32_t*) 0xffff0ffc) +typedef void * (__kuser_get_tls_t)(void); +#define __kuser_get_tls (*(__kuser_get_tls_t*) 0xffff0fe0) +typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr); +#define __kuser_cmpxchg (*(__kuser_cmpxchg_t*) 0xffff0fc0) +typedef void (__kuser_dmb_t)(void); +#define __kuser_dmb (*(__kuser_dmb_t*) 0xffff0fa0) +typedef int (__kuser_cmpxchg64_t)(const int64_t*, const int64_t*, volatile int64_t*); +#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t*) 0xffff0f60) +#endif + #define noinline __attribute__((__noinline__)) // Avoid name mangling so that stacks are more readable. @@ -142,22 +155,36 @@ static int usage() { fprintf(stderr, "where KIND is:\n"); fprintf(stderr, " smash-stack overwrite a -fstack-protector guard\n"); fprintf(stderr, " stack-overflow recurse until the stack overflows\n"); + fprintf(stderr, " nostack crash with a NULL stack pointer\n"); + fprintf(stderr, "\n"); fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n"); fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n"); - fprintf(stderr, " nostack crash with a NULL stack pointer\n"); + fprintf(stderr, "\n"); fprintf(stderr, " abort call abort()\n"); fprintf(stderr, " assert call assert() without a function\n"); fprintf(stderr, " assert2 call assert() with a function\n"); fprintf(stderr, " exit call exit(1)\n"); + fprintf(stderr, "\n"); fprintf(stderr, " fortify fail a _FORTIFY_SOURCE check\n"); + fprintf(stderr, " seccomp fail a seccomp check\n"); +#if defined(__arm__) + fprintf(stderr, " kuser_helper_version call kuser_helper_version\n"); + fprintf(stderr, " kuser_get_tls call kuser_get_tls\n"); + fprintf(stderr, " kuser_cmpxchg call kuser_cmpxchg\n"); + fprintf(stderr, " kuser_memory_barrier call kuser_memory_barrier\n"); + fprintf(stderr, " kuser_cmpxchg64 call kuser_cmpxchg64\n"); +#endif + fprintf(stderr, "\n"); fprintf(stderr, " LOG_ALWAYS_FATAL call liblog LOG_ALWAYS_FATAL\n"); fprintf(stderr, " LOG_ALWAYS_FATAL_IF call liblog LOG_ALWAYS_FATAL_IF\n"); fprintf(stderr, " LOG-FATAL call libbase LOG(FATAL)\n"); + fprintf(stderr, "\n"); fprintf(stderr, " SIGFPE cause a SIGFPE\n"); fprintf(stderr, " SIGSEGV cause a SIGSEGV at address 0x0 (synonym: crash)\n"); fprintf(stderr, " SIGSEGV-non-null cause a SIGSEGV at a non-zero address\n"); fprintf(stderr, " SIGSEGV-unmapped mmap/munmap a region of memory and then attempt to access it\n"); fprintf(stderr, " SIGTRAP cause a SIGTRAP\n"); + fprintf(stderr, "\n"); fprintf(stderr, " fprintf-NULL pass a null pointer to fprintf\n"); fprintf(stderr, " readdir-NULL pass a null pointer to readdir\n"); fprintf(stderr, " strlen-NULL pass a null pointer to strlen\n"); @@ -235,6 +262,20 @@ noinline int do_action(const char* arg) { MAP_SHARED | MAP_ANONYMOUS, -1, 0)); munmap(map, sizeof(int)); map[0] = '8'; + } else if (!strcasecmp(arg, "seccomp")) { + syscall(99999); +#if defined(__arm__) + } else if (!strcasecmp(arg, "kuser_helper_version")) { + return __kuser_helper_version; + } else if (!strcasecmp(arg, "kuser_get_tls")) { + return !__kuser_get_tls(); + } else if (!strcasecmp(arg, "kuser_cmpxchg")) { + return __kuser_cmpxchg(0, 0, 0); + } else if (!strcasecmp(arg, "kuser_memory_barrier")) { + __kuser_dmb(); + } else if (!strcasecmp(arg, "kuser_cmpxchg64")) { + return __kuser_cmpxchg64(0, 0, 0); +#endif } else { return usage(); } diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index 01e9cf69b..ac2c0b6c4 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -49,6 +49,8 @@ #include "open_files_list.h" #include "tombstone.h" +using android::base::StringPrintf; + #define STACK_WORDS 16 #define MAX_TOMBSTONES 10 @@ -74,7 +76,7 @@ static bool signal_has_si_addr(int si_signo, int si_code) { } static const char* get_signame(int sig) { - switch(sig) { + switch (sig) { case SIGABRT: return "SIGABRT"; case SIGBUS: return "SIGBUS"; case SIGFPE: return "SIGFPE"; @@ -195,6 +197,29 @@ static void dump_header_info(log_t* log) { _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING); } +static void dump_probable_cause(log_t* log, const siginfo_t& si) { + std::string cause; + if (si.si_signo == SIGSEGV && si.si_code == SEGV_MAPERR) { + if (si.si_addr < reinterpret_cast(4096)) { + cause = StringPrintf("null pointer dereference"); + } else if (si.si_addr == reinterpret_cast(0xffff0ffc)) { + cause = "call to kuser_helper_version"; + } else if (si.si_addr == reinterpret_cast(0xffff0fe0)) { + cause = "call to kuser_get_tls"; + } else if (si.si_addr == reinterpret_cast(0xffff0fc0)) { + cause = "call to kuser_cmpxchg"; + } else if (si.si_addr == reinterpret_cast(0xffff0fa0)) { + cause = "call to kuser_memory_barrier"; + } else if (si.si_addr == reinterpret_cast(0xffff0f60)) { + cause = "call to kuser_cmpxchg64"; + } + } else if (si.si_signo == SIGSYS && si.si_code == SYS_SECCOMP) { + cause = StringPrintf("seccomp prevented call to disallowed system call %d", si.si_syscall); + } + + if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str()); +} + static void dump_signal_info(log_t* log, pid_t tid) { siginfo_t si; memset(&si, 0, sizeof(si)); @@ -212,6 +237,8 @@ static void dump_signal_info(log_t* log, pid_t tid) { _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si.si_signo, get_signame(si.si_signo), si.si_code, get_sigcode(si.si_signo, si.si_code), addr_desc); + + dump_probable_cause(log, si); } static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) { @@ -262,11 +289,11 @@ static void dump_stack_segment( line = " "; if (i == 0 && label >= 0) { // Print the label once. - line += android::base::StringPrintf("#%02d ", label); + line += StringPrintf("#%02d ", label); } else { line += " "; } - line += android::base::StringPrintf("%" PRIPTR " %" PRIPTR, *sp, stack_data[i]); + line += StringPrintf("%" PRIPTR " %" PRIPTR, *sp, stack_data[i]); backtrace_map_t map; backtrace->FillInMap(stack_data[i], &map); @@ -277,7 +304,7 @@ static void dump_stack_segment( if (!func_name.empty()) { line += " (" + func_name; if (offset) { - line += android::base::StringPrintf("+%" PRIuPTR, offset); + line += StringPrintf("+%" PRIuPTR, offset); } line += ')'; } @@ -336,11 +363,11 @@ static void dump_stack(Backtrace* backtrace, log_t* log) { static std::string get_addr_string(uintptr_t addr) { std::string addr_str; #if defined(__LP64__) - addr_str = android::base::StringPrintf("%08x'%08x", - static_cast(addr >> 32), - static_cast(addr & 0xffffffff)); + addr_str = StringPrintf("%08x'%08x", + static_cast(addr >> 32), + static_cast(addr & 0xffffffff)); #else - addr_str = android::base::StringPrintf("%08x", addr); + addr_str = StringPrintf("%08x", addr); #endif return addr_str; } @@ -426,8 +453,7 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p } else { line += '-'; } - line += android::base::StringPrintf(" %8" PRIxPTR " %8" PRIxPTR, - it->offset, it->end - it->start); + line += StringPrintf(" %8" PRIxPTR " %8" PRIxPTR, it->offset, it->end - it->start); bool space_needed = true; if (it->name.length() > 0) { space_needed = false; @@ -441,7 +467,7 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p if (space_needed) { line += ' '; } - line += android::base::StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base); + line += StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base); } _LOG(log, logtype::MAPS, "%s\n", line.c_str()); }