forked from envoyproxy/envoy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signal_action.h
132 lines (126 loc) · 4.15 KB
/
signal_action.h
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
#pragma once
#include <signal.h>
#include <unistd.h>
#include <algorithm>
#include "common/common/non_copyable.h"
#include "server/backtrace.h"
namespace Envoy {
/**
* This class installs signal handlers for fatal signal types.
*
* These signals are handled:
* SIGABRT
* SIGBUS
* SIGFPE
* SIGILL
* SIGSEGV
*
* Upon intercepting the signal the following actions are taken:
*
* A Backtrace is printed from the address the signal was encountered at, if
* it is possible to retrieve.
*
* The signal handler is reset to the default handler (which is expected to
* terminate the process).
*
* The signal is raised again (which ultimately kills the process)
*
* The signal handler must run on an alternative stack so that we can do the
* stack unwind on the original stack. Memory is allocated for this purpose when
* this object is constructed. When this object goes out of scope the memory
* used for the alternate signal stack is destroyed and the previous signal handler
* and alt stack if previously used are restored.
*
* Note that we do NOT restore the previously saved sigaction and alt stack in
* the signal handler itself. This is fraught with complexity and has little
* benefit. The inner most scope SignalAction will terminate the process by
* re-raising the fatal signal with default handler.
*
* It is recommended that this object be instantiated at the highest possible
* scope, eg, in main(). This enables fatal signal handling for almost all code
* executed. Because of the save-and-restore behavior it is possible for
* SignalAction to be used at both wider and tighter scopes without issue.
*/
class SignalAction : NonCopyable {
public:
SignalAction()
: guard_size_(sysconf(_SC_PAGE_SIZE)),
altstack_size_(std::max(guard_size_ * 4, static_cast<size_t>(MINSIGSTKSZ))),
altstack_(nullptr) {
mapAndProtectStackMemory();
installSigHandlers();
}
~SignalAction() {
removeSigHandlers();
unmapStackMemory();
}
/**
* Helpers for testing guarded stack memory
*/
void doGoodAccessForTest();
void tryEvilAccessForTest(bool end);
/**
* The actual signal handler function with prototype matching signal.h
*
* Public so that we can exercise it directly from a test.
*/
static void sigHandler(int sig, siginfo_t* info, void* context);
private:
/**
* Allocate this many bytes on each side of the area used for alt stack.
*
* Set to system page size.
*
* The memory will be protected from read and write.
*/
const size_t guard_size_;
/**
* Use this many bytes for the alternate signal handling stack.
*
* Initialized as a multiple of page size (although sigaltstack will
* do alignment as needed).
*
* Additionally, two guard pages will be allocated to bookend the usable area.
*/
const size_t altstack_size_;
/**
* This constant array defines the signals we will insert handlers for.
*
* Essentially this is the list of signals that would cause a core dump.
* The object will contain an array of struct sigactions with the same number
* of elements that are in this array.
*/
static constexpr int FATAL_SIGS[] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV};
/**
* Return the memory size we actually map including two guard pages.
*/
size_t mapSizeWithGuards() const { return altstack_size_ + guard_size_ * 2; }
/**
* Install all signal handlers and setup signal handling stack.
*/
void installSigHandlers();
/**
* Remove all signal handlers.
*
* Must be executed before the alt stack memory goes away.
*
* Signal handlers will be reset to the default, NOT back to any signal
* handler existing before InstallSigHandlers().
*/
void removeSigHandlers();
/**
* Use mmap to map anonymous memory for the alternative stack.
*
* GUARD_SIZE on either end of the memory will be marked PROT_NONE, protected
* from all access.
*/
void mapAndProtectStackMemory();
/**
* Unmap alternative stack memory.
*/
void unmapStackMemory();
char* altstack_;
std::array<struct sigaction, sizeof(FATAL_SIGS) / sizeof(int)> previous_handlers_;
stack_t previous_altstack_;
};
} // namespace Envoy