forked from envoyproxy/envoy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsignal_action.cc
121 lines (104 loc) · 3.86 KB
/
signal_action.cc
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "exe/signal_action.h"
#include <signal.h>
#include <sys/mman.h>
#include "common/common/assert.h"
namespace Envoy {
constexpr int SignalAction::FATAL_SIGS[];
void SignalAction::sigHandler(int sig, siginfo_t* info, void* context) {
void* error_pc = 0;
const ucontext_t* ucontext = reinterpret_cast<const ucontext_t*>(context);
if (ucontext != nullptr) {
#ifdef REG_RIP
// x86_64
error_pc = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[REG_RIP]);
#elif defined(__APPLE__) && defined(__x86_64__)
error_pc = reinterpret_cast<void*>(ucontext->uc_mcontext->__ss.__rip);
#elif defined(__powerpc__)
error_pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip);
#elif defined(__aarch64__)
error_pc = reinterpret_cast<void*>(ucontext->uc_mcontext.pc);
#elif defined(__arm__)
error_pc = reinterpret_cast<void*>(ucontext->uc_mcontext.arm_pc);
#else
#warning "Please enable and test PC retrieval code for your arch in signal_action.cc"
// x86 Classic: reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[REG_EIP]);
// ARM: reinterpret_cast<void*>(ucontext->uc_mcontext.arm_pc);
#endif
}
BackwardsTrace tracer;
tracer.logFault(strsignal(sig), info->si_addr);
if (error_pc != 0) {
tracer.captureFrom(error_pc);
} else {
tracer.capture();
}
tracer.logTrace();
signal(sig, SIG_DFL);
raise(sig);
}
void SignalAction::installSigHandlers() {
stack_t stack;
stack.ss_sp = altstack_ + guard_size_; // Guard page at one end ...
stack.ss_size = altstack_size_; // ... guard page at the other
stack.ss_flags = 0;
RELEASE_ASSERT(sigaltstack(&stack, &previous_altstack_) == 0, "");
int hidx = 0;
for (const auto& sig : FATAL_SIGS) {
struct sigaction saction;
std::memset(&saction, 0, sizeof(saction));
sigemptyset(&saction.sa_mask);
saction.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_RESETHAND | SA_NODEFER);
saction.sa_sigaction = sigHandler;
auto* handler = &previous_handlers_[hidx++];
RELEASE_ASSERT(sigaction(sig, &saction, handler) == 0, "");
}
}
void SignalAction::removeSigHandlers() {
#if defined(__APPLE__)
// ss_flags contains SS_DISABLE, but Darwin still checks the size, contrary to the man page
if (previous_altstack_.ss_size < MINSIGSTKSZ) {
previous_altstack_.ss_size = MINSIGSTKSZ;
}
#endif
RELEASE_ASSERT(sigaltstack(&previous_altstack_, nullptr) == 0, "");
int hidx = 0;
for (const auto& sig : FATAL_SIGS) {
auto* handler = &previous_handlers_[hidx++];
RELEASE_ASSERT(sigaction(sig, handler, nullptr) == 0, "");
}
}
#if defined(__APPLE__) && !defined(MAP_STACK)
#define MAP_STACK (0)
#endif
void SignalAction::mapAndProtectStackMemory() {
// Per docs MAP_STACK doesn't actually do anything today but provides a
// library hint that might be used in the future.
altstack_ = static_cast<char*>(mmap(nullptr, mapSizeWithGuards(), PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0));
RELEASE_ASSERT(altstack_, "");
RELEASE_ASSERT(mprotect(altstack_, guard_size_, PROT_NONE) == 0, "");
RELEASE_ASSERT(mprotect(altstack_ + guard_size_ + altstack_size_, guard_size_, PROT_NONE) == 0,
"");
}
void SignalAction::unmapStackMemory() { munmap(altstack_, mapSizeWithGuards()); }
void SignalAction::doGoodAccessForTest() {
volatile char* altaltstack = altstack_;
for (size_t i = 0; i < altstack_size_; ++i) {
*(altaltstack + guard_size_ + i) = 42;
}
for (size_t i = 0; i < altstack_size_; ++i) {
ASSERT(*(altaltstack + guard_size_ + i) == 42);
}
}
void SignalAction::tryEvilAccessForTest(bool end) {
volatile char* altaltstack = altstack_;
if (end) {
// One byte past the valid region
// http://oeis.org/A001969
*(altaltstack + guard_size_ + altstack_size_) = 43;
} else {
// One byte before the valid region
*(altaltstack + guard_size_ - 1) = 43;
}
}
} // namespace Envoy