--- a/mozglue/linker/CustomElf.cpp +++ a/mozglue/linker/CustomElf.cpp @@ -1,16 +1,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include +#include #include "CustomElf.h" #include "Mappable.h" #include "Logging.h" using namespace Elf; using namespace mozilla; /* TODO: Fill ElfLoader::Singleton.lastError on errors. */ @@ -348,16 +349,21 @@ CustomElf::GetSymbolPtrInDeps(const char if (strcmp(symbol + 2, "dso_handle") == 0) return const_cast(this); if (strcmp(symbol + 2, "moz_linker_stats") == 0) return FunctionPtr(&ElfLoader::stats); #ifdef __ARM_EABI__ if (strcmp(symbol + 2, "gnu_Unwind_Find_exidx") == 0) return FunctionPtr(__wrap___gnu_Unwind_Find_exidx); #endif + } else if (symbol[0] == 's' && symbol[1] == 'i') { + if (strcmp(symbol + 2, "gnal") == 0) + return FunctionPtr(signal); + if (strcmp(symbol + 2, "gaction") == 0) + return FunctionPtr(sigaction); } #define MISSING_FLASH_SYMNAME_START "_ZN7android10VectorImpl19reservedVectorImpl" // Android changed some symbols that Flash depended on in 4.4, // so stub those out here if (strncmp(symbol, MISSING_FLASH_SYMNAME_START, --- a/mozglue/linker/ElfLoader.cpp +++ a/mozglue/linker/ElfLoader.cpp @@ -1014,17 +1014,59 @@ SEGVHandler::FinishInitialization() { /* Ideally, we'd need some locking here, but in practice, we're not * going to race with another thread. */ initialized = true; if (signalHandlingBroken || signalHandlingSlow) return; - if (!Divert(sigaction, __wrap_sigaction)) + typedef int (*sigaction_func)(int, const struct sigaction *, + struct sigaction *); + + sigaction_func libc_sigaction; + +#if defined(ANDROID) + /* Android > 4.4 comes with a sigaction wrapper in a LD_PRELOADed library + * (libsigchain) for ART. That wrapper kind of does the same trick as we + * do, so we need extra care in handling it. + * - Divert the libc's sigaction, assuming the LD_PRELOADed library uses + * it under the hood (which is more or less true according to the source + * of that library, since it's doing a lookup in RTLD_NEXT) + * - With the LD_PRELOADed library in place, all calls to sigaction from + * from system libraries will go to the LD_PRELOADed library. + * - The LD_PRELOADed library calls to sigaction go to our __wrap_sigaction. + * - The calls to sigaction from libraries faulty.lib loads are sent to + * the LD_PRELOADed library. + * In practice, for signal handling, this means: + * - The signal handler registered to the kernel is ours. + * - Our handler redispatches to the LD_PRELOADed library's if there's a + * segfault we don't handle. + * - The LD_PRELOADed library redispatches according to whatever system + * library or faulty.lib-loaded library set with sigaction. + * + * When there is no sigaction wrapper in place: + * - Divert the libc's sigaction. + * - Calls to sigaction from system library and faulty.lib-loaded libraries + * all go to the libc's sigaction, which end up in our __wrap_sigaction. + * - The signal handler registered to the kernel is ours. + * - Our handler redispatches according to whatever system library or + * faulty.lib-loaded library set with sigaction. + */ + void *libc = dlopen("libc.so", RTLD_GLOBAL | RTLD_LAZY); + if (libc) { + libc_sigaction = + reinterpret_cast(dlsym(libc, "sigaction")); + } else +#endif + { + libc_sigaction = sigaction; + } + + if (!Divert(libc_sigaction, __wrap_sigaction)) return; /* Setup an alternative stack if the already existing one is not big * enough, or if there is none. */ if (sigaltstack(nullptr, &oldStack) == 0) { if (oldStack.ss_flags == SS_ONSTACK) oldStack.ss_flags = 0; if (!oldStack.ss_sp || oldStack.ss_size < stackSize) {