LCOV - code coverage report
Current view: top level - source/common/signal - signal_action.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 9 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 3 0.0 %

          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

Generated by: LCOV version 1.15