Line data Source code
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 0 : void SignalAction::sigHandler(int sig, siginfo_t* info, void* context) { 16 0 : BackwardsTrace tracer; 17 : 18 0 : tracer.logFault(strsignal(sig), info->si_addr); 19 0 : if (context != nullptr) { 20 0 : tracer.captureFrom(context); 21 0 : } else { 22 0 : tracer.capture(); 23 0 : } 24 0 : tracer.logTrace(); 25 : 26 : // Finally after logging the stack trace, call the crash handlers 27 : // in order from safe to unsafe. 28 0 : auto status = FatalErrorHandler::runSafeActions(); 29 : 30 0 : switch (status) { 31 0 : case FatalAction::Status::Success: 32 0 : FatalErrorHandler::callFatalErrorHandlers(std::cerr); 33 0 : FatalErrorHandler::runUnsafeActions(); 34 0 : break; 35 0 : case FatalAction::Status::ActionManagerUnset: 36 0 : FatalErrorHandler::callFatalErrorHandlers(std::cerr); 37 0 : break; 38 0 : 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 0 : PANIC("not implemented"); 44 0 : break; 45 0 : } 46 0 : case FatalAction::Status::AlreadyRanOnThisThread: 47 : // We caused another fatal signal to be raised. 48 0 : std::cerr << "Our FatalActions triggered a fatal signal.\n"; 49 0 : break; 50 0 : } 51 : 52 0 : signal(sig, SIG_DFL); 53 0 : raise(sig); 54 0 : } 55 : 56 0 : void SignalAction::installSigHandlers() { 57 : // sigaltstack and backtrace() are incompatible on Apple platforms 58 : // https://reviews.llvm.org/D28265 59 0 : #if !defined(__APPLE__) 60 0 : stack_t stack; 61 0 : stack.ss_sp = altstack_ + guard_size_; // Guard page at one end ... 62 0 : stack.ss_size = altstack_size_; // ... guard page at the other 63 0 : stack.ss_flags = 0; 64 : 65 0 : RELEASE_ASSERT(sigaltstack(&stack, &previous_altstack_) == 0, ""); 66 0 : #endif 67 : 68 : // Make sure VersionInfo::version() is initialized so we don't allocate std::string in signal 69 : // handlers. 70 0 : RELEASE_ASSERT(!VersionInfo::version().empty(), ""); 71 : 72 0 : int hidx = 0; 73 0 : for (const auto& sig : FATAL_SIGS) { 74 0 : struct sigaction saction; 75 0 : std::memset(&saction, 0, sizeof(saction)); 76 0 : sigemptyset(&saction.sa_mask); 77 0 : saction.sa_flags = (SA_SIGINFO | SA_ONSTACK | SA_RESETHAND | SA_NODEFER); 78 0 : saction.sa_sigaction = sigHandler; 79 0 : auto* handler = &previous_handlers_[hidx++]; 80 0 : RELEASE_ASSERT(sigaction(sig, &saction, handler) == 0, ""); 81 0 : } 82 0 : } 83 : 84 0 : void SignalAction::removeSigHandlers() { 85 : // sigaltstack and backtrace() are incompatible on Apple platforms 86 : // https://reviews.llvm.org/D28265 87 0 : #if !defined(__APPLE__) 88 0 : RELEASE_ASSERT(sigaltstack(&previous_altstack_, nullptr) == 0, ""); 89 0 : #endif 90 : 91 0 : int hidx = 0; 92 0 : for (const auto& sig : FATAL_SIGS) { 93 0 : auto* handler = &previous_handlers_[hidx++]; 94 0 : RELEASE_ASSERT(sigaction(sig, handler, nullptr) == 0, ""); 95 0 : } 96 0 : } 97 : 98 : #if defined(__APPLE__) && !defined(MAP_STACK) 99 : #define MAP_STACK (0) 100 : #endif 101 : 102 0 : 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 0 : altstack_ = static_cast<char*>(mmap(nullptr, mapSizeWithGuards(), PROT_READ | PROT_WRITE, 106 0 : MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0)); 107 0 : RELEASE_ASSERT(altstack_, ""); 108 0 : RELEASE_ASSERT(mprotect(altstack_, guard_size_, PROT_NONE) == 0, ""); 109 0 : RELEASE_ASSERT(mprotect(altstack_ + guard_size_ + altstack_size_, guard_size_, PROT_NONE) == 0, 110 0 : ""); 111 0 : } 112 : 113 0 : void SignalAction::unmapStackMemory() { munmap(altstack_, mapSizeWithGuards()); } 114 : 115 0 : void SignalAction::doGoodAccessForTest() { 116 0 : volatile char* altaltstack = altstack_; 117 0 : for (size_t i = 0; i < altstack_size_; ++i) { 118 0 : *(altaltstack + guard_size_ + i) = 42; 119 0 : } 120 0 : for (size_t i = 0; i < altstack_size_; ++i) { 121 0 : ASSERT(*(altaltstack + guard_size_ + i) == 42); 122 0 : } 123 0 : } 124 : 125 0 : void SignalAction::tryEvilAccessForTest(bool end) { 126 0 : volatile char* altaltstack = altstack_; 127 0 : if (end) { 128 : // One byte past the valid region 129 : // http://oeis.org/A001969 130 0 : *(altaltstack + guard_size_ + altstack_size_) = 43; 131 0 : } else { 132 : // One byte before the valid region 133 0 : *(altaltstack + guard_size_ - 1) = 43; 134 0 : } 135 0 : } 136 : } // namespace Envoy