1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
--- 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 <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
+++ 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<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) {
|