Line data Source code
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 : : guard_size_(sysconf(_SC_PAGE_SIZE)), 55 : altstack_size_( 56 : std::max(guard_size_ * 4, (static_cast<size_t>(MINSIGSTKSZ) + guard_size_ - 1) / 57 0 : guard_size_ * guard_size_)) { 58 0 : mapAndProtectStackMemory(); 59 0 : installSigHandlers(); 60 0 : } 61 0 : ~SignalAction() { 62 0 : removeSigHandlers(); 63 0 : unmapStackMemory(); 64 0 : } 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 0 : 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