1
#include "source/common/signal/signal_action.h"
2

            
3
#include <sys/mman.h>
4

            
5
#include <csignal>
6

            
7
#include "source/common/common/assert.h"
8
#include "source/common/signal/fatal_action.h"
9
#include "source/common/version/version.h"
10

            
11
namespace Envoy {
12

            
13
constexpr int SignalAction::FATAL_SIGS[];
14

            
15
1
void SignalAction::sigHandler(int sig, siginfo_t* info, void* context) {
16
1
  BackwardsTrace tracer;
17

            
18
1
  tracer.logFault(strsignal(sig), info->si_addr);
19
1
  if (context != nullptr) {
20
    tracer.captureFrom(context);
21
1
  } else {
22
1
    tracer.capture();
23
1
  }
24
1
  tracer.logTrace();
25

            
26
  // Finally after logging the stack trace, call the crash handlers
27
  // in order from safe to unsafe.
28
1
  auto status = FatalErrorHandler::runSafeActions();
29

            
30
1
  switch (status) {
31
  case FatalAction::Status::Success:
32
    FatalErrorHandler::callFatalErrorHandlers(std::cerr);
33
    FatalErrorHandler::runUnsafeActions();
34
    break;
35
1
  case FatalAction::Status::ActionManagerUnset:
36
1
    FatalErrorHandler::callFatalErrorHandlers(std::cerr);
37
1
    break;
38
  case FatalAction::Status::RunningOnAnotherThread: {
39
    // We should wait for some duration for the other thread to finish
40
    // running. We should add support for this scenario, even though the
41
    // probability of it occurring is low.
42
    // TODO(kbaichoo): Implement a configurable call to sleep
43
    PANIC("not implemented");
44
    break;
45
  }
46
  case FatalAction::Status::AlreadyRanOnThisThread:
47
    // We caused another fatal signal to be raised.
48
    std::cerr << "Our FatalActions triggered a fatal signal.\n";
49
    break;
50
1
  }
51

            
52
1
  signal(sig, SIG_DFL);
53
1
  raise(sig);
54
1
}
55

            
56
1721
void SignalAction::installSigHandlers() {
57
  // sigaltstack and backtrace() are incompatible on Apple platforms
58
  // https://reviews.llvm.org/D28265
59
1721
#if !defined(__APPLE__)
60
1721
  stack_t stack;
61
1721
  stack.ss_sp = altstack_ + guard_size_; // Guard page at one end ...
62
1721
  stack.ss_size = altstack_size_;        // ... guard page at the other
63
1721
  stack.ss_flags = 0;
64

            
65
1721
  RELEASE_ASSERT(sigaltstack(&stack, &previous_altstack_) == 0, "");
66
1721
#endif
67

            
68
  // Make sure VersionInfo::version() is initialized so we don't allocate std::string in signal
69
  // handlers.
70
1721
  RELEASE_ASSERT(!VersionInfo::version().empty(), "");
71

            
72
1721
  int hidx = 0;
73
8605
  for (const auto& sig : FATAL_SIGS) {
74
8605
    struct sigaction saction;
75
8605
    std::memset(&saction, 0, sizeof(saction));
76
8605
    sigemptyset(&saction.sa_mask);
77
8605
    saction.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_RESETHAND | SA_NODEFER);
78
8605
    saction.sa_sigaction = sigHandler;
79
8605
    auto* handler = &previous_handlers_[hidx++];
80
8605
    RELEASE_ASSERT(sigaction(sig, &saction, handler) == 0, "");
81
8605
  }
82
1721
}
83

            
84
1721
void SignalAction::removeSigHandlers() {
85
// sigaltstack and backtrace() are incompatible on Apple platforms
86
// https://reviews.llvm.org/D28265
87
1721
#if !defined(__APPLE__)
88
1721
  RELEASE_ASSERT(sigaltstack(&previous_altstack_, nullptr) == 0, "");
89
1721
#endif
90

            
91
1721
  int hidx = 0;
92
8605
  for (const auto& sig : FATAL_SIGS) {
93
8605
    auto* handler = &previous_handlers_[hidx++];
94
8605
    RELEASE_ASSERT(sigaction(sig, handler, nullptr) == 0, "");
95
8605
  }
96
1721
}
97

            
98
#if defined(__APPLE__) && !defined(MAP_STACK)
99
#define MAP_STACK (0)
100
#endif
101

            
102
1721
void SignalAction::mapAndProtectStackMemory() {
103
  // Per docs MAP_STACK doesn't actually do anything today but provides a
104
  // library hint that might be used in the future.
105
1721
  altstack_ = static_cast<char*>(mmap(nullptr, mapSizeWithGuards(), PROT_READ | PROT_WRITE,
106
1721
                                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0));
107
1721
  RELEASE_ASSERT(altstack_, "");
108
1721
  RELEASE_ASSERT(mprotect(altstack_, guard_size_, PROT_NONE) == 0, "");
109
1721
  RELEASE_ASSERT(mprotect(altstack_ + guard_size_ + altstack_size_, guard_size_, PROT_NONE) == 0,
110
1721
                 "");
111
1721
}
112

            
113
1721
void SignalAction::unmapStackMemory() { munmap(altstack_, mapSizeWithGuards()); }
114

            
115
1
void SignalAction::doGoodAccessForTest() {
116
1
  volatile char* altaltstack = altstack_;
117
16385
  for (size_t i = 0; i < altstack_size_; ++i) {
118
16384
    *(altaltstack + guard_size_ + i) = 42;
119
16384
  }
120
16385
  for (size_t i = 0; i < altstack_size_; ++i) {
121
16384
    ASSERT(*(altaltstack + guard_size_ + i) == 42);
122
16384
  }
123
1
}
124

            
125
void SignalAction::tryEvilAccessForTest(bool end) {
126
  volatile char* altaltstack = altstack_;
127
  if (end) {
128
    // One byte past the valid region
129
    // http://oeis.org/A001969
130
    *(altaltstack + guard_size_ + altstack_size_) = 43;
131
  } else {
132
    // One byte before the valid region
133
    *(altaltstack + guard_size_ - 1) = 43;
134
  }
135
}
136
} // namespace Envoy