Bug 1036286 - Ensure faulty.lib diverts libc's sigaction instead of a LD_PRELOADed one. r=nfroyd, a=sledru
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 07 Aug 2014 02:51:20 +0900
changeset 208272 1f96d584763a
parent 208271 ec230387fad2
child 208273 6037db66624b
push id3796
push userryanvm@gmail.com
push date2014-08-08 18:52 +0000
treeherdermozilla-beta@1cf7b5810eb5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd, sledru
bugs1036286
milestone32.0
Bug 1036286 - Ensure faulty.lib diverts libc's sigaction instead of a LD_PRELOADed one. r=nfroyd, a=sledru and force-send calls to sigaction from faulty.lib-loaded libraries to the libc.
mozglue/linker/CustomElf.cpp
mozglue/linker/ElfLoader.cpp
--- a/mozglue/linker/CustomElf.cpp
+++ b/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 <cstring>
 #include <sys/mman.h>
 #include <vector>
 #include <dlfcn.h>
+#include <signal.h>
 #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<CustomElf *>(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
+++ b/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<sigaction_func>(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) {