1
#pragma once
2

            
3
#include <unistd.h>
4

            
5
#include <algorithm>
6
#include <csignal>
7
#include <list>
8

            
9
#include "source/common/common/non_copyable.h"
10
#include "source/common/signal/fatal_error_handler.h"
11
#include "source/server/backtrace.h"
12

            
13
namespace Envoy {
14

            
15
/**
16
 * This class installs signal handlers for fatal signal types.
17
 *
18
 * These signals are handled:
19
 *   SIGABRT
20
 *   SIGBUS
21
 *   SIGFPE
22
 *   SIGILL
23
 *   SIGSEGV
24
 *
25
 * Upon intercepting the signal the following actions are taken:
26
 *
27
 *   A Backtrace is printed from the address the signal was encountered at, if
28
 *   it is possible to retrieve.
29
 *
30
 *   The signal handler is reset to the default handler (which is expected to
31
 *   terminate the process).
32
 *
33
 *   The signal is raised again (which ultimately kills the process)
34
 *
35
 * The signal handler must run on an alternative stack so that we can do the
36
 * stack unwind on the original stack. Memory is allocated for this purpose when
37
 * this object is constructed. When this object goes out of scope the memory
38
 * used for the alternate signal stack is destroyed and the previous signal handler
39
 * and alt stack if previously used are restored.
40
 *
41
 * Note that we do NOT restore the previously saved sigaction and alt stack in
42
 * the signal handler itself. This is fraught with complexity and has little
43
 * benefit. The inner most scope SignalAction will terminate the process by
44
 * re-raising the fatal signal with default handler.
45
 *
46
 * It is recommended that this object be instantiated at the highest possible
47
 * scope, e.g., in main(). This enables fatal signal handling for almost all code
48
 * executed. Because of the save-and-restore behavior it is possible for
49
 * SignalAction to be used at both wider and tighter scopes without issue.
50
 */
51
class SignalAction : NonCopyable {
52
public:
53
  SignalAction()
54
1727
      : guard_size_(sysconf(_SC_PAGE_SIZE)),
55
        altstack_size_(
56
1727
            std::max(guard_size_ * 4, (static_cast<size_t>(MINSIGSTKSZ) + guard_size_ - 1) /
57
1727
                                          guard_size_ * guard_size_)) {
58
1727
    mapAndProtectStackMemory();
59
1727
    installSigHandlers();
60
1727
  }
61
1727
  ~SignalAction() {
62
1727
    removeSigHandlers();
63
1727
    unmapStackMemory();
64
1727
  }
65
  /**
66
   * Helpers for testing guarded stack memory
67
   */
68
  void doGoodAccessForTest();
69
  void tryEvilAccessForTest(bool end);
70
  /**
71
   * The actual signal handler function with prototype matching signal.h
72
   *
73
   * Public so that we can exercise it directly from a test.
74
   */
75
  static void sigHandler(int sig, siginfo_t* info, void* context);
76

            
77
private:
78
  /**
79
   * Allocate this many bytes on each side of the area used for alt stack.
80
   *
81
   * Set to system page size.
82
   *
83
   * The memory will be protected from read and write.
84
   */
85
  const size_t guard_size_;
86
  /**
87
   * Use this many bytes for the alternate signal handling stack.
88
   *
89
   * Initialized as a multiple of page size (although signalstack will
90
   * do alignment as needed).
91
   *
92
   * Additionally, two guard pages will be allocated to bookend the usable area.
93
   */
94
  const size_t altstack_size_;
95
  /**
96
   * This constant array defines the signals we will insert handlers for.
97
   *
98
   * Essentially this is the list of signals that would cause a core dump.
99
   * The object will contain an array of struct sigactions with the same number
100
   * of elements that are in this array.
101
   */
102
  static constexpr int FATAL_SIGS[] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV};
103
  /**
104
   * Return the memory size we actually map including two guard pages.
105
   */
106
3454
  size_t mapSizeWithGuards() const { return altstack_size_ + guard_size_ * 2; }
107
  /**
108
   * Install all signal handlers and setup signal handling stack.
109
   */
110
  void installSigHandlers();
111
  /**
112
   * Remove all signal handlers.
113
   *
114
   * Must be executed before the alt stack memory goes away.
115
   *
116
   * Signal handlers will be reset to the default, NOT back to any signal
117
   * handler existing before InstallSigHandlers().
118
   */
119
  void removeSigHandlers();
120
  /**
121
   * Use mmap to map anonymous memory for the alternative stack.
122
   *
123
   * GUARD_SIZE on either end of the memory will be marked PROT_NONE, protected
124
   * from all access.
125
   */
126
  void mapAndProtectStackMemory();
127
  /**
128
   * Unmap alternative stack memory.
129
   */
130
  void unmapStackMemory();
131
  char* altstack_{};
132
  std::array<struct sigaction, sizeof(FATAL_SIGS) / sizeof(int)> previous_handlers_;
133
// sigaltstack and backtrace() are incompatible on Apple platforms
134
// https://reviews.llvm.org/D28265
135
#if !defined(__APPLE__)
136
  stack_t previous_altstack_;
137
#endif
138
};
139

            
140
} // namespace Envoy