forked from envoyproxy/envoy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsignal_action.cc
134 lines (113 loc) · 4.21 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
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "common/signal/signal_action.h"
#include <sys/mman.h>
#include <csignal>
#include "common/common/assert.h"
#include "common/signal/fatal_action.h"
#include "common/version/version.h"
namespace Envoy {
constexpr int SignalAction::FATAL_SIGS[];
void SignalAction::sigHandler(int sig, siginfo_t* info, void* context) {
BackwardsTrace tracer;
tracer.logFault(strsignal(sig), info->si_addr);
if (context != nullptr) {
tracer.captureFrom(context);
} else {
tracer.capture();
}
tracer.logTrace();
// Finally after logging the stack trace, call the crash handlers
// in order from safe to unsafe.
auto status = FatalErrorHandler::runSafeActions();
switch (status) {
case FatalAction::Status::Success:
FatalErrorHandler::callFatalErrorHandlers(std::cerr);
FatalErrorHandler::runUnsafeActions();
break;
case FatalAction::Status::ActionManagerUnset:
FatalErrorHandler::callFatalErrorHandlers(std::cerr);
break;
case FatalAction::Status::RunningOnAnotherThread: {
// We should wait for some duration for the other thread to finish
// running. We should add support for this scenario, even though the
// probability of it occurring is low.
// TODO(kbaichoo): Implement a configurable call to sleep
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
break;
}
case FatalAction::Status::AlreadyRanOnThisThread:
// We caused another fatal signal to be raised.
std::cerr << "Our FatalActions triggered a fatal signal.\n";
break;
}
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, "");
// Make sure VersionInfo::version() is initialized so we don't allocate std::string in signal
// handlers.
RELEASE_ASSERT(!VersionInfo::version().empty(), "");
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